From 28ef06b2c6e574b320a05fc6ce776740637987e7 Mon Sep 17 00:00:00 2001 From: Seth Juarez Date: Tue, 9 Jun 2026 22:32:49 -0700 Subject: [PATCH 01/22] Add turn harness contract and runtime events Expand the generated turn harness schema, align runtime event emission across supported runtimes, and add generated model coverage for the new event payloads. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../AgentExtensionsTests.cs | 8 +- .../conversation/ToolResultConversionTests.cs | 36 +- ...ompactionCompletePayloadConversionTests.cs | 16 +- .../CompactionStartPayloadConversionTests.cs | 112 ++++ .../events/DoneEventPayloadConversionTests.cs | 102 ---- .../ErrorEventPayloadConversionTests.cs | 26 +- .../LlmCompletePayloadConversionTests.cs | 132 +++++ .../events/LlmStartPayloadConversionTests.cs | 142 +++++ .../MessagesUpdatedPayloadConversionTests.cs | 112 ++++ ...rmissionCompletedPayloadConversionTests.cs | 132 +++++ ...rmissionRequestedPayloadConversionTests.cs | 122 +++++ .../events/RetryPayloadConversionTests.cs | 152 ++++++ .../ToolCallCompletePayloadConversionTests.cs | 152 ++++++ .../ToolCallStartPayloadConversionTests.cs | 10 + .../events/TurnEndPayloadConversionTests.cs | 122 +++++ .../Model/events/TurnEventConversionTests.cs | 162 ++++++ .../events/TurnStartPayloadConversionTests.cs | 122 +++++ .../events/TurnSummaryConversionTests.cs | 172 ++++++ .../Model/events/TurnTraceConversionTests.cs | 132 +++++ runtime/csharp/Prompty.Core/AgentEvents.cs | 40 +- .../Model/agent/GuardrailResult.cs | 4 +- .../Prompty.Core/Model/agent/Prompty.cs | 18 +- .../Model/connection/Connection.cs | 6 +- .../Model/connection/FoundryConnection.cs | 4 +- .../Model/connection/OAuthConnection.cs | 4 +- .../Model/conversation/ContentPart.cs | 2 +- .../Model/conversation/Message.cs | 2 +- .../Model/conversation/ThreadMarker.cs | 6 +- .../Model/conversation/ToolCall.cs | 2 +- .../Model/conversation/ToolResult.cs | 70 ++- .../Model/conversation/ToolResultStatus.cs | 23 + .../Prompty.Core/Model/core/ArrayProperty.cs | 2 +- .../Model/core/FileNotFoundError.cs | 2 +- .../Prompty.Core/Model/core/InvokerError.cs | 4 +- .../Prompty.Core/Model/core/ObjectProperty.cs | 2 +- .../Prompty.Core/Model/core/Property.cs | 8 +- .../Model/core/ValidationError.cs | 2 +- .../Model/core/ValidationResult.cs | 4 +- .../Model/events/CompactionCompletePayload.cs | 16 + .../Model/events/CompactionStartPayload.cs | 155 ++++++ .../Model/events/DoneEventPayload.cs | 6 +- .../Model/events/ErrorEventPayload.cs | 32 ++ .../Model/events/LlmCompletePayload.cs | 206 +++++++ .../Model/events/LlmStartPayload.cs | 206 +++++++ .../Model/events/MessagesUpdatedPayload.cs | 122 ++++- .../events/PermissionCompletedPayload.cs | 184 +++++++ .../events/PermissionRequestedPayload.cs | 187 +++++++ .../Prompty.Core/Model/events/RetryPayload.cs | 216 ++++++++ .../Prompty.Core/Model/events/StreamChunk.cs | 2 +- .../Model/events/ToolCallCompletePayload.cs | 232 ++++++++ .../Model/events/ToolCallStartPayload.cs | 16 + .../Model/events/TurnEndPayload.cs | 206 +++++++ .../Prompty.Core/Model/events/TurnEvent.cs | 262 +++++++++ .../Model/events/TurnEventType.cs | 71 +++ .../Model/events/TurnStartPayload.cs | 190 +++++++ .../Prompty.Core/Model/events/TurnStatus.cs | 20 + .../Prompty.Core/Model/events/TurnSummary.cs | 261 +++++++++ .../Prompty.Core/Model/events/TurnTrace.cs | 283 ++++++++++ .../csharp/Prompty.Core/Model/model/Model.cs | 4 +- .../Prompty.Core/Model/model/ModelInfo.cs | 8 +- .../Prompty.Core/Model/model/TokenUsage.cs | 4 +- .../Model/pipeline/CompactionConfig.cs | 4 +- .../Prompty.Core/Model/pipeline/Executor.cs | 2 +- .../Prompty.Core/Model/pipeline/Parser.cs | 2 +- .../Prompty.Core/Model/pipeline/Processor.cs | 2 +- .../Model/pipeline/TurnOptions.cs | 8 +- .../Model/streaming/StreamOptions.cs | 2 +- .../Prompty.Core/Model/template/Template.cs | 10 +- .../Prompty.Core/Model/tools/CustomTool.cs | 8 +- .../Model/tools/McpApprovalMode.cs | 4 +- .../Prompty.Core/Model/tools/PromptyTool.cs | 4 +- .../Prompty.Core/Model/tools/ToolContext.cs | 4 +- .../Model/tools/ToolDispatchResult.cs | 4 +- .../Prompty.Core/Model/tracing/TraceSpan.cs | 4 +- .../Model/wire/AnthropicImageBlock.cs | 2 +- .../Model/wire/AnthropicToolDefinition.cs | 4 +- .../Model/wire/AnthropicToolUseBlock.cs | 2 +- .../Model/wire/AnthropicWireMessage.cs | 4 +- runtime/csharp/Prompty.Core/Pipeline.cs | 178 +++++- .../model/compaction_complete_payload.go | 22 +- .../model/compaction_complete_payload_test.go | 22 +- .../prompty/model/compaction_start_payload.go | 91 ++++ .../model/compaction_start_payload_test.go | 140 +++++ .../go/prompty/model/done_event_payload.go | 6 +- .../prompty/model/done_event_payload_test.go | 137 ----- .../go/prompty/model/error_event_payload.go | 18 +- .../prompty/model/error_event_payload_test.go | 36 +- .../go/prompty/model/llm_complete_payload.go | 121 +++++ .../model/llm_complete_payload_test.go | 168 ++++++ runtime/go/prompty/model/llm_start_payload.go | 127 +++++ .../prompty/model/llm_start_payload_test.go | 182 +++++++ .../prompty/model/messages_updated_payload.go | 47 +- .../model/messages_updated_payload_test.go | 151 ++++++ .../model/permission_completed_payload.go | 93 ++++ .../permission_completed_payload_test.go | 168 ++++++ .../model/permission_requested_payload.go | 97 ++++ .../permission_requested_payload_test.go | 154 ++++++ runtime/go/prompty/model/prompty.go | 6 + runtime/go/prompty/model/retry_payload.go | 142 +++++ .../go/prompty/model/retry_payload_test.go | 196 +++++++ .../model/tool_call_complete_payload.go | 131 +++++ .../model/tool_call_complete_payload_test.go | 196 +++++++ .../prompty/model/tool_call_start_payload.go | 12 +- .../model/tool_call_start_payload_test.go | 14 + runtime/go/prompty/model/tool_result.go | 56 +- runtime/go/prompty/model/tool_result_test.go | 53 +- runtime/go/prompty/model/turn_end_payload.go | 137 +++++ .../go/prompty/model/turn_end_payload_test.go | 154 ++++++ runtime/go/prompty/model/turn_event.go | 167 ++++++ runtime/go/prompty/model/turn_event_test.go | 210 +++++++ .../go/prompty/model/turn_start_payload.go | 110 ++++ .../prompty/model/turn_start_payload_test.go | 154 ++++++ runtime/go/prompty/model/turn_summary.go | 185 +++++++ runtime/go/prompty/model/turn_summary_test.go | 224 ++++++++ runtime/go/prompty/model/turn_trace.go | 125 +++++ runtime/go/prompty/model/turn_trace_test.go | 168 ++++++ .../prompty/prompty/core/agent_events.py | 16 +- .../python/prompty/prompty/core/pipeline.py | 378 +++++++++++-- .../python/prompty/prompty/model/__init__.py | 24 + .../prompty/prompty/model/agent/_Prompty.py | 6 + .../prompty/model/conversation/_ToolResult.py | 32 +- .../events/_CompactionCompletePayload.py | 7 + .../model/events/_CompactionStartPayload.py | 97 ++++ .../prompty/model/events/_DoneEventPayload.py | 6 +- .../model/events/_ErrorEventPayload.py | 14 + .../model/events/_LlmCompletePayload.py | 119 ++++ .../prompty/model/events/_LlmStartPayload.py | 118 ++++ .../model/events/_MessagesUpdatedPayload.py | 46 +- .../events/_PermissionCompletedPayload.py | 111 ++++ .../events/_PermissionRequestedPayload.py | 111 ++++ .../prompty/model/events/_RetryPayload.py | 125 +++++ .../model/events/_ToolCallCompletePayload.py | 133 +++++ .../model/events/_ToolCallStartPayload.py | 7 + .../prompty/model/events/_TurnEndPayload.py | 120 ++++ .../prompty/model/events/_TurnEvent.py | 171 ++++++ .../prompty/model/events/_TurnStartPayload.py | 111 ++++ .../prompty/model/events/_TurnSummary.py | 147 +++++ .../prompty/model/events/_TurnTrace.py | 150 +++++ .../prompty/prompty/model/events/__init__.py | 24 + .../model/agent/test_guardrail_result.py | 2 +- .../prompty/tests/model/agent/test_prompty.py | 176 +++--- .../connection/test_anonymous_connection.py | 2 +- .../connection/test_api_key_connection.py | 2 +- .../tests/model/connection/test_connection.py | 2 +- .../connection/test_foundry_connection.py | 2 +- .../connection/test_o_auth_connection.py | 2 +- .../connection/test_reference_connection.py | 2 +- .../connection/test_remote_connection.py | 2 +- .../model/conversation/test_audio_part.py | 2 +- .../model/conversation/test_file_part.py | 2 +- .../model/conversation/test_image_part.py | 2 +- .../tests/model/conversation/test_message.py | 2 +- .../model/conversation/test_text_part.py | 2 +- .../model/conversation/test_thread_marker.py | 2 +- .../model/conversation/test_tool_call.py | 2 +- .../model/conversation/test_tool_result.py | 34 +- .../tests/model/core/test_array_property.py | 2 +- .../model/core/test_file_not_found_error.py | 2 +- .../tests/model/core/test_invoker_error.py | 2 +- .../tests/model/core/test_object_property.py | 2 +- .../prompty/tests/model/core/test_property.py | 2 +- .../tests/model/core/test_validation_error.py | 2 +- .../model/core/test_validation_result.py | 2 +- .../test_compaction_complete_payload.py | 18 +- .../events/test_compaction_failed_payload.py | 2 +- .../events/test_compaction_start_payload.py | 73 +++ .../model/events/test_done_event_payload.py | 72 --- .../tests/model/events/test_error_chunk.py | 2 +- .../model/events/test_error_event_payload.py | 26 +- .../model/events/test_llm_complete_payload.py | 89 +++ .../model/events/test_llm_start_payload.py | 97 ++++ .../events/test_messages_updated_payload.py | 80 +++ .../test_permission_completed_payload.py | 89 +++ .../test_permission_requested_payload.py | 81 +++ .../tests/model/events/test_retry_payload.py | 105 ++++ .../model/events/test_status_event_payload.py | 2 +- .../tests/model/events/test_text_chunk.py | 2 +- .../tests/model/events/test_thinking_chunk.py | 2 +- .../events/test_thinking_event_payload.py | 2 +- .../model/events/test_token_event_payload.py | 2 +- .../events/test_tool_call_complete_payload.py | 105 ++++ .../events/test_tool_call_start_payload.py | 10 +- .../tests/model/events/test_tool_chunk.py | 2 +- .../model/events/test_tool_result_payload.py | 2 +- .../model/events/test_turn_end_payload.py | 81 +++ .../tests/model/events/test_turn_event.py | 113 ++++ .../model/events/test_turn_start_payload.py | 81 +++ .../tests/model/events/test_turn_summary.py | 121 +++++ .../tests/model/events/test_turn_trace.py | 89 +++ .../prompty/tests/model/model/test_model.py | 2 +- .../tests/model/model/test_model_info.py | 2 +- .../tests/model/model/test_model_options.py | 2 +- .../tests/model/model/test_token_usage.py | 2 +- .../model/pipeline/test_compaction_config.py | 2 +- .../tests/model/pipeline/test_turn_options.py | 2 +- .../model/streaming/test_stream_options.py | 2 +- .../model/template/test_format_config.py | 2 +- .../model/template/test_parser_config.py | 2 +- .../tests/model/template/test_template.py | 2 +- .../prompty/tests/model/tools/test_binding.py | 2 +- .../tests/model/tools/test_custom_tool.py | 2 +- .../tests/model/tools/test_function_tool.py | 4 +- .../model/tools/test_mcp_approval_mode.py | 2 +- .../tests/model/tools/test_mcp_tool.py | 2 +- .../tests/model/tools/test_open_api_tool.py | 2 +- .../tests/model/tools/test_prompty_tool.py | 2 +- .../prompty/tests/model/tools/test_tool.py | 2 +- .../tests/model/tools/test_tool_context.py | 2 +- .../model/tools/test_tool_dispatch_result.py | 2 +- .../tests/model/tracing/test_trace_file.py | 2 +- .../tests/model/tracing/test_trace_span.py | 2 +- .../tests/model/tracing/test_trace_time.py | 2 +- .../model/wire/test_anthropic_image_source.py | 2 +- .../wire/test_anthropic_messages_request.py | 2 +- .../wire/test_anthropic_messages_response.py | 2 +- .../model/wire/test_anthropic_text_block.py | 2 +- .../wire/test_anthropic_tool_definition.py | 2 +- .../wire/test_anthropic_tool_result_block.py | 2 +- .../wire/test_anthropic_tool_use_block.py | 2 +- .../tests/model/wire/test_anthropic_usage.py | 2 +- .../model/wire/test_anthropic_wire_message.py | 2 +- .../src/model/agent/guardrail_result.rs | 35 +- runtime/rust/prompty/src/model/agent/mod.rs | 8 +- .../rust/prompty/src/model/agent/prompty.rs | 218 +++----- .../src/model/connection/connection.rs | 202 ++----- .../rust/prompty/src/model/connection/mod.rs | 8 +- runtime/rust/prompty/src/model/context.rs | 14 +- .../src/model/conversation/content_part.rs | 114 +--- .../prompty/src/model/conversation/message.rs | 74 +-- .../prompty/src/model/conversation/mod.rs | 8 +- .../src/model/conversation/thread_marker.rs | 30 +- .../src/model/conversation/tool_call.rs | 36 +- .../src/model/conversation/tool_result.rs | 110 +++- .../src/model/core/file_not_found_error.rs | 30 +- .../prompty/src/model/core/invoker_error.rs | 41 +- runtime/rust/prompty/src/model/core/mod.rs | 8 +- .../rust/prompty/src/model/core/property.rs | 110 +--- .../src/model/core/validation_error.rs | 41 +- .../src/model/core/validation_result.rs | 35 +- .../events/compaction_complete_payload.rs | 24 +- .../model/events/compaction_failed_payload.rs | 19 +- .../model/events/compaction_start_payload.rs | 63 +++ .../src/model/events/done_event_payload.rs | 52 +- .../src/model/events/error_event_payload.rs | 31 +- .../src/model/events/llm_complete_payload.rs | 86 +++ .../src/model/events/llm_start_payload.rs | 81 +++ .../model/events/messages_updated_payload.rs | 73 ++- runtime/rust/prompty/src/model/events/mod.rs | 44 +- .../events/permission_completed_payload.rs | 73 +++ .../events/permission_requested_payload.rs | 81 +++ .../prompty/src/model/events/retry_payload.rs | 87 +++ .../src/model/events/status_event_payload.rs | 19 +- .../prompty/src/model/events/stream_chunk.rs | 73 +-- .../model/events/thinking_event_payload.rs | 19 +- .../src/model/events/token_event_payload.rs | 19 +- .../events/tool_call_complete_payload.rs | 96 ++++ .../model/events/tool_call_start_payload.rs | 36 +- .../src/model/events/tool_result_payload.rs | 25 +- .../src/model/events/turn_end_payload.rs | 123 +++++ .../prompty/src/model/events/turn_event.rs | 219 ++++++++ .../src/model/events/turn_start_payload.rs | 81 +++ .../prompty/src/model/events/turn_summary.rs | 110 ++++ .../prompty/src/model/events/turn_trace.rs | 114 ++++ runtime/rust/prompty/src/model/mod.rs | 8 +- runtime/rust/prompty/src/model/model/mod.rs | 8 +- runtime/rust/prompty/src/model/model/model.rs | 49 +- .../prompty/src/model/model/model_info.rs | 87 +-- .../prompty/src/model/model/model_options.rs | 174 ++---- .../prompty/src/model/model/token_usage.rs | 64 +-- .../src/model/pipeline/compaction_config.rs | 34 +- .../prompty/src/model/pipeline/executor.rs | 29 +- .../rust/prompty/src/model/pipeline/mod.rs | 8 +- .../rust/prompty/src/model/pipeline/parser.rs | 16 +- .../prompty/src/model/pipeline/processor.rs | 20 +- .../prompty/src/model/pipeline/renderer.rs | 16 +- .../src/model/pipeline/turn_options.rs | 53 +- .../rust/prompty/src/model/streaming/mod.rs | 8 +- .../src/model/streaming/stream_options.rs | 8 +- .../src/model/template/format_config.rs | 30 +- .../rust/prompty/src/model/template/mod.rs | 8 +- .../src/model/template/parser_config.rs | 30 +- .../prompty/src/model/template/template.rs | 20 +- .../rust/prompty/src/model/tools/binding.rs | 35 +- .../src/model/tools/mcp_approval_mode.rs | 53 +- runtime/rust/prompty/src/model/tools/mod.rs | 8 +- runtime/rust/prompty/src/model/tools/tool.rs | 245 +++------ .../prompty/src/model/tools/tool_context.rs | 41 +- .../src/model/tools/tool_dispatch_result.rs | 36 +- runtime/rust/prompty/src/model/tracing/mod.rs | 8 +- .../prompty/src/model/tracing/trace_file.rs | 36 +- .../prompty/src/model/tracing/trace_span.rs | 66 +-- .../prompty/src/model/tracing/trace_time.rs | 42 +- .../src/model/wire/anthropic_image_block.rs | 25 +- .../src/model/wire/anthropic_image_source.rs | 41 +- .../model/wire/anthropic_messages_request.rs | 173 ++---- .../model/wire/anthropic_messages_response.rs | 75 +-- .../src/model/wire/anthropic_text_block.rs | 30 +- .../model/wire/anthropic_tool_definition.rs | 35 +- .../model/wire/anthropic_tool_result_block.rs | 41 +- .../model/wire/anthropic_tool_use_block.rs | 42 +- .../prompty/src/model/wire/anthropic_usage.rs | 28 +- .../src/model/wire/anthropic_wire_message.rs | 30 +- runtime/rust/prompty/src/model/wire/mod.rs | 8 +- runtime/rust/prompty/src/pipeline.rs | 511 +++++++++++++++++- runtime/rust/prompty/tests/agent_vectors.rs | 26 +- .../model/agent/guardrail_result_test.rs | 26 +- runtime/rust/prompty/tests/model/agent/mod.rs | 10 +- .../prompty/tests/model/agent/prompty_test.rs | 472 +++------------- .../tests/model/connection/connection_test.rs | 22 +- .../prompty/tests/model/connection/mod.rs | 8 +- .../model/conversation/content_part_test.rs | 8 +- .../tests/model/conversation/message_test.rs | 26 +- .../prompty/tests/model/conversation/mod.rs | 12 +- .../model/conversation/thread_marker_test.rs | 26 +- .../model/conversation/tool_call_test.rs | 26 +- .../model/conversation/tool_result_test.rs | 51 +- .../model/core/file_not_found_error_test.rs | 26 +- .../tests/model/core/invoker_error_test.rs | 26 +- runtime/rust/prompty/tests/model/core/mod.rs | 12 +- .../prompty/tests/model/core/property_test.rs | 20 +- .../tests/model/core/validation_error_test.rs | 26 +- .../model/core/validation_result_test.rs | 26 +- .../compaction_complete_payload_test.rs | 36 +- .../events/compaction_failed_payload_test.rs | 36 +- .../events/compaction_start_payload_test.rs | 49 ++ .../model/events/done_event_payload_test.rs | 63 +-- .../model/events/error_event_payload_test.rs | 42 +- .../model/events/llm_complete_payload_test.rs | 62 +++ .../model/events/llm_start_payload_test.rs | 68 +++ .../events/messages_updated_payload_test.rs | 58 +- .../rust/prompty/tests/model/events/mod.rs | 36 +- .../permission_completed_payload_test.rs | 60 ++ .../permission_requested_payload_test.rs | 55 ++ .../tests/model/events/retry_payload_test.rs | 72 +++ .../model/events/status_event_payload_test.rs | 26 +- .../tests/model/events/stream_chunk_test.rs | 8 +- .../events/thinking_event_payload_test.rs | 26 +- .../model/events/token_event_payload_test.rs | 26 +- .../events/tool_call_complete_payload_test.rs | 72 +++ .../events/tool_call_start_payload_test.rs | 32 +- .../model/events/tool_result_payload_test.rs | 26 +- .../model/events/turn_end_payload_test.rs | 57 ++ .../tests/model/events/turn_event_test.rs | 79 +++ .../model/events/turn_start_payload_test.rs | 56 ++ .../tests/model/events/turn_summary_test.rs | 83 +++ .../tests/model/events/turn_trace_test.rs | 61 +++ runtime/rust/prompty/tests/model/main.rs | 8 +- runtime/rust/prompty/tests/model/model/mod.rs | 10 +- .../tests/model/model/model_info_test.rs | 46 +- .../tests/model/model/model_options_test.rs | 76 +-- .../prompty/tests/model/model/model_test.rs | 26 +- .../tests/model/model/token_usage_test.rs | 56 +- .../model/pipeline/compaction_config_test.rs | 26 +- .../rust/prompty/tests/model/pipeline/mod.rs | 8 +- .../tests/model/pipeline/turn_options_test.rs | 66 +-- .../rust/prompty/tests/model/streaming/mod.rs | 8 +- .../model/streaming/stream_options_test.rs | 36 +- .../model/template/format_config_test.rs | 20 +- .../rust/prompty/tests/model/template/mod.rs | 8 +- .../model/template/parser_config_test.rs | 20 +- .../tests/model/template/template_test.rs | 26 +- .../prompty/tests/model/tools/binding_test.rs | 26 +- .../model/tools/mcp_approval_mode_test.rs | 28 +- runtime/rust/prompty/tests/model/tools/mod.rs | 10 +- .../tests/model/tools/tool_context_test.rs | 26 +- .../model/tools/tool_dispatch_result_test.rs | 26 +- .../prompty/tests/model/tools/tool_test.rs | 20 +- .../rust/prompty/tests/model/tracing/mod.rs | 12 +- .../tests/model/tracing/trace_file_test.rs | 26 +- .../tests/model/tracing/trace_span_test.rs | 41 +- .../tests/model/tracing/trace_time_test.rs | 26 +- .../model/wire/anthropic_image_block_test.rs | 8 +- .../model/wire/anthropic_image_source_test.rs | 26 +- .../wire/anthropic_messages_request_test.rs | 41 +- .../wire/anthropic_messages_response_test.rs | 26 +- .../model/wire/anthropic_text_block_test.rs | 26 +- .../wire/anthropic_tool_definition_test.rs | 41 +- .../wire/anthropic_tool_result_block_test.rs | 26 +- .../wire/anthropic_tool_use_block_test.rs | 26 +- .../tests/model/wire/anthropic_usage_test.rs | 26 +- .../model/wire/anthropic_wire_message_test.rs | 26 +- runtime/rust/prompty/tests/model/wire/mod.rs | 22 +- runtime/rust/prompty/tests/parse_vectors.rs | 2 +- .../packages/core/src/core/agent-events.ts | 19 +- .../packages/core/src/core/pipeline.ts | 202 +++++-- .../src/model/conversation/tool-result.ts | 42 ++ .../events/compaction-complete-payload.ts | 10 + .../model/events/compaction-start-payload.ts | 87 +++ .../src/model/events/done-event-payload.ts | 4 +- .../src/model/events/error-event-payload.ts | 20 + .../packages/core/src/model/events/index.ts | 12 + .../src/model/events/llm-complete-payload.ts | 120 ++++ .../src/model/events/llm-start-payload.ts | 113 ++++ .../model/events/messages-updated-payload.ts | 75 ++- .../events/permission-completed-payload.ts | 111 ++++ .../events/permission-requested-payload.ts | 113 ++++ .../core/src/model/events/retry-payload.ts | 119 ++++ .../events/tool-call-complete-payload.ts | 145 +++++ .../model/events/tool-call-start-payload.ts | 10 + .../core/src/model/events/turn-end-payload.ts | 115 ++++ .../core/src/model/events/turn-event.ts | 164 ++++++ .../src/model/events/turn-start-payload.ts | 103 ++++ .../core/src/model/events/turn-summary.ts | 151 ++++++ .../core/src/model/events/turn-trace.ts | 160 ++++++ .../packages/core/src/model/index.ts | 12 + .../core/tests/agent-extensions.test.ts | 14 +- .../model/conversation/tool-result.test.ts | 24 +- .../compaction-complete-payload.test.ts | 12 +- .../events/compaction-start-payload.test.ts | 67 +++ .../model/events/done-event-payload.test.ts | 38 -- .../model/events/error-event-payload.test.ts | 16 +- .../model/events/llm-complete-payload.test.ts | 75 +++ .../model/events/llm-start-payload.test.ts | 79 +++ .../events/messages-updated-payload.test.ts | 38 ++ .../permission-completed-payload.test.ts | 75 +++ .../permission-requested-payload.test.ts | 71 +++ .../tests/model/events/retry-payload.test.ts | 83 +++ .../events/tool-call-complete-payload.test.ts | 83 +++ .../events/tool-call-start-payload.test.ts | 12 +- .../model/events/turn-end-payload.test.ts | 71 +++ .../tests/model/events/turn-event.test.ts | 87 +++ .../model/events/turn-start-payload.test.ts | 71 +++ .../tests/model/events/turn-summary.test.ts | 91 ++++ .../tests/model/events/turn-trace.test.ts | 75 +++ .../emitter/src/languages/csharp/emitter.ts | 11 +- .../src/languages/python/test-emitter.ts | 4 +- schema/emitter/src/languages/rust/driver.ts | 23 +- schema/emitter/src/languages/rust/emitter.ts | 11 +- schema/model/conversation/tool-invocation.tsp | 22 + schema/model/events/payloads.tsp | 317 ++++++++++- .../schemas/CompactionCompletePayload.yaml | 5 + .../schemas/CompactionStartPayload.yaml | 12 + vscode/prompty/schemas/DoneEventPayload.yaml | 3 +- vscode/prompty/schemas/ErrorEventPayload.yaml | 6 + .../prompty/schemas/LlmCompletePayload.yaml | 17 + vscode/prompty/schemas/LlmStartPayload.yaml | 21 + .../schemas/MessagesUpdatedPayload.yaml | 15 +- .../schemas/PermissionCompletedPayload.yaml | 17 + .../schemas/PermissionRequestedPayload.yaml | 16 + vscode/prompty/schemas/Prompty.yaml | 6 + vscode/prompty/schemas/RetryPayload.yaml | 27 + .../schemas/ToolCallCompletePayload.yaml | 26 + .../prompty/schemas/ToolCallStartPayload.yaml | 3 + vscode/prompty/schemas/ToolResult.yaml | 20 + vscode/prompty/schemas/TurnEndPayload.yaml | 24 + vscode/prompty/schemas/TurnEvent.yaml | 80 +++ vscode/prompty/schemas/TurnStartPayload.yaml | 16 + vscode/prompty/schemas/TurnSummary.yaml | 41 ++ vscode/prompty/schemas/TurnTrace.yaml | 26 + .../reference/CompactionCompletePayload.md | 3 + .../docs/reference/CompactionStartPayload.md | 36 ++ .../docs/reference/DoneEventPayload.md | 10 +- .../docs/reference/ErrorEventPayload.md | 6 + .../docs/reference/LlmCompletePayload.md | 56 ++ .../content/docs/reference/LlmStartPayload.md | 45 ++ .../docs/reference/MessagesUpdatedPayload.md | 22 + .../reference/PermissionCompletedPayload.md | 42 ++ .../reference/PermissionRequestedPayload.md | 41 ++ web/src/content/docs/reference/Prompty.md | 6 + .../content/docs/reference/RetryPayload.md | 48 ++ .../docs/reference/ToolCallCompletePayload.md | 65 +++ .../docs/reference/ToolCallStartPayload.md | 3 + .../docs/reference/ToolDispatchResult.md | 4 + web/src/content/docs/reference/ToolResult.md | 11 + .../docs/reference/ToolResultPayload.md | 4 + .../content/docs/reference/TurnEndPayload.md | 43 ++ web/src/content/docs/reference/TurnEvent.md | 57 ++ .../docs/reference/TurnStartPayload.md | 41 ++ web/src/content/docs/reference/TurnSummary.md | 68 +++ web/src/content/docs/reference/TurnTrace.md | 75 +++ web/src/content/docs/reference/index.md | 18 +- 471 files changed, 20753 insertions(+), 5040 deletions(-) create mode 100644 runtime/csharp/Prompty.Core.Tests/Model/events/CompactionStartPayloadConversionTests.cs create mode 100644 runtime/csharp/Prompty.Core.Tests/Model/events/LlmCompletePayloadConversionTests.cs create mode 100644 runtime/csharp/Prompty.Core.Tests/Model/events/LlmStartPayloadConversionTests.cs create mode 100644 runtime/csharp/Prompty.Core.Tests/Model/events/PermissionCompletedPayloadConversionTests.cs create mode 100644 runtime/csharp/Prompty.Core.Tests/Model/events/PermissionRequestedPayloadConversionTests.cs create mode 100644 runtime/csharp/Prompty.Core.Tests/Model/events/RetryPayloadConversionTests.cs create mode 100644 runtime/csharp/Prompty.Core.Tests/Model/events/ToolCallCompletePayloadConversionTests.cs create mode 100644 runtime/csharp/Prompty.Core.Tests/Model/events/TurnEndPayloadConversionTests.cs create mode 100644 runtime/csharp/Prompty.Core.Tests/Model/events/TurnEventConversionTests.cs create mode 100644 runtime/csharp/Prompty.Core.Tests/Model/events/TurnStartPayloadConversionTests.cs create mode 100644 runtime/csharp/Prompty.Core.Tests/Model/events/TurnSummaryConversionTests.cs create mode 100644 runtime/csharp/Prompty.Core.Tests/Model/events/TurnTraceConversionTests.cs create mode 100644 runtime/csharp/Prompty.Core/Model/conversation/ToolResultStatus.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/CompactionStartPayload.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/LlmCompletePayload.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/LlmStartPayload.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/PermissionCompletedPayload.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/PermissionRequestedPayload.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/RetryPayload.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/ToolCallCompletePayload.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/TurnEndPayload.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/TurnEvent.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/TurnEventType.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/TurnStartPayload.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/TurnStatus.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/TurnSummary.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/TurnTrace.cs create mode 100644 runtime/go/prompty/model/compaction_start_payload.go create mode 100644 runtime/go/prompty/model/compaction_start_payload_test.go create mode 100644 runtime/go/prompty/model/llm_complete_payload.go create mode 100644 runtime/go/prompty/model/llm_complete_payload_test.go create mode 100644 runtime/go/prompty/model/llm_start_payload.go create mode 100644 runtime/go/prompty/model/llm_start_payload_test.go create mode 100644 runtime/go/prompty/model/permission_completed_payload.go create mode 100644 runtime/go/prompty/model/permission_completed_payload_test.go create mode 100644 runtime/go/prompty/model/permission_requested_payload.go create mode 100644 runtime/go/prompty/model/permission_requested_payload_test.go create mode 100644 runtime/go/prompty/model/retry_payload.go create mode 100644 runtime/go/prompty/model/retry_payload_test.go create mode 100644 runtime/go/prompty/model/tool_call_complete_payload.go create mode 100644 runtime/go/prompty/model/tool_call_complete_payload_test.go create mode 100644 runtime/go/prompty/model/turn_end_payload.go create mode 100644 runtime/go/prompty/model/turn_end_payload_test.go create mode 100644 runtime/go/prompty/model/turn_event.go create mode 100644 runtime/go/prompty/model/turn_event_test.go create mode 100644 runtime/go/prompty/model/turn_start_payload.go create mode 100644 runtime/go/prompty/model/turn_start_payload_test.go create mode 100644 runtime/go/prompty/model/turn_summary.go create mode 100644 runtime/go/prompty/model/turn_summary_test.go create mode 100644 runtime/go/prompty/model/turn_trace.go create mode 100644 runtime/go/prompty/model/turn_trace_test.go create mode 100644 runtime/python/prompty/prompty/model/events/_CompactionStartPayload.py create mode 100644 runtime/python/prompty/prompty/model/events/_LlmCompletePayload.py create mode 100644 runtime/python/prompty/prompty/model/events/_LlmStartPayload.py create mode 100644 runtime/python/prompty/prompty/model/events/_PermissionCompletedPayload.py create mode 100644 runtime/python/prompty/prompty/model/events/_PermissionRequestedPayload.py create mode 100644 runtime/python/prompty/prompty/model/events/_RetryPayload.py create mode 100644 runtime/python/prompty/prompty/model/events/_ToolCallCompletePayload.py create mode 100644 runtime/python/prompty/prompty/model/events/_TurnEndPayload.py create mode 100644 runtime/python/prompty/prompty/model/events/_TurnEvent.py create mode 100644 runtime/python/prompty/prompty/model/events/_TurnStartPayload.py create mode 100644 runtime/python/prompty/prompty/model/events/_TurnSummary.py create mode 100644 runtime/python/prompty/prompty/model/events/_TurnTrace.py create mode 100644 runtime/python/prompty/tests/model/events/test_compaction_start_payload.py create mode 100644 runtime/python/prompty/tests/model/events/test_llm_complete_payload.py create mode 100644 runtime/python/prompty/tests/model/events/test_llm_start_payload.py create mode 100644 runtime/python/prompty/tests/model/events/test_permission_completed_payload.py create mode 100644 runtime/python/prompty/tests/model/events/test_permission_requested_payload.py create mode 100644 runtime/python/prompty/tests/model/events/test_retry_payload.py create mode 100644 runtime/python/prompty/tests/model/events/test_tool_call_complete_payload.py create mode 100644 runtime/python/prompty/tests/model/events/test_turn_end_payload.py create mode 100644 runtime/python/prompty/tests/model/events/test_turn_event.py create mode 100644 runtime/python/prompty/tests/model/events/test_turn_start_payload.py create mode 100644 runtime/python/prompty/tests/model/events/test_turn_summary.py create mode 100644 runtime/python/prompty/tests/model/events/test_turn_trace.py create mode 100644 runtime/rust/prompty/src/model/events/compaction_start_payload.rs create mode 100644 runtime/rust/prompty/src/model/events/llm_complete_payload.rs create mode 100644 runtime/rust/prompty/src/model/events/llm_start_payload.rs create mode 100644 runtime/rust/prompty/src/model/events/permission_completed_payload.rs create mode 100644 runtime/rust/prompty/src/model/events/permission_requested_payload.rs create mode 100644 runtime/rust/prompty/src/model/events/retry_payload.rs create mode 100644 runtime/rust/prompty/src/model/events/tool_call_complete_payload.rs create mode 100644 runtime/rust/prompty/src/model/events/turn_end_payload.rs create mode 100644 runtime/rust/prompty/src/model/events/turn_event.rs create mode 100644 runtime/rust/prompty/src/model/events/turn_start_payload.rs create mode 100644 runtime/rust/prompty/src/model/events/turn_summary.rs create mode 100644 runtime/rust/prompty/src/model/events/turn_trace.rs create mode 100644 runtime/rust/prompty/tests/model/events/compaction_start_payload_test.rs create mode 100644 runtime/rust/prompty/tests/model/events/llm_complete_payload_test.rs create mode 100644 runtime/rust/prompty/tests/model/events/llm_start_payload_test.rs create mode 100644 runtime/rust/prompty/tests/model/events/permission_completed_payload_test.rs create mode 100644 runtime/rust/prompty/tests/model/events/permission_requested_payload_test.rs create mode 100644 runtime/rust/prompty/tests/model/events/retry_payload_test.rs create mode 100644 runtime/rust/prompty/tests/model/events/tool_call_complete_payload_test.rs create mode 100644 runtime/rust/prompty/tests/model/events/turn_end_payload_test.rs create mode 100644 runtime/rust/prompty/tests/model/events/turn_event_test.rs create mode 100644 runtime/rust/prompty/tests/model/events/turn_start_payload_test.rs create mode 100644 runtime/rust/prompty/tests/model/events/turn_summary_test.rs create mode 100644 runtime/rust/prompty/tests/model/events/turn_trace_test.rs create mode 100644 runtime/typescript/packages/core/src/model/events/compaction-start-payload.ts create mode 100644 runtime/typescript/packages/core/src/model/events/llm-complete-payload.ts create mode 100644 runtime/typescript/packages/core/src/model/events/llm-start-payload.ts create mode 100644 runtime/typescript/packages/core/src/model/events/permission-completed-payload.ts create mode 100644 runtime/typescript/packages/core/src/model/events/permission-requested-payload.ts create mode 100644 runtime/typescript/packages/core/src/model/events/retry-payload.ts create mode 100644 runtime/typescript/packages/core/src/model/events/tool-call-complete-payload.ts create mode 100644 runtime/typescript/packages/core/src/model/events/turn-end-payload.ts create mode 100644 runtime/typescript/packages/core/src/model/events/turn-event.ts create mode 100644 runtime/typescript/packages/core/src/model/events/turn-start-payload.ts create mode 100644 runtime/typescript/packages/core/src/model/events/turn-summary.ts create mode 100644 runtime/typescript/packages/core/src/model/events/turn-trace.ts create mode 100644 runtime/typescript/packages/core/tests/model/events/compaction-start-payload.test.ts create mode 100644 runtime/typescript/packages/core/tests/model/events/llm-complete-payload.test.ts create mode 100644 runtime/typescript/packages/core/tests/model/events/llm-start-payload.test.ts create mode 100644 runtime/typescript/packages/core/tests/model/events/permission-completed-payload.test.ts create mode 100644 runtime/typescript/packages/core/tests/model/events/permission-requested-payload.test.ts create mode 100644 runtime/typescript/packages/core/tests/model/events/retry-payload.test.ts create mode 100644 runtime/typescript/packages/core/tests/model/events/tool-call-complete-payload.test.ts create mode 100644 runtime/typescript/packages/core/tests/model/events/turn-end-payload.test.ts create mode 100644 runtime/typescript/packages/core/tests/model/events/turn-event.test.ts create mode 100644 runtime/typescript/packages/core/tests/model/events/turn-start-payload.test.ts create mode 100644 runtime/typescript/packages/core/tests/model/events/turn-summary.test.ts create mode 100644 runtime/typescript/packages/core/tests/model/events/turn-trace.test.ts create mode 100644 vscode/prompty/schemas/CompactionStartPayload.yaml create mode 100644 vscode/prompty/schemas/LlmCompletePayload.yaml create mode 100644 vscode/prompty/schemas/LlmStartPayload.yaml create mode 100644 vscode/prompty/schemas/PermissionCompletedPayload.yaml create mode 100644 vscode/prompty/schemas/PermissionRequestedPayload.yaml create mode 100644 vscode/prompty/schemas/RetryPayload.yaml create mode 100644 vscode/prompty/schemas/ToolCallCompletePayload.yaml create mode 100644 vscode/prompty/schemas/TurnEndPayload.yaml create mode 100644 vscode/prompty/schemas/TurnEvent.yaml create mode 100644 vscode/prompty/schemas/TurnStartPayload.yaml create mode 100644 vscode/prompty/schemas/TurnSummary.yaml create mode 100644 vscode/prompty/schemas/TurnTrace.yaml create mode 100644 web/src/content/docs/reference/CompactionStartPayload.md create mode 100644 web/src/content/docs/reference/LlmCompletePayload.md create mode 100644 web/src/content/docs/reference/LlmStartPayload.md create mode 100644 web/src/content/docs/reference/PermissionCompletedPayload.md create mode 100644 web/src/content/docs/reference/PermissionRequestedPayload.md create mode 100644 web/src/content/docs/reference/RetryPayload.md create mode 100644 web/src/content/docs/reference/ToolCallCompletePayload.md create mode 100644 web/src/content/docs/reference/TurnEndPayload.md create mode 100644 web/src/content/docs/reference/TurnEvent.md create mode 100644 web/src/content/docs/reference/TurnStartPayload.md create mode 100644 web/src/content/docs/reference/TurnSummary.md create mode 100644 web/src/content/docs/reference/TurnTrace.md diff --git a/runtime/csharp/Prompty.Core.Tests/AgentExtensionsTests.cs b/runtime/csharp/Prompty.Core.Tests/AgentExtensionsTests.cs index 2a4704c9..9ffe3e37 100644 --- a/runtime/csharp/Prompty.Core.Tests/AgentExtensionsTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/AgentExtensionsTests.cs @@ -26,7 +26,13 @@ public void EmitEvent_CallsCallback_WithCorrectArgs() AgentEvents.EmitEvent(cb, AgentEventType.ToolCallStart, data); Assert.Equal(AgentEventType.ToolCallStart, captured); - Assert.Same(data, capturedData); + Assert.NotNull(capturedData); + Assert.Equal("value", capturedData["key"]); + var turnEvent = Assert.IsType>(capturedData["turnEvent"]); + Assert.IsType(turnEvent["id"]); + Assert.Equal("tool_call_start", turnEvent["type"]); + Assert.IsType(turnEvent["timestamp"]); + Assert.Same(data, turnEvent["payload"]); } [Fact] diff --git a/runtime/csharp/Prompty.Core.Tests/Model/conversation/ToolResultConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/conversation/ToolResultConversionTests.cs index a8566d0c..2e3d8a99 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/conversation/ToolResultConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/conversation/ToolResultConversionTests.cs @@ -14,12 +14,18 @@ public void LoadYamlInput() parts: - kind: text value: 72°F and sunny +errorKind: missing_tool +errorMessage: Tool 'get_weather' is not registered +durationMs: 42 """; var instance = ToolResult.FromYaml(yamlData); Assert.NotNull(instance); + Assert.Equal("missing_tool", instance.ErrorKind); + Assert.Equal("Tool 'get_weather' is not registered", instance.ErrorMessage); + Assert.Equal(42, instance.DurationMs); } [Fact] @@ -32,12 +38,18 @@ public void LoadJsonInput() "kind": "text", "value": "72°F and sunny" } - ] + ], + "errorKind": "missing_tool", + "errorMessage": "Tool 'get_weather' is not registered", + "durationMs": 42 } """; var instance = ToolResult.FromJson(jsonData); Assert.NotNull(instance); + Assert.Equal("missing_tool", instance.ErrorKind); + Assert.Equal("Tool 'get_weather' is not registered", instance.ErrorMessage); + Assert.Equal(42, instance.DurationMs); } [Fact] @@ -51,7 +63,10 @@ public void RoundtripJson() "kind": "text", "value": "72°F and sunny" } - ] + ], + "errorKind": "missing_tool", + "errorMessage": "Tool 'get_weather' is not registered", + "durationMs": 42 } """; @@ -63,6 +78,9 @@ public void RoundtripJson() var reloaded = ToolResult.FromJson(json); Assert.NotNull(reloaded); + Assert.Equal("missing_tool", reloaded.ErrorKind); + Assert.Equal("Tool 'get_weather' is not registered", reloaded.ErrorMessage); + Assert.Equal(42, reloaded.DurationMs); } [Fact] @@ -73,6 +91,9 @@ public void RoundtripYaml() parts: - kind: text value: 72°F and sunny +errorKind: missing_tool +errorMessage: Tool 'get_weather' is not registered +durationMs: 42 """; @@ -84,6 +105,9 @@ public void RoundtripYaml() var reloaded = ToolResult.FromYaml(yaml); Assert.NotNull(reloaded); + Assert.Equal("missing_tool", reloaded.ErrorKind); + Assert.Equal("Tool 'get_weather' is not registered", reloaded.ErrorMessage); + Assert.Equal(42, reloaded.DurationMs); } [Fact] @@ -96,7 +120,10 @@ public void ToJsonProducesValidJson() "kind": "text", "value": "72°F and sunny" } - ] + ], + "errorKind": "missing_tool", + "errorMessage": "Tool 'get_weather' is not registered", + "durationMs": 42 } """; @@ -115,6 +142,9 @@ public void ToYamlProducesValidYaml() parts: - kind: text value: 72°F and sunny +errorKind: missing_tool +errorMessage: Tool 'get_weather' is not registered +durationMs: 42 """; diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/CompactionCompletePayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/CompactionCompletePayloadConversionTests.cs index 40f3a6c2..d9f7f19b 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/CompactionCompletePayloadConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/CompactionCompletePayloadConversionTests.cs @@ -13,6 +13,7 @@ public void LoadYamlInput() string yamlData = """ removed: 5 remaining: 3 +summaryLength: 1200 """; @@ -21,6 +22,7 @@ public void LoadYamlInput() Assert.NotNull(instance); Assert.Equal(5, instance.Removed); Assert.Equal(3, instance.Remaining); + Assert.Equal(1200, instance.SummaryLength); } [Fact] @@ -29,7 +31,8 @@ public void LoadJsonInput() string jsonData = """ { "removed": 5, - "remaining": 3 + "remaining": 3, + "summaryLength": 1200 } """; @@ -37,6 +40,7 @@ public void LoadJsonInput() Assert.NotNull(instance); Assert.Equal(5, instance.Removed); Assert.Equal(3, instance.Remaining); + Assert.Equal(1200, instance.SummaryLength); } [Fact] @@ -46,7 +50,8 @@ public void RoundtripJson() string jsonData = """ { "removed": 5, - "remaining": 3 + "remaining": 3, + "summaryLength": 1200 } """; @@ -60,6 +65,7 @@ public void RoundtripJson() Assert.NotNull(reloaded); Assert.Equal(5, reloaded.Removed); Assert.Equal(3, reloaded.Remaining); + Assert.Equal(1200, reloaded.SummaryLength); } [Fact] @@ -69,6 +75,7 @@ public void RoundtripYaml() string yamlData = """ removed: 5 remaining: 3 +summaryLength: 1200 """; @@ -82,6 +89,7 @@ public void RoundtripYaml() Assert.NotNull(reloaded); Assert.Equal(5, reloaded.Removed); Assert.Equal(3, reloaded.Remaining); + Assert.Equal(1200, reloaded.SummaryLength); } [Fact] @@ -90,7 +98,8 @@ public void ToJsonProducesValidJson() string jsonData = """ { "removed": 5, - "remaining": 3 + "remaining": 3, + "summaryLength": 1200 } """; @@ -108,6 +117,7 @@ public void ToYamlProducesValidYaml() string yamlData = """ removed: 5 remaining: 3 +summaryLength: 1200 """; diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/CompactionStartPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/CompactionStartPayloadConversionTests.cs new file mode 100644 index 00000000..b5cd6584 --- /dev/null +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/CompactionStartPayloadConversionTests.cs @@ -0,0 +1,112 @@ +using Xunit; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + + +public class CompactionStartPayloadConversionTests +{ + [Fact] + public void LoadYamlInput() + { + string yamlData = """ +droppedCount: 5 + +"""; + + var instance = CompactionStartPayload.FromYaml(yamlData); + + Assert.NotNull(instance); + Assert.Equal(5, instance.DroppedCount); + } + + [Fact] + public void LoadJsonInput() + { + string jsonData = """ +{ + "droppedCount": 5 +} +"""; + + var instance = CompactionStartPayload.FromJson(jsonData); + Assert.NotNull(instance); + Assert.Equal(5, instance.DroppedCount); + } + + [Fact] + public void RoundtripJson() + { + // Test that FromJson -> ToJson -> FromJson produces equivalent data + string jsonData = """ +{ + "droppedCount": 5 +} +"""; + + var original = CompactionStartPayload.FromJson(jsonData); + Assert.NotNull(original); + + var json = original.ToJson(); + Assert.False(string.IsNullOrEmpty(json)); + + var reloaded = CompactionStartPayload.FromJson(json); + Assert.NotNull(reloaded); + Assert.Equal(5, reloaded.DroppedCount); + } + + [Fact] + public void RoundtripYaml() + { + // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data + string yamlData = """ +droppedCount: 5 + +"""; + + var original = CompactionStartPayload.FromYaml(yamlData); + Assert.NotNull(original); + + var yaml = original.ToYaml(); + Assert.False(string.IsNullOrEmpty(yaml)); + + var reloaded = CompactionStartPayload.FromYaml(yaml); + Assert.NotNull(reloaded); + Assert.Equal(5, reloaded.DroppedCount); + } + + [Fact] + public void ToJsonProducesValidJson() + { + string jsonData = """ +{ + "droppedCount": 5 +} +"""; + + var instance = CompactionStartPayload.FromJson(jsonData); + var json = instance.ToJson(); + + // Verify it's valid JSON by parsing it + var parsed = System.Text.Json.JsonDocument.Parse(json); + Assert.NotNull(parsed); + } + + [Fact] + public void ToYamlProducesValidYaml() + { + string yamlData = """ +droppedCount: 5 + +"""; + + var instance = CompactionStartPayload.FromYaml(yamlData); + var yaml = instance.ToYaml(); + + // Verify it's valid YAML by parsing it + var deserializer = new YamlDotNet.Serialization.DeserializerBuilder().Build(); + var parsed = deserializer.Deserialize(yaml); + Assert.NotNull(parsed); + } +} diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/DoneEventPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/DoneEventPayloadConversionTests.cs index 1211f745..db467680 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/DoneEventPayloadConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/DoneEventPayloadConversionTests.cs @@ -7,106 +7,4 @@ namespace Prompty.Core; public class DoneEventPayloadConversionTests { - [Fact] - public void LoadYamlInput() - { - string yamlData = """ -response: The weather in Paris is 72°F and sunny. - -"""; - - var instance = DoneEventPayload.FromYaml(yamlData); - - Assert.NotNull(instance); - Assert.Equal("The weather in Paris is 72°F and sunny.", instance.Response); - } - - [Fact] - public void LoadJsonInput() - { - string jsonData = """ -{ - "response": "The weather in Paris is 72°F and sunny." -} -"""; - - var instance = DoneEventPayload.FromJson(jsonData); - Assert.NotNull(instance); - Assert.Equal("The weather in Paris is 72°F and sunny.", instance.Response); - } - - [Fact] - public void RoundtripJson() - { - // Test that FromJson -> ToJson -> FromJson produces equivalent data - string jsonData = """ -{ - "response": "The weather in Paris is 72°F and sunny." -} -"""; - - var original = DoneEventPayload.FromJson(jsonData); - Assert.NotNull(original); - - var json = original.ToJson(); - Assert.False(string.IsNullOrEmpty(json)); - - var reloaded = DoneEventPayload.FromJson(json); - Assert.NotNull(reloaded); - Assert.Equal("The weather in Paris is 72°F and sunny.", reloaded.Response); - } - - [Fact] - public void RoundtripYaml() - { - // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data - string yamlData = """ -response: The weather in Paris is 72°F and sunny. - -"""; - - var original = DoneEventPayload.FromYaml(yamlData); - Assert.NotNull(original); - - var yaml = original.ToYaml(); - Assert.False(string.IsNullOrEmpty(yaml)); - - var reloaded = DoneEventPayload.FromYaml(yaml); - Assert.NotNull(reloaded); - Assert.Equal("The weather in Paris is 72°F and sunny.", reloaded.Response); - } - - [Fact] - public void ToJsonProducesValidJson() - { - string jsonData = """ -{ - "response": "The weather in Paris is 72°F and sunny." -} -"""; - - var instance = DoneEventPayload.FromJson(jsonData); - var json = instance.ToJson(); - - // Verify it's valid JSON by parsing it - var parsed = System.Text.Json.JsonDocument.Parse(json); - Assert.NotNull(parsed); - } - - [Fact] - public void ToYamlProducesValidYaml() - { - string yamlData = """ -response: The weather in Paris is 72°F and sunny. - -"""; - - var instance = DoneEventPayload.FromYaml(yamlData); - var yaml = instance.ToYaml(); - - // Verify it's valid YAML by parsing it - var deserializer = new YamlDotNet.Serialization.DeserializerBuilder().Build(); - var parsed = deserializer.Deserialize(yaml); - Assert.NotNull(parsed); - } } diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/ErrorEventPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/ErrorEventPayloadConversionTests.cs index d3cc78e2..4ff13000 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/ErrorEventPayloadConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/ErrorEventPayloadConversionTests.cs @@ -12,6 +12,8 @@ public void LoadYamlInput() { string yamlData = """ message: Rate limit exceeded +errorKind: rate_limit +phase: llm """; @@ -19,6 +21,8 @@ public void LoadYamlInput() Assert.NotNull(instance); Assert.Equal("Rate limit exceeded", instance.Message); + Assert.Equal("rate_limit", instance.ErrorKind); + Assert.Equal("llm", instance.Phase); } [Fact] @@ -26,13 +30,17 @@ public void LoadJsonInput() { string jsonData = """ { - "message": "Rate limit exceeded" + "message": "Rate limit exceeded", + "errorKind": "rate_limit", + "phase": "llm" } """; var instance = ErrorEventPayload.FromJson(jsonData); Assert.NotNull(instance); Assert.Equal("Rate limit exceeded", instance.Message); + Assert.Equal("rate_limit", instance.ErrorKind); + Assert.Equal("llm", instance.Phase); } [Fact] @@ -41,7 +49,9 @@ public void RoundtripJson() // Test that FromJson -> ToJson -> FromJson produces equivalent data string jsonData = """ { - "message": "Rate limit exceeded" + "message": "Rate limit exceeded", + "errorKind": "rate_limit", + "phase": "llm" } """; @@ -54,6 +64,8 @@ public void RoundtripJson() var reloaded = ErrorEventPayload.FromJson(json); Assert.NotNull(reloaded); Assert.Equal("Rate limit exceeded", reloaded.Message); + Assert.Equal("rate_limit", reloaded.ErrorKind); + Assert.Equal("llm", reloaded.Phase); } [Fact] @@ -62,6 +74,8 @@ public void RoundtripYaml() // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data string yamlData = """ message: Rate limit exceeded +errorKind: rate_limit +phase: llm """; @@ -74,6 +88,8 @@ public void RoundtripYaml() var reloaded = ErrorEventPayload.FromYaml(yaml); Assert.NotNull(reloaded); Assert.Equal("Rate limit exceeded", reloaded.Message); + Assert.Equal("rate_limit", reloaded.ErrorKind); + Assert.Equal("llm", reloaded.Phase); } [Fact] @@ -81,7 +97,9 @@ public void ToJsonProducesValidJson() { string jsonData = """ { - "message": "Rate limit exceeded" + "message": "Rate limit exceeded", + "errorKind": "rate_limit", + "phase": "llm" } """; @@ -98,6 +116,8 @@ public void ToYamlProducesValidYaml() { string yamlData = """ message: Rate limit exceeded +errorKind: rate_limit +phase: llm """; diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/LlmCompletePayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/LlmCompletePayloadConversionTests.cs new file mode 100644 index 00000000..c9ac152b --- /dev/null +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/LlmCompletePayloadConversionTests.cs @@ -0,0 +1,132 @@ +using Xunit; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + + +public class LlmCompletePayloadConversionTests +{ + [Fact] + public void LoadYamlInput() + { + string yamlData = """ +requestId: req_abc123 +serviceRequestId: srv_abc123 +durationMs: 820 + +"""; + + var instance = LlmCompletePayload.FromYaml(yamlData); + + Assert.NotNull(instance); + Assert.Equal("req_abc123", instance.RequestId); + Assert.Equal("srv_abc123", instance.ServiceRequestId); + Assert.Equal(820, instance.DurationMs); + } + + [Fact] + public void LoadJsonInput() + { + string jsonData = """ +{ + "requestId": "req_abc123", + "serviceRequestId": "srv_abc123", + "durationMs": 820 +} +"""; + + var instance = LlmCompletePayload.FromJson(jsonData); + Assert.NotNull(instance); + Assert.Equal("req_abc123", instance.RequestId); + Assert.Equal("srv_abc123", instance.ServiceRequestId); + Assert.Equal(820, instance.DurationMs); + } + + [Fact] + public void RoundtripJson() + { + // Test that FromJson -> ToJson -> FromJson produces equivalent data + string jsonData = """ +{ + "requestId": "req_abc123", + "serviceRequestId": "srv_abc123", + "durationMs": 820 +} +"""; + + var original = LlmCompletePayload.FromJson(jsonData); + Assert.NotNull(original); + + var json = original.ToJson(); + Assert.False(string.IsNullOrEmpty(json)); + + var reloaded = LlmCompletePayload.FromJson(json); + Assert.NotNull(reloaded); + Assert.Equal("req_abc123", reloaded.RequestId); + Assert.Equal("srv_abc123", reloaded.ServiceRequestId); + Assert.Equal(820, reloaded.DurationMs); + } + + [Fact] + public void RoundtripYaml() + { + // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data + string yamlData = """ +requestId: req_abc123 +serviceRequestId: srv_abc123 +durationMs: 820 + +"""; + + var original = LlmCompletePayload.FromYaml(yamlData); + Assert.NotNull(original); + + var yaml = original.ToYaml(); + Assert.False(string.IsNullOrEmpty(yaml)); + + var reloaded = LlmCompletePayload.FromYaml(yaml); + Assert.NotNull(reloaded); + Assert.Equal("req_abc123", reloaded.RequestId); + Assert.Equal("srv_abc123", reloaded.ServiceRequestId); + Assert.Equal(820, reloaded.DurationMs); + } + + [Fact] + public void ToJsonProducesValidJson() + { + string jsonData = """ +{ + "requestId": "req_abc123", + "serviceRequestId": "srv_abc123", + "durationMs": 820 +} +"""; + + var instance = LlmCompletePayload.FromJson(jsonData); + var json = instance.ToJson(); + + // Verify it's valid JSON by parsing it + var parsed = System.Text.Json.JsonDocument.Parse(json); + Assert.NotNull(parsed); + } + + [Fact] + public void ToYamlProducesValidYaml() + { + string yamlData = """ +requestId: req_abc123 +serviceRequestId: srv_abc123 +durationMs: 820 + +"""; + + var instance = LlmCompletePayload.FromYaml(yamlData); + var yaml = instance.ToYaml(); + + // Verify it's valid YAML by parsing it + var deserializer = new YamlDotNet.Serialization.DeserializerBuilder().Build(); + var parsed = deserializer.Deserialize(yaml); + Assert.NotNull(parsed); + } +} diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/LlmStartPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/LlmStartPayloadConversionTests.cs new file mode 100644 index 00000000..822ca842 --- /dev/null +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/LlmStartPayloadConversionTests.cs @@ -0,0 +1,142 @@ +using Xunit; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + + +public class LlmStartPayloadConversionTests +{ + [Fact] + public void LoadYamlInput() + { + string yamlData = """ +provider: openai +modelId: gpt-4o-mini +messageCount: 4 +attempt: 0 + +"""; + + var instance = LlmStartPayload.FromYaml(yamlData); + + Assert.NotNull(instance); + Assert.Equal("openai", instance.Provider); + Assert.Equal("gpt-4o-mini", instance.ModelId); + Assert.Equal(4, instance.MessageCount); + Assert.Equal(0, instance.Attempt); + } + + [Fact] + public void LoadJsonInput() + { + string jsonData = """ +{ + "provider": "openai", + "modelId": "gpt-4o-mini", + "messageCount": 4, + "attempt": 0 +} +"""; + + var instance = LlmStartPayload.FromJson(jsonData); + Assert.NotNull(instance); + Assert.Equal("openai", instance.Provider); + Assert.Equal("gpt-4o-mini", instance.ModelId); + Assert.Equal(4, instance.MessageCount); + Assert.Equal(0, instance.Attempt); + } + + [Fact] + public void RoundtripJson() + { + // Test that FromJson -> ToJson -> FromJson produces equivalent data + string jsonData = """ +{ + "provider": "openai", + "modelId": "gpt-4o-mini", + "messageCount": 4, + "attempt": 0 +} +"""; + + var original = LlmStartPayload.FromJson(jsonData); + Assert.NotNull(original); + + var json = original.ToJson(); + Assert.False(string.IsNullOrEmpty(json)); + + var reloaded = LlmStartPayload.FromJson(json); + Assert.NotNull(reloaded); + Assert.Equal("openai", reloaded.Provider); + Assert.Equal("gpt-4o-mini", reloaded.ModelId); + Assert.Equal(4, reloaded.MessageCount); + Assert.Equal(0, reloaded.Attempt); + } + + [Fact] + public void RoundtripYaml() + { + // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data + string yamlData = """ +provider: openai +modelId: gpt-4o-mini +messageCount: 4 +attempt: 0 + +"""; + + var original = LlmStartPayload.FromYaml(yamlData); + Assert.NotNull(original); + + var yaml = original.ToYaml(); + Assert.False(string.IsNullOrEmpty(yaml)); + + var reloaded = LlmStartPayload.FromYaml(yaml); + Assert.NotNull(reloaded); + Assert.Equal("openai", reloaded.Provider); + Assert.Equal("gpt-4o-mini", reloaded.ModelId); + Assert.Equal(4, reloaded.MessageCount); + Assert.Equal(0, reloaded.Attempt); + } + + [Fact] + public void ToJsonProducesValidJson() + { + string jsonData = """ +{ + "provider": "openai", + "modelId": "gpt-4o-mini", + "messageCount": 4, + "attempt": 0 +} +"""; + + var instance = LlmStartPayload.FromJson(jsonData); + var json = instance.ToJson(); + + // Verify it's valid JSON by parsing it + var parsed = System.Text.Json.JsonDocument.Parse(json); + Assert.NotNull(parsed); + } + + [Fact] + public void ToYamlProducesValidYaml() + { + string yamlData = """ +provider: openai +modelId: gpt-4o-mini +messageCount: 4 +attempt: 0 + +"""; + + var instance = LlmStartPayload.FromYaml(yamlData); + var yaml = instance.ToYaml(); + + // Verify it's valid YAML by parsing it + var deserializer = new YamlDotNet.Serialization.DeserializerBuilder().Build(); + var parsed = deserializer.Deserialize(yaml); + Assert.NotNull(parsed); + } +} diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/MessagesUpdatedPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/MessagesUpdatedPayloadConversionTests.cs index 8a059d2c..5bd6b3f7 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/MessagesUpdatedPayloadConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/MessagesUpdatedPayloadConversionTests.cs @@ -7,4 +7,116 @@ namespace Prompty.Core; public class MessagesUpdatedPayloadConversionTests { + [Fact] + public void LoadYamlInput() + { + string yamlData = """ +reason: tool_results +removed: 2 + +"""; + + var instance = MessagesUpdatedPayload.FromYaml(yamlData); + + Assert.NotNull(instance); + Assert.Equal("tool_results", instance.Reason); + Assert.Equal(2, instance.Removed); + } + + [Fact] + public void LoadJsonInput() + { + string jsonData = """ +{ + "reason": "tool_results", + "removed": 2 +} +"""; + + var instance = MessagesUpdatedPayload.FromJson(jsonData); + Assert.NotNull(instance); + Assert.Equal("tool_results", instance.Reason); + Assert.Equal(2, instance.Removed); + } + + [Fact] + public void RoundtripJson() + { + // Test that FromJson -> ToJson -> FromJson produces equivalent data + string jsonData = """ +{ + "reason": "tool_results", + "removed": 2 +} +"""; + + var original = MessagesUpdatedPayload.FromJson(jsonData); + Assert.NotNull(original); + + var json = original.ToJson(); + Assert.False(string.IsNullOrEmpty(json)); + + var reloaded = MessagesUpdatedPayload.FromJson(json); + Assert.NotNull(reloaded); + Assert.Equal("tool_results", reloaded.Reason); + Assert.Equal(2, reloaded.Removed); + } + + [Fact] + public void RoundtripYaml() + { + // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data + string yamlData = """ +reason: tool_results +removed: 2 + +"""; + + var original = MessagesUpdatedPayload.FromYaml(yamlData); + Assert.NotNull(original); + + var yaml = original.ToYaml(); + Assert.False(string.IsNullOrEmpty(yaml)); + + var reloaded = MessagesUpdatedPayload.FromYaml(yaml); + Assert.NotNull(reloaded); + Assert.Equal("tool_results", reloaded.Reason); + Assert.Equal(2, reloaded.Removed); + } + + [Fact] + public void ToJsonProducesValidJson() + { + string jsonData = """ +{ + "reason": "tool_results", + "removed": 2 +} +"""; + + var instance = MessagesUpdatedPayload.FromJson(jsonData); + var json = instance.ToJson(); + + // Verify it's valid JSON by parsing it + var parsed = System.Text.Json.JsonDocument.Parse(json); + Assert.NotNull(parsed); + } + + [Fact] + public void ToYamlProducesValidYaml() + { + string yamlData = """ +reason: tool_results +removed: 2 + +"""; + + var instance = MessagesUpdatedPayload.FromYaml(yamlData); + var yaml = instance.ToYaml(); + + // Verify it's valid YAML by parsing it + var deserializer = new YamlDotNet.Serialization.DeserializerBuilder().Build(); + var parsed = deserializer.Deserialize(yaml); + Assert.NotNull(parsed); + } } diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/PermissionCompletedPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/PermissionCompletedPayloadConversionTests.cs new file mode 100644 index 00000000..e64a1470 --- /dev/null +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/PermissionCompletedPayloadConversionTests.cs @@ -0,0 +1,132 @@ +using Xunit; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + + +public class PermissionCompletedPayloadConversionTests +{ + [Fact] + public void LoadYamlInput() + { + string yamlData = """ +permission: tool.execute +approved: true +reason: user_approved + +"""; + + var instance = PermissionCompletedPayload.FromYaml(yamlData); + + Assert.NotNull(instance); + Assert.Equal("tool.execute", instance.Permission); + Assert.True(instance.Approved); + Assert.Equal("user_approved", instance.Reason); + } + + [Fact] + public void LoadJsonInput() + { + string jsonData = """ +{ + "permission": "tool.execute", + "approved": true, + "reason": "user_approved" +} +"""; + + var instance = PermissionCompletedPayload.FromJson(jsonData); + Assert.NotNull(instance); + Assert.Equal("tool.execute", instance.Permission); + Assert.True(instance.Approved); + Assert.Equal("user_approved", instance.Reason); + } + + [Fact] + public void RoundtripJson() + { + // Test that FromJson -> ToJson -> FromJson produces equivalent data + string jsonData = """ +{ + "permission": "tool.execute", + "approved": true, + "reason": "user_approved" +} +"""; + + var original = PermissionCompletedPayload.FromJson(jsonData); + Assert.NotNull(original); + + var json = original.ToJson(); + Assert.False(string.IsNullOrEmpty(json)); + + var reloaded = PermissionCompletedPayload.FromJson(json); + Assert.NotNull(reloaded); + Assert.Equal("tool.execute", reloaded.Permission); + Assert.True(reloaded.Approved); + Assert.Equal("user_approved", reloaded.Reason); + } + + [Fact] + public void RoundtripYaml() + { + // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data + string yamlData = """ +permission: tool.execute +approved: true +reason: user_approved + +"""; + + var original = PermissionCompletedPayload.FromYaml(yamlData); + Assert.NotNull(original); + + var yaml = original.ToYaml(); + Assert.False(string.IsNullOrEmpty(yaml)); + + var reloaded = PermissionCompletedPayload.FromYaml(yaml); + Assert.NotNull(reloaded); + Assert.Equal("tool.execute", reloaded.Permission); + Assert.True(reloaded.Approved); + Assert.Equal("user_approved", reloaded.Reason); + } + + [Fact] + public void ToJsonProducesValidJson() + { + string jsonData = """ +{ + "permission": "tool.execute", + "approved": true, + "reason": "user_approved" +} +"""; + + var instance = PermissionCompletedPayload.FromJson(jsonData); + var json = instance.ToJson(); + + // Verify it's valid JSON by parsing it + var parsed = System.Text.Json.JsonDocument.Parse(json); + Assert.NotNull(parsed); + } + + [Fact] + public void ToYamlProducesValidYaml() + { + string yamlData = """ +permission: tool.execute +approved: true +reason: user_approved + +"""; + + var instance = PermissionCompletedPayload.FromYaml(yamlData); + var yaml = instance.ToYaml(); + + // Verify it's valid YAML by parsing it + var deserializer = new YamlDotNet.Serialization.DeserializerBuilder().Build(); + var parsed = deserializer.Deserialize(yaml); + Assert.NotNull(parsed); + } +} diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/PermissionRequestedPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/PermissionRequestedPayloadConversionTests.cs new file mode 100644 index 00000000..cbcef536 --- /dev/null +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/PermissionRequestedPayloadConversionTests.cs @@ -0,0 +1,122 @@ +using Xunit; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + + +public class PermissionRequestedPayloadConversionTests +{ + [Fact] + public void LoadYamlInput() + { + string yamlData = """ +permission: tool.execute +target: shell + +"""; + + var instance = PermissionRequestedPayload.FromYaml(yamlData); + + Assert.NotNull(instance); + Assert.Equal("tool.execute", instance.Permission); + Assert.Equal("shell", instance.Target); + } + + [Fact] + public void LoadJsonInput() + { + string jsonData = """ +{ + "permission": "tool.execute", + "target": "shell" +} +"""; + + var instance = PermissionRequestedPayload.FromJson(jsonData); + Assert.NotNull(instance); + Assert.Equal("tool.execute", instance.Permission); + Assert.Equal("shell", instance.Target); + } + + [Fact] + public void RoundtripJson() + { + // Test that FromJson -> ToJson -> FromJson produces equivalent data + string jsonData = """ +{ + "permission": "tool.execute", + "target": "shell" +} +"""; + + var original = PermissionRequestedPayload.FromJson(jsonData); + Assert.NotNull(original); + + var json = original.ToJson(); + Assert.False(string.IsNullOrEmpty(json)); + + var reloaded = PermissionRequestedPayload.FromJson(json); + Assert.NotNull(reloaded); + Assert.Equal("tool.execute", reloaded.Permission); + Assert.Equal("shell", reloaded.Target); + } + + [Fact] + public void RoundtripYaml() + { + // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data + string yamlData = """ +permission: tool.execute +target: shell + +"""; + + var original = PermissionRequestedPayload.FromYaml(yamlData); + Assert.NotNull(original); + + var yaml = original.ToYaml(); + Assert.False(string.IsNullOrEmpty(yaml)); + + var reloaded = PermissionRequestedPayload.FromYaml(yaml); + Assert.NotNull(reloaded); + Assert.Equal("tool.execute", reloaded.Permission); + Assert.Equal("shell", reloaded.Target); + } + + [Fact] + public void ToJsonProducesValidJson() + { + string jsonData = """ +{ + "permission": "tool.execute", + "target": "shell" +} +"""; + + var instance = PermissionRequestedPayload.FromJson(jsonData); + var json = instance.ToJson(); + + // Verify it's valid JSON by parsing it + var parsed = System.Text.Json.JsonDocument.Parse(json); + Assert.NotNull(parsed); + } + + [Fact] + public void ToYamlProducesValidYaml() + { + string yamlData = """ +permission: tool.execute +target: shell + +"""; + + var instance = PermissionRequestedPayload.FromYaml(yamlData); + var yaml = instance.ToYaml(); + + // Verify it's valid YAML by parsing it + var deserializer = new YamlDotNet.Serialization.DeserializerBuilder().Build(); + var parsed = deserializer.Deserialize(yaml); + Assert.NotNull(parsed); + } +} diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/RetryPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/RetryPayloadConversionTests.cs new file mode 100644 index 00000000..0e5cb1d4 --- /dev/null +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/RetryPayloadConversionTests.cs @@ -0,0 +1,152 @@ +using Xunit; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + + +public class RetryPayloadConversionTests +{ + [Fact] + public void LoadYamlInput() + { + string yamlData = """ +operation: llm +attempt: 2 +maxAttempts: 3 +delayMs: 1250 +reason: rate_limit + +"""; + + var instance = RetryPayload.FromYaml(yamlData); + + Assert.NotNull(instance); + Assert.Equal("llm", instance.Operation); + Assert.Equal(2, instance.Attempt); + Assert.Equal(3, instance.MaxAttempts); + Assert.Equal(1250, instance.DelayMs); + Assert.Equal("rate_limit", instance.Reason); + } + + [Fact] + public void LoadJsonInput() + { + string jsonData = """ +{ + "operation": "llm", + "attempt": 2, + "maxAttempts": 3, + "delayMs": 1250, + "reason": "rate_limit" +} +"""; + + var instance = RetryPayload.FromJson(jsonData); + Assert.NotNull(instance); + Assert.Equal("llm", instance.Operation); + Assert.Equal(2, instance.Attempt); + Assert.Equal(3, instance.MaxAttempts); + Assert.Equal(1250, instance.DelayMs); + Assert.Equal("rate_limit", instance.Reason); + } + + [Fact] + public void RoundtripJson() + { + // Test that FromJson -> ToJson -> FromJson produces equivalent data + string jsonData = """ +{ + "operation": "llm", + "attempt": 2, + "maxAttempts": 3, + "delayMs": 1250, + "reason": "rate_limit" +} +"""; + + var original = RetryPayload.FromJson(jsonData); + Assert.NotNull(original); + + var json = original.ToJson(); + Assert.False(string.IsNullOrEmpty(json)); + + var reloaded = RetryPayload.FromJson(json); + Assert.NotNull(reloaded); + Assert.Equal("llm", reloaded.Operation); + Assert.Equal(2, reloaded.Attempt); + Assert.Equal(3, reloaded.MaxAttempts); + Assert.Equal(1250, reloaded.DelayMs); + Assert.Equal("rate_limit", reloaded.Reason); + } + + [Fact] + public void RoundtripYaml() + { + // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data + string yamlData = """ +operation: llm +attempt: 2 +maxAttempts: 3 +delayMs: 1250 +reason: rate_limit + +"""; + + var original = RetryPayload.FromYaml(yamlData); + Assert.NotNull(original); + + var yaml = original.ToYaml(); + Assert.False(string.IsNullOrEmpty(yaml)); + + var reloaded = RetryPayload.FromYaml(yaml); + Assert.NotNull(reloaded); + Assert.Equal("llm", reloaded.Operation); + Assert.Equal(2, reloaded.Attempt); + Assert.Equal(3, reloaded.MaxAttempts); + Assert.Equal(1250, reloaded.DelayMs); + Assert.Equal("rate_limit", reloaded.Reason); + } + + [Fact] + public void ToJsonProducesValidJson() + { + string jsonData = """ +{ + "operation": "llm", + "attempt": 2, + "maxAttempts": 3, + "delayMs": 1250, + "reason": "rate_limit" +} +"""; + + var instance = RetryPayload.FromJson(jsonData); + var json = instance.ToJson(); + + // Verify it's valid JSON by parsing it + var parsed = System.Text.Json.JsonDocument.Parse(json); + Assert.NotNull(parsed); + } + + [Fact] + public void ToYamlProducesValidYaml() + { + string yamlData = """ +operation: llm +attempt: 2 +maxAttempts: 3 +delayMs: 1250 +reason: rate_limit + +"""; + + var instance = RetryPayload.FromYaml(yamlData); + var yaml = instance.ToYaml(); + + // Verify it's valid YAML by parsing it + var deserializer = new YamlDotNet.Serialization.DeserializerBuilder().Build(); + var parsed = deserializer.Deserialize(yaml); + Assert.NotNull(parsed); + } +} diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/ToolCallCompletePayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/ToolCallCompletePayloadConversionTests.cs new file mode 100644 index 00000000..b3641edd --- /dev/null +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/ToolCallCompletePayloadConversionTests.cs @@ -0,0 +1,152 @@ +using Xunit; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + + +public class ToolCallCompletePayloadConversionTests +{ + [Fact] + public void LoadYamlInput() + { + string yamlData = """ +id: call_abc123 +name: get_weather +success: true +durationMs: 42 +errorKind: timeout + +"""; + + var instance = ToolCallCompletePayload.FromYaml(yamlData); + + Assert.NotNull(instance); + Assert.Equal("call_abc123", instance.Id); + Assert.Equal("get_weather", instance.Name); + Assert.True(instance.Success); + Assert.Equal(42, instance.DurationMs); + Assert.Equal("timeout", instance.ErrorKind); + } + + [Fact] + public void LoadJsonInput() + { + string jsonData = """ +{ + "id": "call_abc123", + "name": "get_weather", + "success": true, + "durationMs": 42, + "errorKind": "timeout" +} +"""; + + var instance = ToolCallCompletePayload.FromJson(jsonData); + Assert.NotNull(instance); + Assert.Equal("call_abc123", instance.Id); + Assert.Equal("get_weather", instance.Name); + Assert.True(instance.Success); + Assert.Equal(42, instance.DurationMs); + Assert.Equal("timeout", instance.ErrorKind); + } + + [Fact] + public void RoundtripJson() + { + // Test that FromJson -> ToJson -> FromJson produces equivalent data + string jsonData = """ +{ + "id": "call_abc123", + "name": "get_weather", + "success": true, + "durationMs": 42, + "errorKind": "timeout" +} +"""; + + var original = ToolCallCompletePayload.FromJson(jsonData); + Assert.NotNull(original); + + var json = original.ToJson(); + Assert.False(string.IsNullOrEmpty(json)); + + var reloaded = ToolCallCompletePayload.FromJson(json); + Assert.NotNull(reloaded); + Assert.Equal("call_abc123", reloaded.Id); + Assert.Equal("get_weather", reloaded.Name); + Assert.True(reloaded.Success); + Assert.Equal(42, reloaded.DurationMs); + Assert.Equal("timeout", reloaded.ErrorKind); + } + + [Fact] + public void RoundtripYaml() + { + // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data + string yamlData = """ +id: call_abc123 +name: get_weather +success: true +durationMs: 42 +errorKind: timeout + +"""; + + var original = ToolCallCompletePayload.FromYaml(yamlData); + Assert.NotNull(original); + + var yaml = original.ToYaml(); + Assert.False(string.IsNullOrEmpty(yaml)); + + var reloaded = ToolCallCompletePayload.FromYaml(yaml); + Assert.NotNull(reloaded); + Assert.Equal("call_abc123", reloaded.Id); + Assert.Equal("get_weather", reloaded.Name); + Assert.True(reloaded.Success); + Assert.Equal(42, reloaded.DurationMs); + Assert.Equal("timeout", reloaded.ErrorKind); + } + + [Fact] + public void ToJsonProducesValidJson() + { + string jsonData = """ +{ + "id": "call_abc123", + "name": "get_weather", + "success": true, + "durationMs": 42, + "errorKind": "timeout" +} +"""; + + var instance = ToolCallCompletePayload.FromJson(jsonData); + var json = instance.ToJson(); + + // Verify it's valid JSON by parsing it + var parsed = System.Text.Json.JsonDocument.Parse(json); + Assert.NotNull(parsed); + } + + [Fact] + public void ToYamlProducesValidYaml() + { + string yamlData = """ +id: call_abc123 +name: get_weather +success: true +durationMs: 42 +errorKind: timeout + +"""; + + var instance = ToolCallCompletePayload.FromYaml(yamlData); + var yaml = instance.ToYaml(); + + // Verify it's valid YAML by parsing it + var deserializer = new YamlDotNet.Serialization.DeserializerBuilder().Build(); + var parsed = deserializer.Deserialize(yaml); + Assert.NotNull(parsed); + } +} diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/ToolCallStartPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/ToolCallStartPayloadConversionTests.cs index 7c907643..f4db36e4 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/ToolCallStartPayloadConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/ToolCallStartPayloadConversionTests.cs @@ -11,6 +11,7 @@ public class ToolCallStartPayloadConversionTests public void LoadYamlInput() { string yamlData = """ +id: call_abc123 name: get_weather arguments: "{\"city\": \"Paris\"}" @@ -19,6 +20,7 @@ public void LoadYamlInput() var instance = ToolCallStartPayload.FromYaml(yamlData); Assert.NotNull(instance); + Assert.Equal("call_abc123", instance.Id); Assert.Equal("get_weather", instance.Name); Assert.Equal(@"{""city"": ""Paris""}".Replace("\r\n", "\n"), instance.Arguments); } @@ -28,6 +30,7 @@ public void LoadJsonInput() { string jsonData = """ { + "id": "call_abc123", "name": "get_weather", "arguments": "{\"city\": \"Paris\"}" } @@ -35,6 +38,7 @@ public void LoadJsonInput() var instance = ToolCallStartPayload.FromJson(jsonData); Assert.NotNull(instance); + Assert.Equal("call_abc123", instance.Id); Assert.Equal("get_weather", instance.Name); Assert.Equal(@"{""city"": ""Paris""}".Replace("\r\n", "\n"), instance.Arguments); } @@ -45,6 +49,7 @@ public void RoundtripJson() // Test that FromJson -> ToJson -> FromJson produces equivalent data string jsonData = """ { + "id": "call_abc123", "name": "get_weather", "arguments": "{\"city\": \"Paris\"}" } @@ -58,6 +63,7 @@ public void RoundtripJson() var reloaded = ToolCallStartPayload.FromJson(json); Assert.NotNull(reloaded); + Assert.Equal("call_abc123", reloaded.Id); Assert.Equal("get_weather", reloaded.Name); Assert.Equal(@"{""city"": ""Paris""}".Replace("\r\n", "\n"), reloaded.Arguments); } @@ -67,6 +73,7 @@ public void RoundtripYaml() { // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data string yamlData = """ +id: call_abc123 name: get_weather arguments: "{\"city\": \"Paris\"}" @@ -80,6 +87,7 @@ public void RoundtripYaml() var reloaded = ToolCallStartPayload.FromYaml(yaml); Assert.NotNull(reloaded); + Assert.Equal("call_abc123", reloaded.Id); Assert.Equal("get_weather", reloaded.Name); Assert.Equal(@"{""city"": ""Paris""}".Replace("\r\n", "\n"), reloaded.Arguments); } @@ -89,6 +97,7 @@ public void ToJsonProducesValidJson() { string jsonData = """ { + "id": "call_abc123", "name": "get_weather", "arguments": "{\"city\": \"Paris\"}" } @@ -106,6 +115,7 @@ public void ToJsonProducesValidJson() public void ToYamlProducesValidYaml() { string yamlData = """ +id: call_abc123 name: get_weather arguments: "{\"city\": \"Paris\"}" diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/TurnEndPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/TurnEndPayloadConversionTests.cs new file mode 100644 index 00000000..133b98e9 --- /dev/null +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/TurnEndPayloadConversionTests.cs @@ -0,0 +1,122 @@ +using Xunit; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + + +public class TurnEndPayloadConversionTests +{ + [Fact] + public void LoadYamlInput() + { + string yamlData = """ +iterations: 2 +durationMs: 1500 + +"""; + + var instance = TurnEndPayload.FromYaml(yamlData); + + Assert.NotNull(instance); + Assert.Equal(2, instance.Iterations); + Assert.Equal(1500, instance.DurationMs); + } + + [Fact] + public void LoadJsonInput() + { + string jsonData = """ +{ + "iterations": 2, + "durationMs": 1500 +} +"""; + + var instance = TurnEndPayload.FromJson(jsonData); + Assert.NotNull(instance); + Assert.Equal(2, instance.Iterations); + Assert.Equal(1500, instance.DurationMs); + } + + [Fact] + public void RoundtripJson() + { + // Test that FromJson -> ToJson -> FromJson produces equivalent data + string jsonData = """ +{ + "iterations": 2, + "durationMs": 1500 +} +"""; + + var original = TurnEndPayload.FromJson(jsonData); + Assert.NotNull(original); + + var json = original.ToJson(); + Assert.False(string.IsNullOrEmpty(json)); + + var reloaded = TurnEndPayload.FromJson(json); + Assert.NotNull(reloaded); + Assert.Equal(2, reloaded.Iterations); + Assert.Equal(1500, reloaded.DurationMs); + } + + [Fact] + public void RoundtripYaml() + { + // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data + string yamlData = """ +iterations: 2 +durationMs: 1500 + +"""; + + var original = TurnEndPayload.FromYaml(yamlData); + Assert.NotNull(original); + + var yaml = original.ToYaml(); + Assert.False(string.IsNullOrEmpty(yaml)); + + var reloaded = TurnEndPayload.FromYaml(yaml); + Assert.NotNull(reloaded); + Assert.Equal(2, reloaded.Iterations); + Assert.Equal(1500, reloaded.DurationMs); + } + + [Fact] + public void ToJsonProducesValidJson() + { + string jsonData = """ +{ + "iterations": 2, + "durationMs": 1500 +} +"""; + + var instance = TurnEndPayload.FromJson(jsonData); + var json = instance.ToJson(); + + // Verify it's valid JSON by parsing it + var parsed = System.Text.Json.JsonDocument.Parse(json); + Assert.NotNull(parsed); + } + + [Fact] + public void ToYamlProducesValidYaml() + { + string yamlData = """ +iterations: 2 +durationMs: 1500 + +"""; + + var instance = TurnEndPayload.FromYaml(yamlData); + var yaml = instance.ToYaml(); + + // Verify it's valid YAML by parsing it + var deserializer = new YamlDotNet.Serialization.DeserializerBuilder().Build(); + var parsed = deserializer.Deserialize(yaml); + Assert.NotNull(parsed); + } +} diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/TurnEventConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/TurnEventConversionTests.cs new file mode 100644 index 00000000..fe82defc --- /dev/null +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/TurnEventConversionTests.cs @@ -0,0 +1,162 @@ +using Xunit; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + + +public class TurnEventConversionTests +{ + [Fact] + public void LoadYamlInput() + { + string yamlData = """ +id: evt_abc123 +timestamp: "2026-06-09T20:00:00Z" +turnId: turn_001 +iteration: 0 +parentId: evt_parent +spanId: span_tool_001 + +"""; + + var instance = TurnEvent.FromYaml(yamlData); + + Assert.NotNull(instance); + Assert.Equal("evt_abc123", instance.Id); + Assert.Equal("2026-06-09T20:00:00Z", instance.Timestamp); + Assert.Equal("turn_001", instance.TurnId); + Assert.Equal(0, instance.Iteration); + Assert.Equal("evt_parent", instance.ParentId); + Assert.Equal("span_tool_001", instance.SpanId); + } + + [Fact] + public void LoadJsonInput() + { + string jsonData = """ +{ + "id": "evt_abc123", + "timestamp": "2026-06-09T20:00:00Z", + "turnId": "turn_001", + "iteration": 0, + "parentId": "evt_parent", + "spanId": "span_tool_001" +} +"""; + + var instance = TurnEvent.FromJson(jsonData); + Assert.NotNull(instance); + Assert.Equal("evt_abc123", instance.Id); + Assert.Equal("2026-06-09T20:00:00Z", instance.Timestamp); + Assert.Equal("turn_001", instance.TurnId); + Assert.Equal(0, instance.Iteration); + Assert.Equal("evt_parent", instance.ParentId); + Assert.Equal("span_tool_001", instance.SpanId); + } + + [Fact] + public void RoundtripJson() + { + // Test that FromJson -> ToJson -> FromJson produces equivalent data + string jsonData = """ +{ + "id": "evt_abc123", + "timestamp": "2026-06-09T20:00:00Z", + "turnId": "turn_001", + "iteration": 0, + "parentId": "evt_parent", + "spanId": "span_tool_001" +} +"""; + + var original = TurnEvent.FromJson(jsonData); + Assert.NotNull(original); + + var json = original.ToJson(); + Assert.False(string.IsNullOrEmpty(json)); + + var reloaded = TurnEvent.FromJson(json); + Assert.NotNull(reloaded); + Assert.Equal("evt_abc123", reloaded.Id); + Assert.Equal("2026-06-09T20:00:00Z", reloaded.Timestamp); + Assert.Equal("turn_001", reloaded.TurnId); + Assert.Equal(0, reloaded.Iteration); + Assert.Equal("evt_parent", reloaded.ParentId); + Assert.Equal("span_tool_001", reloaded.SpanId); + } + + [Fact] + public void RoundtripYaml() + { + // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data + string yamlData = """ +id: evt_abc123 +timestamp: "2026-06-09T20:00:00Z" +turnId: turn_001 +iteration: 0 +parentId: evt_parent +spanId: span_tool_001 + +"""; + + var original = TurnEvent.FromYaml(yamlData); + Assert.NotNull(original); + + var yaml = original.ToYaml(); + Assert.False(string.IsNullOrEmpty(yaml)); + + var reloaded = TurnEvent.FromYaml(yaml); + Assert.NotNull(reloaded); + Assert.Equal("evt_abc123", reloaded.Id); + Assert.Equal("2026-06-09T20:00:00Z", reloaded.Timestamp); + Assert.Equal("turn_001", reloaded.TurnId); + Assert.Equal(0, reloaded.Iteration); + Assert.Equal("evt_parent", reloaded.ParentId); + Assert.Equal("span_tool_001", reloaded.SpanId); + } + + [Fact] + public void ToJsonProducesValidJson() + { + string jsonData = """ +{ + "id": "evt_abc123", + "timestamp": "2026-06-09T20:00:00Z", + "turnId": "turn_001", + "iteration": 0, + "parentId": "evt_parent", + "spanId": "span_tool_001" +} +"""; + + var instance = TurnEvent.FromJson(jsonData); + var json = instance.ToJson(); + + // Verify it's valid JSON by parsing it + var parsed = System.Text.Json.JsonDocument.Parse(json); + Assert.NotNull(parsed); + } + + [Fact] + public void ToYamlProducesValidYaml() + { + string yamlData = """ +id: evt_abc123 +timestamp: "2026-06-09T20:00:00Z" +turnId: turn_001 +iteration: 0 +parentId: evt_parent +spanId: span_tool_001 + +"""; + + var instance = TurnEvent.FromYaml(yamlData); + var yaml = instance.ToYaml(); + + // Verify it's valid YAML by parsing it + var deserializer = new YamlDotNet.Serialization.DeserializerBuilder().Build(); + var parsed = deserializer.Deserialize(yaml); + Assert.NotNull(parsed); + } +} diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/TurnStartPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/TurnStartPayloadConversionTests.cs new file mode 100644 index 00000000..57a7bcff --- /dev/null +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/TurnStartPayloadConversionTests.cs @@ -0,0 +1,122 @@ +using Xunit; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + + +public class TurnStartPayloadConversionTests +{ + [Fact] + public void LoadYamlInput() + { + string yamlData = """ +agent: weather-agent +maxIterations: 10 + +"""; + + var instance = TurnStartPayload.FromYaml(yamlData); + + Assert.NotNull(instance); + Assert.Equal("weather-agent", instance.Agent); + Assert.Equal(10, instance.MaxIterations); + } + + [Fact] + public void LoadJsonInput() + { + string jsonData = """ +{ + "agent": "weather-agent", + "maxIterations": 10 +} +"""; + + var instance = TurnStartPayload.FromJson(jsonData); + Assert.NotNull(instance); + Assert.Equal("weather-agent", instance.Agent); + Assert.Equal(10, instance.MaxIterations); + } + + [Fact] + public void RoundtripJson() + { + // Test that FromJson -> ToJson -> FromJson produces equivalent data + string jsonData = """ +{ + "agent": "weather-agent", + "maxIterations": 10 +} +"""; + + var original = TurnStartPayload.FromJson(jsonData); + Assert.NotNull(original); + + var json = original.ToJson(); + Assert.False(string.IsNullOrEmpty(json)); + + var reloaded = TurnStartPayload.FromJson(json); + Assert.NotNull(reloaded); + Assert.Equal("weather-agent", reloaded.Agent); + Assert.Equal(10, reloaded.MaxIterations); + } + + [Fact] + public void RoundtripYaml() + { + // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data + string yamlData = """ +agent: weather-agent +maxIterations: 10 + +"""; + + var original = TurnStartPayload.FromYaml(yamlData); + Assert.NotNull(original); + + var yaml = original.ToYaml(); + Assert.False(string.IsNullOrEmpty(yaml)); + + var reloaded = TurnStartPayload.FromYaml(yaml); + Assert.NotNull(reloaded); + Assert.Equal("weather-agent", reloaded.Agent); + Assert.Equal(10, reloaded.MaxIterations); + } + + [Fact] + public void ToJsonProducesValidJson() + { + string jsonData = """ +{ + "agent": "weather-agent", + "maxIterations": 10 +} +"""; + + var instance = TurnStartPayload.FromJson(jsonData); + var json = instance.ToJson(); + + // Verify it's valid JSON by parsing it + var parsed = System.Text.Json.JsonDocument.Parse(json); + Assert.NotNull(parsed); + } + + [Fact] + public void ToYamlProducesValidYaml() + { + string yamlData = """ +agent: weather-agent +maxIterations: 10 + +"""; + + var instance = TurnStartPayload.FromYaml(yamlData); + var yaml = instance.ToYaml(); + + // Verify it's valid YAML by parsing it + var deserializer = new YamlDotNet.Serialization.DeserializerBuilder().Build(); + var parsed = deserializer.Deserialize(yaml); + Assert.NotNull(parsed); + } +} diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/TurnSummaryConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/TurnSummaryConversionTests.cs new file mode 100644 index 00000000..148d264d --- /dev/null +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/TurnSummaryConversionTests.cs @@ -0,0 +1,172 @@ +using Xunit; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + + +public class TurnSummaryConversionTests +{ + [Fact] + public void LoadYamlInput() + { + string yamlData = """ +turnId: turn_001 +status: success +iterations: 2 +llmCalls: 3 +toolCalls: 2 +retries: 1 +durationMs: 2500 + +"""; + + var instance = TurnSummary.FromYaml(yamlData); + + Assert.NotNull(instance); + Assert.Equal("turn_001", instance.TurnId); + Assert.Equal("success", instance.Status); + Assert.Equal(2, instance.Iterations); + Assert.Equal(3, instance.LlmCalls); + Assert.Equal(2, instance.ToolCalls); + Assert.Equal(1, instance.Retries); + Assert.Equal(2500, instance.DurationMs); + } + + [Fact] + public void LoadJsonInput() + { + string jsonData = """ +{ + "turnId": "turn_001", + "status": "success", + "iterations": 2, + "llmCalls": 3, + "toolCalls": 2, + "retries": 1, + "durationMs": 2500 +} +"""; + + var instance = TurnSummary.FromJson(jsonData); + Assert.NotNull(instance); + Assert.Equal("turn_001", instance.TurnId); + Assert.Equal("success", instance.Status); + Assert.Equal(2, instance.Iterations); + Assert.Equal(3, instance.LlmCalls); + Assert.Equal(2, instance.ToolCalls); + Assert.Equal(1, instance.Retries); + Assert.Equal(2500, instance.DurationMs); + } + + [Fact] + public void RoundtripJson() + { + // Test that FromJson -> ToJson -> FromJson produces equivalent data + string jsonData = """ +{ + "turnId": "turn_001", + "status": "success", + "iterations": 2, + "llmCalls": 3, + "toolCalls": 2, + "retries": 1, + "durationMs": 2500 +} +"""; + + var original = TurnSummary.FromJson(jsonData); + Assert.NotNull(original); + + var json = original.ToJson(); + Assert.False(string.IsNullOrEmpty(json)); + + var reloaded = TurnSummary.FromJson(json); + Assert.NotNull(reloaded); + Assert.Equal("turn_001", reloaded.TurnId); + Assert.Equal("success", reloaded.Status); + Assert.Equal(2, reloaded.Iterations); + Assert.Equal(3, reloaded.LlmCalls); + Assert.Equal(2, reloaded.ToolCalls); + Assert.Equal(1, reloaded.Retries); + Assert.Equal(2500, reloaded.DurationMs); + } + + [Fact] + public void RoundtripYaml() + { + // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data + string yamlData = """ +turnId: turn_001 +status: success +iterations: 2 +llmCalls: 3 +toolCalls: 2 +retries: 1 +durationMs: 2500 + +"""; + + var original = TurnSummary.FromYaml(yamlData); + Assert.NotNull(original); + + var yaml = original.ToYaml(); + Assert.False(string.IsNullOrEmpty(yaml)); + + var reloaded = TurnSummary.FromYaml(yaml); + Assert.NotNull(reloaded); + Assert.Equal("turn_001", reloaded.TurnId); + Assert.Equal("success", reloaded.Status); + Assert.Equal(2, reloaded.Iterations); + Assert.Equal(3, reloaded.LlmCalls); + Assert.Equal(2, reloaded.ToolCalls); + Assert.Equal(1, reloaded.Retries); + Assert.Equal(2500, reloaded.DurationMs); + } + + [Fact] + public void ToJsonProducesValidJson() + { + string jsonData = """ +{ + "turnId": "turn_001", + "status": "success", + "iterations": 2, + "llmCalls": 3, + "toolCalls": 2, + "retries": 1, + "durationMs": 2500 +} +"""; + + var instance = TurnSummary.FromJson(jsonData); + var json = instance.ToJson(); + + // Verify it's valid JSON by parsing it + var parsed = System.Text.Json.JsonDocument.Parse(json); + Assert.NotNull(parsed); + } + + [Fact] + public void ToYamlProducesValidYaml() + { + string yamlData = """ +turnId: turn_001 +status: success +iterations: 2 +llmCalls: 3 +toolCalls: 2 +retries: 1 +durationMs: 2500 + +"""; + + var instance = TurnSummary.FromYaml(yamlData); + var yaml = instance.ToYaml(); + + // Verify it's valid YAML by parsing it + var deserializer = new YamlDotNet.Serialization.DeserializerBuilder().Build(); + var parsed = deserializer.Deserialize(yaml); + Assert.NotNull(parsed); + } +} diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/TurnTraceConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/TurnTraceConversionTests.cs new file mode 100644 index 00000000..306c9b43 --- /dev/null +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/TurnTraceConversionTests.cs @@ -0,0 +1,132 @@ +using Xunit; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + + +public class TurnTraceConversionTests +{ + [Fact] + public void LoadYamlInput() + { + string yamlData = """ +version: "1" +runtime: typescript +promptyVersion: 2.0.0 + +"""; + + var instance = TurnTrace.FromYaml(yamlData); + + Assert.NotNull(instance); + Assert.Equal("1", instance.Version); + Assert.Equal("typescript", instance.Runtime); + Assert.Equal("2.0.0", instance.PromptyVersion); + } + + [Fact] + public void LoadJsonInput() + { + string jsonData = """ +{ + "version": "1", + "runtime": "typescript", + "promptyVersion": "2.0.0" +} +"""; + + var instance = TurnTrace.FromJson(jsonData); + Assert.NotNull(instance); + Assert.Equal("1", instance.Version); + Assert.Equal("typescript", instance.Runtime); + Assert.Equal("2.0.0", instance.PromptyVersion); + } + + [Fact] + public void RoundtripJson() + { + // Test that FromJson -> ToJson -> FromJson produces equivalent data + string jsonData = """ +{ + "version": "1", + "runtime": "typescript", + "promptyVersion": "2.0.0" +} +"""; + + var original = TurnTrace.FromJson(jsonData); + Assert.NotNull(original); + + var json = original.ToJson(); + Assert.False(string.IsNullOrEmpty(json)); + + var reloaded = TurnTrace.FromJson(json); + Assert.NotNull(reloaded); + Assert.Equal("1", reloaded.Version); + Assert.Equal("typescript", reloaded.Runtime); + Assert.Equal("2.0.0", reloaded.PromptyVersion); + } + + [Fact] + public void RoundtripYaml() + { + // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data + string yamlData = """ +version: "1" +runtime: typescript +promptyVersion: 2.0.0 + +"""; + + var original = TurnTrace.FromYaml(yamlData); + Assert.NotNull(original); + + var yaml = original.ToYaml(); + Assert.False(string.IsNullOrEmpty(yaml)); + + var reloaded = TurnTrace.FromYaml(yaml); + Assert.NotNull(reloaded); + Assert.Equal("1", reloaded.Version); + Assert.Equal("typescript", reloaded.Runtime); + Assert.Equal("2.0.0", reloaded.PromptyVersion); + } + + [Fact] + public void ToJsonProducesValidJson() + { + string jsonData = """ +{ + "version": "1", + "runtime": "typescript", + "promptyVersion": "2.0.0" +} +"""; + + var instance = TurnTrace.FromJson(jsonData); + var json = instance.ToJson(); + + // Verify it's valid JSON by parsing it + var parsed = System.Text.Json.JsonDocument.Parse(json); + Assert.NotNull(parsed); + } + + [Fact] + public void ToYamlProducesValidYaml() + { + string yamlData = """ +version: "1" +runtime: typescript +promptyVersion: 2.0.0 + +"""; + + var instance = TurnTrace.FromYaml(yamlData); + var yaml = instance.ToYaml(); + + // Verify it's valid YAML by parsing it + var deserializer = new YamlDotNet.Serialization.DeserializerBuilder().Build(); + var parsed = deserializer.Deserialize(yaml); + Assert.NotNull(parsed); + } +} diff --git a/runtime/csharp/Prompty.Core/AgentEvents.cs b/runtime/csharp/Prompty.Core/AgentEvents.cs index f2a272cd..b7172acd 100644 --- a/runtime/csharp/Prompty.Core/AgentEvents.cs +++ b/runtime/csharp/Prompty.Core/AgentEvents.cs @@ -5,9 +5,17 @@ namespace Prompty.Core; /// §13.1 Agent loop event types. public enum AgentEventType { + TurnStart, + TurnEnd, + LlmStart, + LlmComplete, + Retry, + PermissionRequested, + PermissionCompleted, Token, Thinking, ToolCallStart, + ToolCallComplete, ToolResult, Status, MessagesUpdated, @@ -34,7 +42,18 @@ public static void EmitEvent(EventCallback? callback, AgentEventType eventType, if (callback is null) return; try { - callback(eventType, data); + var eventData = new Dictionary(data) + { + ["turnEvent"] = new Dictionary + { + ["id"] = $"evt_{Guid.NewGuid():N}", + ["type"] = ToWireName(eventType), + ["timestamp"] = DateTimeOffset.UtcNow.ToString("O"), + ["iteration"] = data.TryGetValue("iteration", out var iteration) ? iteration : null, + ["payload"] = data, + }, + }; + callback(eventType, eventData); } catch (Exception ex) { @@ -42,4 +61,23 @@ public static void EmitEvent(EventCallback? callback, AgentEventType eventType, System.Diagnostics.Debug.WriteLine($"Event callback error for {eventType}: {ex.Message}"); } } + + private static string ToWireName(AgentEventType eventType) => eventType switch + { + AgentEventType.TurnStart => "turn_start", + AgentEventType.TurnEnd => "turn_end", + AgentEventType.LlmStart => "llm_start", + AgentEventType.LlmComplete => "llm_complete", + AgentEventType.Retry => "retry", + AgentEventType.PermissionRequested => "permission_requested", + AgentEventType.PermissionCompleted => "permission_completed", + AgentEventType.ToolCallStart => "tool_call_start", + AgentEventType.ToolCallComplete => "tool_call_complete", + AgentEventType.ToolResult => "tool_result", + AgentEventType.MessagesUpdated => "messages_updated", + AgentEventType.CompactionStart => "compaction_start", + AgentEventType.CompactionComplete => "compaction_complete", + AgentEventType.CompactionFailed => "compaction_failed", + _ => eventType.ToString().ToLowerInvariant(), + }; } diff --git a/runtime/csharp/Prompty.Core/Model/agent/GuardrailResult.cs b/runtime/csharp/Prompty.Core/Model/agent/GuardrailResult.cs index bd8b00c9..582e492d 100644 --- a/runtime/csharp/Prompty.Core/Model/agent/GuardrailResult.cs +++ b/runtime/csharp/Prompty.Core/Model/agent/GuardrailResult.cs @@ -8,9 +8,9 @@ namespace Prompty.Core; /// /// The result of a guardrail evaluation. Guardrails are safety checks that -/// +/// /// run at specific phases of the agent loop and can allow, deny, or rewrite -/// +/// /// content. /// public partial class GuardrailResult diff --git a/runtime/csharp/Prompty.Core/Model/agent/Prompty.cs b/runtime/csharp/Prompty.Core/Model/agent/Prompty.cs index e5e2a6d3..65a967fa 100644 --- a/runtime/csharp/Prompty.Core/Model/agent/Prompty.cs +++ b/runtime/csharp/Prompty.Core/Model/agent/Prompty.cs @@ -8,14 +8,24 @@ namespace Prompty.Core; /// /// A Prompty is a markdown file format for LLM prompts. The frontmatter defines -/// +/// /// structured metadata including model configuration, input/output schemas, tools, -/// +/// /// and template settings. The markdown body becomes the instructions. -/// +/// /// This is the single root type for the Prompty schema — there is no abstract base -/// +/// /// class or kind discriminator. A .prompty file always produces a Prompty instance. +/// +/// Runtime loaders may resolve frontmatter references such as `${env:VAR}` and +/// +/// `${file:relative/path}`. File references must be treated as a host-controlled +/// +/// capability: by default they are scoped to the containing .prompty file's +/// +/// directory tree after canonicalization, and any additional allowed roots must +/// +/// be supplied by the host application's load options rather than frontmatter. /// public partial class Prompty { diff --git a/runtime/csharp/Prompty.Core/Model/connection/Connection.cs b/runtime/csharp/Prompty.Core/Model/connection/Connection.cs index 43206e90..2c8fb282 100644 --- a/runtime/csharp/Prompty.Core/Model/connection/Connection.cs +++ b/runtime/csharp/Prompty.Core/Model/connection/Connection.cs @@ -8,9 +8,9 @@ namespace Prompty.Core; /// /// Connection configuration for AI agents. -/// +/// /// `provider`, `kind`, and `endpoint` are required properties here, -/// +/// /// but this section can accept additional via options. /// public abstract partial class Connection @@ -140,7 +140,7 @@ private static Connection LoadKind(Dictionary data, LoadContext if (obj.AuthenticationMode is not null) { - result["authenticationMode"] = obj.AuthenticationMode.ToString().ToLowerInvariant(); + result["authenticationMode"] = obj.AuthenticationMode.Value.ToString().ToLowerInvariant(); } diff --git a/runtime/csharp/Prompty.Core/Model/connection/FoundryConnection.cs b/runtime/csharp/Prompty.Core/Model/connection/FoundryConnection.cs index 5be78291..d52e9219 100644 --- a/runtime/csharp/Prompty.Core/Model/connection/FoundryConnection.cs +++ b/runtime/csharp/Prompty.Core/Model/connection/FoundryConnection.cs @@ -8,9 +8,9 @@ namespace Prompty.Core; /// /// Connection configuration for Microsoft Foundry projects. -/// +/// /// Provides project-scoped access to models, tools, and services -/// +/// /// via Entra ID (DefaultAzureCredential) authentication. /// public partial class FoundryConnection : Connection diff --git a/runtime/csharp/Prompty.Core/Model/connection/OAuthConnection.cs b/runtime/csharp/Prompty.Core/Model/connection/OAuthConnection.cs index bf557755..a576abf7 100644 --- a/runtime/csharp/Prompty.Core/Model/connection/OAuthConnection.cs +++ b/runtime/csharp/Prompty.Core/Model/connection/OAuthConnection.cs @@ -8,9 +8,9 @@ namespace Prompty.Core; /// /// Connection configuration using OAuth 2.0 client credentials. -/// +/// /// Useful for tools and services that require OAuth authentication, -/// +/// /// such as MCP servers, OpenAPI endpoints, or other REST APIs. /// public partial class OAuthConnection : Connection diff --git a/runtime/csharp/Prompty.Core/Model/conversation/ContentPart.cs b/runtime/csharp/Prompty.Core/Model/conversation/ContentPart.cs index 8bf55070..47f3e900 100644 --- a/runtime/csharp/Prompty.Core/Model/conversation/ContentPart.cs +++ b/runtime/csharp/Prompty.Core/Model/conversation/ContentPart.cs @@ -8,7 +8,7 @@ namespace Prompty.Core; /// /// A part of a message's content. Content parts are discriminated on the `kind` -/// +/// /// field and represent the different modalities that can appear in a message. /// public abstract partial class ContentPart diff --git a/runtime/csharp/Prompty.Core/Model/conversation/Message.cs b/runtime/csharp/Prompty.Core/Model/conversation/Message.cs index f13b76f8..1e99408b 100644 --- a/runtime/csharp/Prompty.Core/Model/conversation/Message.cs +++ b/runtime/csharp/Prompty.Core/Model/conversation/Message.cs @@ -8,7 +8,7 @@ namespace Prompty.Core; /// /// A message in a conversation. Messages have a role and a list of content parts -/// +/// /// representing the different modalities of the message content. /// public partial class Message : IMessageHelpers diff --git a/runtime/csharp/Prompty.Core/Model/conversation/ThreadMarker.cs b/runtime/csharp/Prompty.Core/Model/conversation/ThreadMarker.cs index 7cf74f85..1912303c 100644 --- a/runtime/csharp/Prompty.Core/Model/conversation/ThreadMarker.cs +++ b/runtime/csharp/Prompty.Core/Model/conversation/ThreadMarker.cs @@ -8,11 +8,11 @@ namespace Prompty.Core; /// /// Positional marker for conversation history insertion during template rendering. -/// +/// /// During `prepare()`, nonce strings in rendered text are replaced with -/// +/// /// ThreadMarker objects. The pipeline then replaces them with actual -/// +/// /// conversation messages from the inputs. /// public partial class ThreadMarker diff --git a/runtime/csharp/Prompty.Core/Model/conversation/ToolCall.cs b/runtime/csharp/Prompty.Core/Model/conversation/ToolCall.cs index 4c68a00e..201ae840 100644 --- a/runtime/csharp/Prompty.Core/Model/conversation/ToolCall.cs +++ b/runtime/csharp/Prompty.Core/Model/conversation/ToolCall.cs @@ -8,7 +8,7 @@ namespace Prompty.Core; /// /// A tool call requested by the LLM. Contains the function name and serialized -/// +/// /// arguments that should be dispatched to the appropriate tool handler. /// public partial class ToolCall diff --git a/runtime/csharp/Prompty.Core/Model/conversation/ToolResult.cs b/runtime/csharp/Prompty.Core/Model/conversation/ToolResult.cs index 9f045d87..b8ebce9d 100644 --- a/runtime/csharp/Prompty.Core/Model/conversation/ToolResult.cs +++ b/runtime/csharp/Prompty.Core/Model/conversation/ToolResult.cs @@ -8,11 +8,11 @@ namespace Prompty.Core; /// /// The result of a tool execution. Contains a list of content parts, enabling -/// +/// /// rich tool results (text, images, files, audio) rather than just strings. -/// +/// /// Implementations MUST support conversion from a plain string to a ToolResult -/// +/// /// containing a single TextPart for backward compatibility. /// public partial class ToolResult : IToolResultHelpers @@ -36,6 +36,26 @@ public ToolResult() /// public IList Parts { get; set; } = []; + /// + /// Semantic execution status for the tool result + /// + public ToolResultStatus? Status { get; set; } + + /// + /// Stable machine-readable error category when status is not success + /// + public string? ErrorKind { get; set; } + + /// + /// Human-readable error message when status is not success + /// + public string? ErrorMessage { get; set; } + + /// + /// Tool execution duration in milliseconds + /// + public double? DurationMs { get; set; } + #region Load Methods @@ -63,6 +83,26 @@ public static ToolResult Load(Dictionary data, LoadContext? con instance.Parts = LoadParts(partsValue, context); } + if (data.TryGetValue("status", out var statusValue) && statusValue is not null) + { + instance.Status = Enum.Parse(statusValue?.ToString()!, true); + } + + if (data.TryGetValue("errorKind", out var errorKindValue) && errorKindValue is not null) + { + instance.ErrorKind = errorKindValue?.ToString()!; + } + + if (data.TryGetValue("errorMessage", out var errorMessageValue) && errorMessageValue is not null) + { + instance.ErrorMessage = errorMessageValue?.ToString()!; + } + + if (data.TryGetValue("durationMs", out var durationMsValue) && durationMsValue is not null) + { + instance.DurationMs = Convert.ToDouble(durationMsValue); + } + if (context is not null) { instance = context.ProcessOutput(instance); @@ -149,6 +189,30 @@ public static IList LoadParts(object data, LoadContext? context) result["parts"] = SaveParts(obj.Parts, context); + if (obj.Status is not null) + { + result["status"] = obj.Status.Value.ToString().ToLowerInvariant(); + } + + + if (obj.ErrorKind is not null) + { + result["errorKind"] = obj.ErrorKind; + } + + + if (obj.ErrorMessage is not null) + { + result["errorMessage"] = obj.ErrorMessage; + } + + + if (obj.DurationMs is not null) + { + result["durationMs"] = obj.DurationMs; + } + + if (context is not null) { result = context.ProcessDict(result); diff --git a/runtime/csharp/Prompty.Core/Model/conversation/ToolResultStatus.cs b/runtime/csharp/Prompty.Core/Model/conversation/ToolResultStatus.cs new file mode 100644 index 00000000..9a659b88 --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/conversation/ToolResultStatus.cs @@ -0,0 +1,23 @@ +// +// Code generated by Prompty emitter; DO NOT EDIT. + +using System.Text.Json.Serialization; + +namespace Prompty.Core; + +[JsonConverter(typeof(JsonStringEnumConverter))] +public enum ToolResultStatus +{ + [JsonPropertyName("success")] + Success, + + [JsonPropertyName("error")] + Error, + + [JsonPropertyName("cancelled")] + Cancelled, + + [JsonPropertyName("timeout")] + Timeout, + +} diff --git a/runtime/csharp/Prompty.Core/Model/core/ArrayProperty.cs b/runtime/csharp/Prompty.Core/Model/core/ArrayProperty.cs index 24d31f62..8d38bc04 100644 --- a/runtime/csharp/Prompty.Core/Model/core/ArrayProperty.cs +++ b/runtime/csharp/Prompty.Core/Model/core/ArrayProperty.cs @@ -8,7 +8,7 @@ namespace Prompty.Core; /// /// Represents an array property. -/// +/// /// This extends the base Property model to represent an array of items. /// public partial class ArrayProperty : Property diff --git a/runtime/csharp/Prompty.Core/Model/core/FileNotFoundError.cs b/runtime/csharp/Prompty.Core/Model/core/FileNotFoundError.cs index 42e4f636..381a1f36 100644 --- a/runtime/csharp/Prompty.Core/Model/core/FileNotFoundError.cs +++ b/runtime/csharp/Prompty.Core/Model/core/FileNotFoundError.cs @@ -8,7 +8,7 @@ namespace Prompty.Core; /// /// Raised when a referenced file cannot be found. This applies to both -/// +/// /// .prompty files and ${file:path} references in frontmatter. /// public partial class FileNotFoundError diff --git a/runtime/csharp/Prompty.Core/Model/core/InvokerError.cs b/runtime/csharp/Prompty.Core/Model/core/InvokerError.cs index 840c4b65..1b05784c 100644 --- a/runtime/csharp/Prompty.Core/Model/core/InvokerError.cs +++ b/runtime/csharp/Prompty.Core/Model/core/InvokerError.cs @@ -8,9 +8,9 @@ namespace Prompty.Core; /// /// Raised when no invoker implementation is registered for a given component -/// +/// /// and key. For example, if no renderer is registered for the key "jinja2", -/// +/// /// an InvokerError is raised. /// public partial class InvokerError diff --git a/runtime/csharp/Prompty.Core/Model/core/ObjectProperty.cs b/runtime/csharp/Prompty.Core/Model/core/ObjectProperty.cs index 1ef8f5cf..d6a5c9b7 100644 --- a/runtime/csharp/Prompty.Core/Model/core/ObjectProperty.cs +++ b/runtime/csharp/Prompty.Core/Model/core/ObjectProperty.cs @@ -8,7 +8,7 @@ namespace Prompty.Core; /// /// Represents an object property. -/// +/// /// This extends the base Property model to represent a structured object. /// public partial class ObjectProperty : Property diff --git a/runtime/csharp/Prompty.Core/Model/core/Property.cs b/runtime/csharp/Prompty.Core/Model/core/Property.cs index 38ac93a6..ace0e867 100644 --- a/runtime/csharp/Prompty.Core/Model/core/Property.cs +++ b/runtime/csharp/Prompty.Core/Model/core/Property.cs @@ -8,13 +8,13 @@ namespace Prompty.Core; /// /// Represents a single property. -/// +/// /// - This model defines the structure of properties that can be used in prompts, -/// +/// /// including their type, description, whether they are required, and other attributes. -/// +/// /// - It allows for the definition of dynamic inputs that can be filled with data -/// +/// /// and processed to generate prompts for AI models. /// public partial class Property diff --git a/runtime/csharp/Prompty.Core/Model/core/ValidationError.cs b/runtime/csharp/Prompty.Core/Model/core/ValidationError.cs index b2a9192a..b7a6b650 100644 --- a/runtime/csharp/Prompty.Core/Model/core/ValidationError.cs +++ b/runtime/csharp/Prompty.Core/Model/core/ValidationError.cs @@ -8,7 +8,7 @@ namespace Prompty.Core; /// /// Raised when input validation fails. Each ValidationError describes a -/// +/// /// single property that did not satisfy its constraint. /// public partial class ValidationError diff --git a/runtime/csharp/Prompty.Core/Model/core/ValidationResult.cs b/runtime/csharp/Prompty.Core/Model/core/ValidationResult.cs index 3ac6d938..beabf0e6 100644 --- a/runtime/csharp/Prompty.Core/Model/core/ValidationResult.cs +++ b/runtime/csharp/Prompty.Core/Model/core/ValidationResult.cs @@ -8,9 +8,9 @@ namespace Prompty.Core; /// /// The result of validating inputs against a Prompty's inputs. -/// +/// /// Returned by `validate_inputs` (§12.2) to indicate whether all -/// +/// /// required inputs are present and satisfy their constraints. /// public partial class ValidationResult diff --git a/runtime/csharp/Prompty.Core/Model/events/CompactionCompletePayload.cs b/runtime/csharp/Prompty.Core/Model/events/CompactionCompletePayload.cs index ab81e80c..0f283935 100644 --- a/runtime/csharp/Prompty.Core/Model/events/CompactionCompletePayload.cs +++ b/runtime/csharp/Prompty.Core/Model/events/CompactionCompletePayload.cs @@ -35,6 +35,11 @@ public CompactionCompletePayload() /// public int Remaining { get; set; } + /// + /// Length of the generated summary, when a summarization strategy is used + /// + public int? SummaryLength { get; set; } + #region Load Methods @@ -67,6 +72,11 @@ public static CompactionCompletePayload Load(Dictionary data, L instance.Remaining = Convert.ToInt32(remainingValue); } + if (data.TryGetValue("summaryLength", out var summaryLengthValue) && summaryLengthValue is not null) + { + instance.SummaryLength = Convert.ToInt32(summaryLengthValue); + } + if (context is not null) { instance = context.ProcessOutput(instance); @@ -102,6 +112,12 @@ public static CompactionCompletePayload Load(Dictionary data, L result["remaining"] = obj.Remaining; + if (obj.SummaryLength is not null) + { + result["summaryLength"] = obj.SummaryLength; + } + + if (context is not null) { result = context.ProcessDict(result); diff --git a/runtime/csharp/Prompty.Core/Model/events/CompactionStartPayload.cs b/runtime/csharp/Prompty.Core/Model/events/CompactionStartPayload.cs new file mode 100644 index 00000000..3990bc19 --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/CompactionStartPayload.cs @@ -0,0 +1,155 @@ +// Copyright (c) Microsoft. All rights reserved. +using System.Text.Json; +using YamlDotNet.Serialization; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + +/// +/// Payload for "compaction_start" events — context compaction is beginning. +/// +public partial class CompactionStartPayload +{ + /// + /// The shorthand property name for this type, if any. + /// + public static string? ShorthandProperty => null; + + /// + /// Initializes a new instance of . + /// +#pragma warning disable CS8618 + public CompactionStartPayload() + { + } +#pragma warning restore CS8618 + + /// + /// Number of messages selected for compaction + /// + public int DroppedCount { get; set; } + + + + #region Load Methods + + /// + /// Load a CompactionStartPayload instance from a dictionary. + /// + /// The dictionary containing the data. + /// Optional context with pre/post processing callbacks. + /// The loaded CompactionStartPayload instance. + public static CompactionStartPayload Load(Dictionary data, LoadContext? context = null) + { + if (context is not null) + { + data = context.ProcessInput(data); + } + + + // Create new instance + var instance = new CompactionStartPayload(); + + + if (data.TryGetValue("droppedCount", out var droppedCountValue) && droppedCountValue is not null) + { + instance.DroppedCount = Convert.ToInt32(droppedCountValue); + } + + if (context is not null) + { + instance = context.ProcessOutput(instance); + } + return instance; + } + + + #endregion + + #region Save Methods + + /// + /// Save the CompactionStartPayload instance to a dictionary. + /// + /// Optional context with pre/post processing callbacks. + /// The dictionary representation of this instance. + public Dictionary Save(SaveContext? context = null) + { + var obj = this; + if (context is not null) + { + obj = context.ProcessObject(obj); + } + + + var result = new Dictionary(); + + + result["droppedCount"] = obj.DroppedCount; + + + if (context is not null) + { + result = context.ProcessDict(result); + } + + return result; + } + + + /// + /// Convert the CompactionStartPayload instance to a YAML string. + /// + /// Optional context with pre/post processing callbacks. + /// The YAML string representation of this instance. + public string ToYaml(SaveContext? context = null) + { + context ??= new SaveContext(); + return context.ToYaml(Save(context)); + } + + /// + /// Convert the CompactionStartPayload instance to a JSON string. + /// + /// Optional context with pre/post processing callbacks. + /// Whether to indent the output. Defaults to true. + /// The JSON string representation of this instance. + public string ToJson(SaveContext? context = null, bool indent = true) + { + context ??= new SaveContext(); + return context.ToJson(Save(context), indent); + } + + /// + /// Load a CompactionStartPayload instance from a JSON string. + /// + /// The JSON string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded CompactionStartPayload instance. + public static CompactionStartPayload FromJson(string json, LoadContext? context = null) + { + using var doc = JsonDocument.Parse(json); + Dictionary dict; + dict = JsonSerializer.Deserialize>(json, JsonUtils.Options) + ?? throw new ArgumentException("Failed to parse JSON as dictionary"); + + return Load(dict, context); + } + + /// + /// Load a CompactionStartPayload instance from a YAML string. + /// + /// The YAML string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded CompactionStartPayload instance. + public static CompactionStartPayload FromYaml(string yaml, LoadContext? context = null) + { + var dict = YamlUtils.Deserializer.Deserialize>(yaml) + ?? throw new ArgumentException("Failed to parse YAML as dictionary"); + + return Load(dict, context); + } + + #endregion +} diff --git a/runtime/csharp/Prompty.Core/Model/events/DoneEventPayload.cs b/runtime/csharp/Prompty.Core/Model/events/DoneEventPayload.cs index 3845e84b..fc193aac 100644 --- a/runtime/csharp/Prompty.Core/Model/events/DoneEventPayload.cs +++ b/runtime/csharp/Prompty.Core/Model/events/DoneEventPayload.cs @@ -26,9 +26,9 @@ public DoneEventPayload() #pragma warning restore CS8618 /// - /// The final text response from the LLM + /// The final response from the LLM after processing /// - public string Response { get; set; } = string.Empty; + public object Response { get; set; } = new object(); /// /// The final conversation state including all messages @@ -59,7 +59,7 @@ public static DoneEventPayload Load(Dictionary data, LoadContex if (data.TryGetValue("response", out var responseValue) && responseValue is not null) { - instance.Response = responseValue?.ToString()!; + instance.Response = responseValue; } if (data.TryGetValue("messages", out var messagesValue) && messagesValue is not null) diff --git a/runtime/csharp/Prompty.Core/Model/events/ErrorEventPayload.cs b/runtime/csharp/Prompty.Core/Model/events/ErrorEventPayload.cs index 8513e878..3c72a13a 100644 --- a/runtime/csharp/Prompty.Core/Model/events/ErrorEventPayload.cs +++ b/runtime/csharp/Prompty.Core/Model/events/ErrorEventPayload.cs @@ -30,6 +30,16 @@ public ErrorEventPayload() /// public string Message { get; set; } = string.Empty; + /// + /// Stable machine-readable error category + /// + public string? ErrorKind { get; set; } + + /// + /// Operation or phase where the error occurred + /// + public string? Phase { get; set; } + #region Load Methods @@ -57,6 +67,16 @@ public static ErrorEventPayload Load(Dictionary data, LoadConte instance.Message = messageValue?.ToString()!; } + if (data.TryGetValue("errorKind", out var errorKindValue) && errorKindValue is not null) + { + instance.ErrorKind = errorKindValue?.ToString()!; + } + + if (data.TryGetValue("phase", out var phaseValue) && phaseValue is not null) + { + instance.Phase = phaseValue?.ToString()!; + } + if (context is not null) { instance = context.ProcessOutput(instance); @@ -89,6 +109,18 @@ public static ErrorEventPayload Load(Dictionary data, LoadConte result["message"] = obj.Message; + if (obj.ErrorKind is not null) + { + result["errorKind"] = obj.ErrorKind; + } + + + if (obj.Phase is not null) + { + result["phase"] = obj.Phase; + } + + if (context is not null) { result = context.ProcessDict(result); diff --git a/runtime/csharp/Prompty.Core/Model/events/LlmCompletePayload.cs b/runtime/csharp/Prompty.Core/Model/events/LlmCompletePayload.cs new file mode 100644 index 00000000..755ff31a --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/LlmCompletePayload.cs @@ -0,0 +1,206 @@ +// Copyright (c) Microsoft. All rights reserved. +using System.Text.Json; +using YamlDotNet.Serialization; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + +/// +/// Payload for "llm_complete" events — an LLM request completed. +/// +public partial class LlmCompletePayload +{ + /// + /// The shorthand property name for this type, if any. + /// + public static string? ShorthandProperty => null; + + /// + /// Initializes a new instance of . + /// +#pragma warning disable CS8618 + public LlmCompletePayload() + { + } +#pragma warning restore CS8618 + + /// + /// Provider request identifier, when supplied by the SDK/API + /// + public string? RequestId { get; set; } + + /// + /// Service request identifier, when supplied by the SDK/API + /// + public string? ServiceRequestId { get; set; } + + /// + /// Token usage reported by the provider + /// + public TokenUsage? Usage { get; set; } + + /// + /// LLM call duration in milliseconds + /// + public double? DurationMs { get; set; } + + + + #region Load Methods + + /// + /// Load a LlmCompletePayload instance from a dictionary. + /// + /// The dictionary containing the data. + /// Optional context with pre/post processing callbacks. + /// The loaded LlmCompletePayload instance. + public static LlmCompletePayload Load(Dictionary data, LoadContext? context = null) + { + if (context is not null) + { + data = context.ProcessInput(data); + } + + + // Create new instance + var instance = new LlmCompletePayload(); + + + if (data.TryGetValue("requestId", out var requestIdValue) && requestIdValue is not null) + { + instance.RequestId = requestIdValue?.ToString()!; + } + + if (data.TryGetValue("serviceRequestId", out var serviceRequestIdValue) && serviceRequestIdValue is not null) + { + instance.ServiceRequestId = serviceRequestIdValue?.ToString()!; + } + + if (data.TryGetValue("usage", out var usageValue) && usageValue is not null) + { + instance.Usage = TokenUsage.Load(usageValue.GetDictionary(TokenUsage.ShorthandProperty), context); + } + + if (data.TryGetValue("durationMs", out var durationMsValue) && durationMsValue is not null) + { + instance.DurationMs = Convert.ToDouble(durationMsValue); + } + + if (context is not null) + { + instance = context.ProcessOutput(instance); + } + return instance; + } + + + #endregion + + #region Save Methods + + /// + /// Save the LlmCompletePayload instance to a dictionary. + /// + /// Optional context with pre/post processing callbacks. + /// The dictionary representation of this instance. + public Dictionary Save(SaveContext? context = null) + { + var obj = this; + if (context is not null) + { + obj = context.ProcessObject(obj); + } + + + var result = new Dictionary(); + + + if (obj.RequestId is not null) + { + result["requestId"] = obj.RequestId; + } + + + if (obj.ServiceRequestId is not null) + { + result["serviceRequestId"] = obj.ServiceRequestId; + } + + + if (obj.Usage is not null) + { + result["usage"] = obj.Usage?.Save(context); + } + + + if (obj.DurationMs is not null) + { + result["durationMs"] = obj.DurationMs; + } + + + if (context is not null) + { + result = context.ProcessDict(result); + } + + return result; + } + + + /// + /// Convert the LlmCompletePayload instance to a YAML string. + /// + /// Optional context with pre/post processing callbacks. + /// The YAML string representation of this instance. + public string ToYaml(SaveContext? context = null) + { + context ??= new SaveContext(); + return context.ToYaml(Save(context)); + } + + /// + /// Convert the LlmCompletePayload instance to a JSON string. + /// + /// Optional context with pre/post processing callbacks. + /// Whether to indent the output. Defaults to true. + /// The JSON string representation of this instance. + public string ToJson(SaveContext? context = null, bool indent = true) + { + context ??= new SaveContext(); + return context.ToJson(Save(context), indent); + } + + /// + /// Load a LlmCompletePayload instance from a JSON string. + /// + /// The JSON string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded LlmCompletePayload instance. + public static LlmCompletePayload FromJson(string json, LoadContext? context = null) + { + using var doc = JsonDocument.Parse(json); + Dictionary dict; + dict = JsonSerializer.Deserialize>(json, JsonUtils.Options) + ?? throw new ArgumentException("Failed to parse JSON as dictionary"); + + return Load(dict, context); + } + + /// + /// Load a LlmCompletePayload instance from a YAML string. + /// + /// The YAML string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded LlmCompletePayload instance. + public static LlmCompletePayload FromYaml(string yaml, LoadContext? context = null) + { + var dict = YamlUtils.Deserializer.Deserialize>(yaml) + ?? throw new ArgumentException("Failed to parse YAML as dictionary"); + + return Load(dict, context); + } + + #endregion +} diff --git a/runtime/csharp/Prompty.Core/Model/events/LlmStartPayload.cs b/runtime/csharp/Prompty.Core/Model/events/LlmStartPayload.cs new file mode 100644 index 00000000..7fce71e5 --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/LlmStartPayload.cs @@ -0,0 +1,206 @@ +// Copyright (c) Microsoft. All rights reserved. +using System.Text.Json; +using YamlDotNet.Serialization; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + +/// +/// Payload for "llm_start" events — an LLM request is about to be sent. +/// +public partial class LlmStartPayload +{ + /// + /// The shorthand property name for this type, if any. + /// + public static string? ShorthandProperty => null; + + /// + /// Initializes a new instance of . + /// +#pragma warning disable CS8618 + public LlmStartPayload() + { + } +#pragma warning restore CS8618 + + /// + /// Provider identifier used for the request + /// + public string? Provider { get; set; } + + /// + /// Model or deployment identifier used for the request + /// + public string? ModelId { get; set; } + + /// + /// Number of messages sent to the provider + /// + public int? MessageCount { get; set; } + + /// + /// Retry attempt number, zero for the initial attempt + /// + public int? Attempt { get; set; } + + + + #region Load Methods + + /// + /// Load a LlmStartPayload instance from a dictionary. + /// + /// The dictionary containing the data. + /// Optional context with pre/post processing callbacks. + /// The loaded LlmStartPayload instance. + public static LlmStartPayload Load(Dictionary data, LoadContext? context = null) + { + if (context is not null) + { + data = context.ProcessInput(data); + } + + + // Create new instance + var instance = new LlmStartPayload(); + + + if (data.TryGetValue("provider", out var providerValue) && providerValue is not null) + { + instance.Provider = providerValue?.ToString()!; + } + + if (data.TryGetValue("modelId", out var modelIdValue) && modelIdValue is not null) + { + instance.ModelId = modelIdValue?.ToString()!; + } + + if (data.TryGetValue("messageCount", out var messageCountValue) && messageCountValue is not null) + { + instance.MessageCount = Convert.ToInt32(messageCountValue); + } + + if (data.TryGetValue("attempt", out var attemptValue) && attemptValue is not null) + { + instance.Attempt = Convert.ToInt32(attemptValue); + } + + if (context is not null) + { + instance = context.ProcessOutput(instance); + } + return instance; + } + + + #endregion + + #region Save Methods + + /// + /// Save the LlmStartPayload instance to a dictionary. + /// + /// Optional context with pre/post processing callbacks. + /// The dictionary representation of this instance. + public Dictionary Save(SaveContext? context = null) + { + var obj = this; + if (context is not null) + { + obj = context.ProcessObject(obj); + } + + + var result = new Dictionary(); + + + if (obj.Provider is not null) + { + result["provider"] = obj.Provider; + } + + + if (obj.ModelId is not null) + { + result["modelId"] = obj.ModelId; + } + + + if (obj.MessageCount is not null) + { + result["messageCount"] = obj.MessageCount; + } + + + if (obj.Attempt is not null) + { + result["attempt"] = obj.Attempt; + } + + + if (context is not null) + { + result = context.ProcessDict(result); + } + + return result; + } + + + /// + /// Convert the LlmStartPayload instance to a YAML string. + /// + /// Optional context with pre/post processing callbacks. + /// The YAML string representation of this instance. + public string ToYaml(SaveContext? context = null) + { + context ??= new SaveContext(); + return context.ToYaml(Save(context)); + } + + /// + /// Convert the LlmStartPayload instance to a JSON string. + /// + /// Optional context with pre/post processing callbacks. + /// Whether to indent the output. Defaults to true. + /// The JSON string representation of this instance. + public string ToJson(SaveContext? context = null, bool indent = true) + { + context ??= new SaveContext(); + return context.ToJson(Save(context), indent); + } + + /// + /// Load a LlmStartPayload instance from a JSON string. + /// + /// The JSON string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded LlmStartPayload instance. + public static LlmStartPayload FromJson(string json, LoadContext? context = null) + { + using var doc = JsonDocument.Parse(json); + Dictionary dict; + dict = JsonSerializer.Deserialize>(json, JsonUtils.Options) + ?? throw new ArgumentException("Failed to parse JSON as dictionary"); + + return Load(dict, context); + } + + /// + /// Load a LlmStartPayload instance from a YAML string. + /// + /// The YAML string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded LlmStartPayload instance. + public static LlmStartPayload FromYaml(string yaml, LoadContext? context = null) + { + var dict = YamlUtils.Deserializer.Deserialize>(yaml) + ?? throw new ArgumentException("Failed to parse YAML as dictionary"); + + return Load(dict, context); + } + + #endregion +} diff --git a/runtime/csharp/Prompty.Core/Model/events/MessagesUpdatedPayload.cs b/runtime/csharp/Prompty.Core/Model/events/MessagesUpdatedPayload.cs index cfddbe1a..a42c325c 100644 --- a/runtime/csharp/Prompty.Core/Model/events/MessagesUpdatedPayload.cs +++ b/runtime/csharp/Prompty.Core/Model/events/MessagesUpdatedPayload.cs @@ -28,7 +28,22 @@ public MessagesUpdatedPayload() /// /// The current full message list after the update /// - public IList Messages { get; set; } = []; + public IList? Messages { get; set; } + + /// + /// Why the message list changed + /// + public string? Reason { get; set; } + + /// + /// Messages appended by this update, when available + /// + public IList? Appended { get; set; } + + /// + /// Number of messages removed by this update, when available + /// + public int? Removed { get; set; } @@ -57,6 +72,21 @@ public static MessagesUpdatedPayload Load(Dictionary data, Load instance.Messages = LoadMessages(messagesValue, context); } + if (data.TryGetValue("reason", out var reasonValue) && reasonValue is not null) + { + instance.Reason = reasonValue?.ToString()!; + } + + if (data.TryGetValue("appended", out var appendedValue) && appendedValue is not null) + { + instance.Appended = LoadAppended(appendedValue, context); + } + + if (data.TryGetValue("removed", out var removedValue) && removedValue is not null) + { + instance.Removed = Convert.ToInt32(removedValue); + } + if (context is not null) { instance = context.ProcessOutput(instance); @@ -119,6 +149,60 @@ public static IList LoadMessages(object data, LoadContext? context) } + /// + /// Load a list of Message from a dictionary or list. + /// + public static IList LoadAppended(object data, LoadContext? context) + { + var result = new List(); + + if (data is Dictionary dict) + { + // Convert named dictionary to list + foreach (var kvp in dict) + { + if (kvp.Value is IEnumerable) + { + throw new ArgumentException( + $"Invalid 'appended' format: key '{kvp.Key}' has an array value. " + + $"'appended' must be a flat list of objects or a name-keyed dict — " + + "not a nested {" + kvp.Key + ": [...]} structure."); + } + var itemDict = kvp.Value.GetDictionary(); + if (itemDict.Count > 0) + { + // Value is an object, add name to it + itemDict["name"] = kvp.Key; + result.Add(Message.Load(itemDict, context)); + } + else + { + // Value is a scalar, use it as the primary property + var newDict = new Dictionary + { + ["name"] = kvp.Key, + ["role"] = kvp.Value + }; + result.Add(Message.Load(newDict, context)); + } + } + } + else if (data is IEnumerable list) + { + foreach (var item in list) + { + var itemDict = item.GetDictionary(Message.ShorthandProperty); + if (itemDict.Count > 0) + { + result.Add(Message.Load(itemDict, context)); + } + } + } + + return result; + } + + #endregion #region Save Methods @@ -140,7 +224,28 @@ public static IList LoadMessages(object data, LoadContext? context) var result = new Dictionary(); - result["messages"] = SaveMessages(obj.Messages, context); + if (obj.Messages is not null) + { + result["messages"] = SaveMessages(obj.Messages, context); + } + + + if (obj.Reason is not null) + { + result["reason"] = obj.Reason; + } + + + if (obj.Appended is not null) + { + result["appended"] = SaveAppended(obj.Appended, context); + } + + + if (obj.Removed is not null) + { + result["removed"] = obj.Removed; + } if (context is not null) @@ -165,6 +270,19 @@ public static object SaveMessages(IList items, SaveContext? context) } + /// + /// Save a list of Message to object or array format. + /// + public static object SaveAppended(IList items, SaveContext? context) + { + context ??= new SaveContext(); + + // This collection type does not have a 'name' property, only array format is supported + return items.Select(item => item.Save(context)).ToList(); + + } + + /// /// Convert the MessagesUpdatedPayload instance to a YAML string. /// diff --git a/runtime/csharp/Prompty.Core/Model/events/PermissionCompletedPayload.cs b/runtime/csharp/Prompty.Core/Model/events/PermissionCompletedPayload.cs new file mode 100644 index 00000000..ed54a8b2 --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/PermissionCompletedPayload.cs @@ -0,0 +1,184 @@ +// Copyright (c) Microsoft. All rights reserved. +using System.Text.Json; +using YamlDotNet.Serialization; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + +/// +/// Payload for permission completion events — an approval decision was made. +/// +public partial class PermissionCompletedPayload +{ + /// + /// The shorthand property name for this type, if any. + /// + public static string? ShorthandProperty => null; + + /// + /// Initializes a new instance of . + /// +#pragma warning disable CS8618 + public PermissionCompletedPayload() + { + } +#pragma warning restore CS8618 + + /// + /// Permission/action name that was decided + /// + public string Permission { get; set; } = string.Empty; + + /// + /// Whether the requested permission was approved + /// + public bool Approved { get; set; } = false; + + /// + /// Decision reason, if available + /// + public string? Reason { get; set; } + + + + #region Load Methods + + /// + /// Load a PermissionCompletedPayload instance from a dictionary. + /// + /// The dictionary containing the data. + /// Optional context with pre/post processing callbacks. + /// The loaded PermissionCompletedPayload instance. + public static PermissionCompletedPayload Load(Dictionary data, LoadContext? context = null) + { + if (context is not null) + { + data = context.ProcessInput(data); + } + + + // Create new instance + var instance = new PermissionCompletedPayload(); + + + if (data.TryGetValue("permission", out var permissionValue) && permissionValue is not null) + { + instance.Permission = permissionValue?.ToString()!; + } + + if (data.TryGetValue("approved", out var approvedValue) && approvedValue is not null) + { + instance.Approved = Convert.ToBoolean(approvedValue); + } + + if (data.TryGetValue("reason", out var reasonValue) && reasonValue is not null) + { + instance.Reason = reasonValue?.ToString()!; + } + + if (context is not null) + { + instance = context.ProcessOutput(instance); + } + return instance; + } + + + #endregion + + #region Save Methods + + /// + /// Save the PermissionCompletedPayload instance to a dictionary. + /// + /// Optional context with pre/post processing callbacks. + /// The dictionary representation of this instance. + public Dictionary Save(SaveContext? context = null) + { + var obj = this; + if (context is not null) + { + obj = context.ProcessObject(obj); + } + + + var result = new Dictionary(); + + + result["permission"] = obj.Permission; + + + result["approved"] = obj.Approved; + + + if (obj.Reason is not null) + { + result["reason"] = obj.Reason; + } + + + if (context is not null) + { + result = context.ProcessDict(result); + } + + return result; + } + + + /// + /// Convert the PermissionCompletedPayload instance to a YAML string. + /// + /// Optional context with pre/post processing callbacks. + /// The YAML string representation of this instance. + public string ToYaml(SaveContext? context = null) + { + context ??= new SaveContext(); + return context.ToYaml(Save(context)); + } + + /// + /// Convert the PermissionCompletedPayload instance to a JSON string. + /// + /// Optional context with pre/post processing callbacks. + /// Whether to indent the output. Defaults to true. + /// The JSON string representation of this instance. + public string ToJson(SaveContext? context = null, bool indent = true) + { + context ??= new SaveContext(); + return context.ToJson(Save(context), indent); + } + + /// + /// Load a PermissionCompletedPayload instance from a JSON string. + /// + /// The JSON string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded PermissionCompletedPayload instance. + public static PermissionCompletedPayload FromJson(string json, LoadContext? context = null) + { + using var doc = JsonDocument.Parse(json); + Dictionary dict; + dict = JsonSerializer.Deserialize>(json, JsonUtils.Options) + ?? throw new ArgumentException("Failed to parse JSON as dictionary"); + + return Load(dict, context); + } + + /// + /// Load a PermissionCompletedPayload instance from a YAML string. + /// + /// The YAML string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded PermissionCompletedPayload instance. + public static PermissionCompletedPayload FromYaml(string yaml, LoadContext? context = null) + { + var dict = YamlUtils.Deserializer.Deserialize>(yaml) + ?? throw new ArgumentException("Failed to parse YAML as dictionary"); + + return Load(dict, context); + } + + #endregion +} diff --git a/runtime/csharp/Prompty.Core/Model/events/PermissionRequestedPayload.cs b/runtime/csharp/Prompty.Core/Model/events/PermissionRequestedPayload.cs new file mode 100644 index 00000000..a2e19616 --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/PermissionRequestedPayload.cs @@ -0,0 +1,187 @@ +// Copyright (c) Microsoft. All rights reserved. +using System.Text.Json; +using YamlDotNet.Serialization; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + +/// +/// Payload for permission request events — a host is asked to approve an action. +/// +public partial class PermissionRequestedPayload +{ + /// + /// The shorthand property name for this type, if any. + /// + public static string? ShorthandProperty => null; + + /// + /// Initializes a new instance of . + /// +#pragma warning disable CS8618 + public PermissionRequestedPayload() + { + } +#pragma warning restore CS8618 + + /// + /// Permission/action name being requested + /// + public string Permission { get; set; } = string.Empty; + + /// + /// Resource or tool the permission applies to + /// + public string? Target { get; set; } + + /// + /// Additional host-specific permission details + /// + public IDictionary? Details { get; set; } + + + + #region Load Methods + + /// + /// Load a PermissionRequestedPayload instance from a dictionary. + /// + /// The dictionary containing the data. + /// Optional context with pre/post processing callbacks. + /// The loaded PermissionRequestedPayload instance. + public static PermissionRequestedPayload Load(Dictionary data, LoadContext? context = null) + { + if (context is not null) + { + data = context.ProcessInput(data); + } + + + // Create new instance + var instance = new PermissionRequestedPayload(); + + + if (data.TryGetValue("permission", out var permissionValue) && permissionValue is not null) + { + instance.Permission = permissionValue?.ToString()!; + } + + if (data.TryGetValue("target", out var targetValue) && targetValue is not null) + { + instance.Target = targetValue?.ToString()!; + } + + if (data.TryGetValue("details", out var detailsValue) && detailsValue is not null) + { + instance.Details = detailsValue.GetDictionary()!; + } + + if (context is not null) + { + instance = context.ProcessOutput(instance); + } + return instance; + } + + + #endregion + + #region Save Methods + + /// + /// Save the PermissionRequestedPayload instance to a dictionary. + /// + /// Optional context with pre/post processing callbacks. + /// The dictionary representation of this instance. + public Dictionary Save(SaveContext? context = null) + { + var obj = this; + if (context is not null) + { + obj = context.ProcessObject(obj); + } + + + var result = new Dictionary(); + + + result["permission"] = obj.Permission; + + + if (obj.Target is not null) + { + result["target"] = obj.Target; + } + + + if (obj.Details is not null) + { + result["details"] = obj.Details; + } + + + if (context is not null) + { + result = context.ProcessDict(result); + } + + return result; + } + + + /// + /// Convert the PermissionRequestedPayload instance to a YAML string. + /// + /// Optional context with pre/post processing callbacks. + /// The YAML string representation of this instance. + public string ToYaml(SaveContext? context = null) + { + context ??= new SaveContext(); + return context.ToYaml(Save(context)); + } + + /// + /// Convert the PermissionRequestedPayload instance to a JSON string. + /// + /// Optional context with pre/post processing callbacks. + /// Whether to indent the output. Defaults to true. + /// The JSON string representation of this instance. + public string ToJson(SaveContext? context = null, bool indent = true) + { + context ??= new SaveContext(); + return context.ToJson(Save(context), indent); + } + + /// + /// Load a PermissionRequestedPayload instance from a JSON string. + /// + /// The JSON string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded PermissionRequestedPayload instance. + public static PermissionRequestedPayload FromJson(string json, LoadContext? context = null) + { + using var doc = JsonDocument.Parse(json); + Dictionary dict; + dict = JsonSerializer.Deserialize>(json, JsonUtils.Options) + ?? throw new ArgumentException("Failed to parse JSON as dictionary"); + + return Load(dict, context); + } + + /// + /// Load a PermissionRequestedPayload instance from a YAML string. + /// + /// The YAML string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded PermissionRequestedPayload instance. + public static PermissionRequestedPayload FromYaml(string yaml, LoadContext? context = null) + { + var dict = YamlUtils.Deserializer.Deserialize>(yaml) + ?? throw new ArgumentException("Failed to parse YAML as dictionary"); + + return Load(dict, context); + } + + #endregion +} diff --git a/runtime/csharp/Prompty.Core/Model/events/RetryPayload.cs b/runtime/csharp/Prompty.Core/Model/events/RetryPayload.cs new file mode 100644 index 00000000..c3b9f67b --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/RetryPayload.cs @@ -0,0 +1,216 @@ +// Copyright (c) Microsoft. All rights reserved. +using System.Text.Json; +using YamlDotNet.Serialization; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + +/// +/// Payload for "retry" events — a transient operation will be retried. +/// +public partial class RetryPayload +{ + /// + /// The shorthand property name for this type, if any. + /// + public static string? ShorthandProperty => null; + + /// + /// Initializes a new instance of . + /// +#pragma warning disable CS8618 + public RetryPayload() + { + } +#pragma warning restore CS8618 + + /// + /// Operation being retried + /// + public string Operation { get; set; } = string.Empty; + + /// + /// Attempt number about to run + /// + public int Attempt { get; set; } + + /// + /// Maximum configured attempts + /// + public int? MaxAttempts { get; set; } + + /// + /// Backoff delay before the next attempt in milliseconds + /// + public double? DelayMs { get; set; } + + /// + /// Reason for the retry + /// + public string? Reason { get; set; } + + + + #region Load Methods + + /// + /// Load a RetryPayload instance from a dictionary. + /// + /// The dictionary containing the data. + /// Optional context with pre/post processing callbacks. + /// The loaded RetryPayload instance. + public static RetryPayload Load(Dictionary data, LoadContext? context = null) + { + if (context is not null) + { + data = context.ProcessInput(data); + } + + + // Create new instance + var instance = new RetryPayload(); + + + if (data.TryGetValue("operation", out var operationValue) && operationValue is not null) + { + instance.Operation = operationValue?.ToString()!; + } + + if (data.TryGetValue("attempt", out var attemptValue) && attemptValue is not null) + { + instance.Attempt = Convert.ToInt32(attemptValue); + } + + if (data.TryGetValue("maxAttempts", out var maxAttemptsValue) && maxAttemptsValue is not null) + { + instance.MaxAttempts = Convert.ToInt32(maxAttemptsValue); + } + + if (data.TryGetValue("delayMs", out var delayMsValue) && delayMsValue is not null) + { + instance.DelayMs = Convert.ToDouble(delayMsValue); + } + + if (data.TryGetValue("reason", out var reasonValue) && reasonValue is not null) + { + instance.Reason = reasonValue?.ToString()!; + } + + if (context is not null) + { + instance = context.ProcessOutput(instance); + } + return instance; + } + + + #endregion + + #region Save Methods + + /// + /// Save the RetryPayload instance to a dictionary. + /// + /// Optional context with pre/post processing callbacks. + /// The dictionary representation of this instance. + public Dictionary Save(SaveContext? context = null) + { + var obj = this; + if (context is not null) + { + obj = context.ProcessObject(obj); + } + + + var result = new Dictionary(); + + + result["operation"] = obj.Operation; + + + result["attempt"] = obj.Attempt; + + + if (obj.MaxAttempts is not null) + { + result["maxAttempts"] = obj.MaxAttempts; + } + + + if (obj.DelayMs is not null) + { + result["delayMs"] = obj.DelayMs; + } + + + if (obj.Reason is not null) + { + result["reason"] = obj.Reason; + } + + + if (context is not null) + { + result = context.ProcessDict(result); + } + + return result; + } + + + /// + /// Convert the RetryPayload instance to a YAML string. + /// + /// Optional context with pre/post processing callbacks. + /// The YAML string representation of this instance. + public string ToYaml(SaveContext? context = null) + { + context ??= new SaveContext(); + return context.ToYaml(Save(context)); + } + + /// + /// Convert the RetryPayload instance to a JSON string. + /// + /// Optional context with pre/post processing callbacks. + /// Whether to indent the output. Defaults to true. + /// The JSON string representation of this instance. + public string ToJson(SaveContext? context = null, bool indent = true) + { + context ??= new SaveContext(); + return context.ToJson(Save(context), indent); + } + + /// + /// Load a RetryPayload instance from a JSON string. + /// + /// The JSON string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded RetryPayload instance. + public static RetryPayload FromJson(string json, LoadContext? context = null) + { + using var doc = JsonDocument.Parse(json); + Dictionary dict; + dict = JsonSerializer.Deserialize>(json, JsonUtils.Options) + ?? throw new ArgumentException("Failed to parse JSON as dictionary"); + + return Load(dict, context); + } + + /// + /// Load a RetryPayload instance from a YAML string. + /// + /// The YAML string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded RetryPayload instance. + public static RetryPayload FromYaml(string yaml, LoadContext? context = null) + { + var dict = YamlUtils.Deserializer.Deserialize>(yaml) + ?? throw new ArgumentException("Failed to parse YAML as dictionary"); + + return Load(dict, context); + } + + #endregion +} diff --git a/runtime/csharp/Prompty.Core/Model/events/StreamChunk.cs b/runtime/csharp/Prompty.Core/Model/events/StreamChunk.cs index 2fcc0b9d..56a8091d 100644 --- a/runtime/csharp/Prompty.Core/Model/events/StreamChunk.cs +++ b/runtime/csharp/Prompty.Core/Model/events/StreamChunk.cs @@ -8,7 +8,7 @@ namespace Prompty.Core; /// /// A chunk of data from a streaming LLM response. Stream chunks are -/// +/// /// discriminated on the `kind` field. /// public abstract partial class StreamChunk diff --git a/runtime/csharp/Prompty.Core/Model/events/ToolCallCompletePayload.cs b/runtime/csharp/Prompty.Core/Model/events/ToolCallCompletePayload.cs new file mode 100644 index 00000000..7d5f7cf9 --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/ToolCallCompletePayload.cs @@ -0,0 +1,232 @@ +// Copyright (c) Microsoft. All rights reserved. +using System.Text.Json; +using YamlDotNet.Serialization; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + +/// +/// Payload for "tool_call_complete" events — a tool dispatch finished. +/// +public partial class ToolCallCompletePayload +{ + /// + /// The shorthand property name for this type, if any. + /// + public static string? ShorthandProperty => null; + + /// + /// Initializes a new instance of . + /// +#pragma warning disable CS8618 + public ToolCallCompletePayload() + { + } +#pragma warning restore CS8618 + + /// + /// The unique identifier of the tool call + /// + public string? Id { get; set; } + + /// + /// The name of the tool that completed + /// + public string Name { get; set; } = string.Empty; + + /// + /// Whether the tool dispatch succeeded semantically + /// + public bool Success { get; set; } = false; + + /// + /// Normalized tool result + /// + public ToolResult? Result { get; set; } + + /// + /// Tool execution duration in milliseconds + /// + public double? DurationMs { get; set; } + + /// + /// Machine-readable error category when success is false + /// + public string? ErrorKind { get; set; } + + + + #region Load Methods + + /// + /// Load a ToolCallCompletePayload instance from a dictionary. + /// + /// The dictionary containing the data. + /// Optional context with pre/post processing callbacks. + /// The loaded ToolCallCompletePayload instance. + public static ToolCallCompletePayload Load(Dictionary data, LoadContext? context = null) + { + if (context is not null) + { + data = context.ProcessInput(data); + } + + + // Create new instance + var instance = new ToolCallCompletePayload(); + + + if (data.TryGetValue("id", out var idValue) && idValue is not null) + { + instance.Id = idValue?.ToString()!; + } + + if (data.TryGetValue("name", out var nameValue) && nameValue is not null) + { + instance.Name = nameValue?.ToString()!; + } + + if (data.TryGetValue("success", out var successValue) && successValue is not null) + { + instance.Success = Convert.ToBoolean(successValue); + } + + if (data.TryGetValue("result", out var resultValue) && resultValue is not null) + { + instance.Result = ToolResult.Load(resultValue.GetDictionary(ToolResult.ShorthandProperty), context); + } + + if (data.TryGetValue("durationMs", out var durationMsValue) && durationMsValue is not null) + { + instance.DurationMs = Convert.ToDouble(durationMsValue); + } + + if (data.TryGetValue("errorKind", out var errorKindValue) && errorKindValue is not null) + { + instance.ErrorKind = errorKindValue?.ToString()!; + } + + if (context is not null) + { + instance = context.ProcessOutput(instance); + } + return instance; + } + + + #endregion + + #region Save Methods + + /// + /// Save the ToolCallCompletePayload instance to a dictionary. + /// + /// Optional context with pre/post processing callbacks. + /// The dictionary representation of this instance. + public Dictionary Save(SaveContext? context = null) + { + var obj = this; + if (context is not null) + { + obj = context.ProcessObject(obj); + } + + + var result = new Dictionary(); + + + if (obj.Id is not null) + { + result["id"] = obj.Id; + } + + + result["name"] = obj.Name; + + + result["success"] = obj.Success; + + + if (obj.Result is not null) + { + result["result"] = obj.Result?.Save(context); + } + + + if (obj.DurationMs is not null) + { + result["durationMs"] = obj.DurationMs; + } + + + if (obj.ErrorKind is not null) + { + result["errorKind"] = obj.ErrorKind; + } + + + if (context is not null) + { + result = context.ProcessDict(result); + } + + return result; + } + + + /// + /// Convert the ToolCallCompletePayload instance to a YAML string. + /// + /// Optional context with pre/post processing callbacks. + /// The YAML string representation of this instance. + public string ToYaml(SaveContext? context = null) + { + context ??= new SaveContext(); + return context.ToYaml(Save(context)); + } + + /// + /// Convert the ToolCallCompletePayload instance to a JSON string. + /// + /// Optional context with pre/post processing callbacks. + /// Whether to indent the output. Defaults to true. + /// The JSON string representation of this instance. + public string ToJson(SaveContext? context = null, bool indent = true) + { + context ??= new SaveContext(); + return context.ToJson(Save(context), indent); + } + + /// + /// Load a ToolCallCompletePayload instance from a JSON string. + /// + /// The JSON string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded ToolCallCompletePayload instance. + public static ToolCallCompletePayload FromJson(string json, LoadContext? context = null) + { + using var doc = JsonDocument.Parse(json); + Dictionary dict; + dict = JsonSerializer.Deserialize>(json, JsonUtils.Options) + ?? throw new ArgumentException("Failed to parse JSON as dictionary"); + + return Load(dict, context); + } + + /// + /// Load a ToolCallCompletePayload instance from a YAML string. + /// + /// The YAML string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded ToolCallCompletePayload instance. + public static ToolCallCompletePayload FromYaml(string yaml, LoadContext? context = null) + { + var dict = YamlUtils.Deserializer.Deserialize>(yaml) + ?? throw new ArgumentException("Failed to parse YAML as dictionary"); + + return Load(dict, context); + } + + #endregion +} diff --git a/runtime/csharp/Prompty.Core/Model/events/ToolCallStartPayload.cs b/runtime/csharp/Prompty.Core/Model/events/ToolCallStartPayload.cs index 7527106d..de04a1da 100644 --- a/runtime/csharp/Prompty.Core/Model/events/ToolCallStartPayload.cs +++ b/runtime/csharp/Prompty.Core/Model/events/ToolCallStartPayload.cs @@ -25,6 +25,11 @@ public ToolCallStartPayload() } #pragma warning restore CS8618 + /// + /// The unique identifier of the tool call + /// + public string? Id { get; set; } + /// /// The name of the tool being called /// @@ -57,6 +62,11 @@ public static ToolCallStartPayload Load(Dictionary data, LoadCo var instance = new ToolCallStartPayload(); + if (data.TryGetValue("id", out var idValue) && idValue is not null) + { + instance.Id = idValue?.ToString()!; + } + if (data.TryGetValue("name", out var nameValue) && nameValue is not null) { instance.Name = nameValue?.ToString()!; @@ -96,6 +106,12 @@ public static ToolCallStartPayload Load(Dictionary data, LoadCo var result = new Dictionary(); + if (obj.Id is not null) + { + result["id"] = obj.Id; + } + + result["name"] = obj.Name; diff --git a/runtime/csharp/Prompty.Core/Model/events/TurnEndPayload.cs b/runtime/csharp/Prompty.Core/Model/events/TurnEndPayload.cs new file mode 100644 index 00000000..645f7b8d --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/TurnEndPayload.cs @@ -0,0 +1,206 @@ +// Copyright (c) Microsoft. All rights reserved. +using System.Text.Json; +using YamlDotNet.Serialization; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + +/// +/// Payload for "turn_end" events — a turn has completed. +/// +public partial class TurnEndPayload +{ + /// + /// The shorthand property name for this type, if any. + /// + public static string? ShorthandProperty => null; + + /// + /// Initializes a new instance of . + /// +#pragma warning disable CS8618 + public TurnEndPayload() + { + } +#pragma warning restore CS8618 + + /// + /// Number of tool-call iterations performed + /// + public int? Iterations { get; set; } + + /// + /// Final semantic status of the turn + /// + public TurnStatus? Status { get; set; } + + /// + /// Final response after processing, if available + /// + public object? Response { get; set; } + + /// + /// Total elapsed turn duration in milliseconds + /// + public double? DurationMs { get; set; } + + + + #region Load Methods + + /// + /// Load a TurnEndPayload instance from a dictionary. + /// + /// The dictionary containing the data. + /// Optional context with pre/post processing callbacks. + /// The loaded TurnEndPayload instance. + public static TurnEndPayload Load(Dictionary data, LoadContext? context = null) + { + if (context is not null) + { + data = context.ProcessInput(data); + } + + + // Create new instance + var instance = new TurnEndPayload(); + + + if (data.TryGetValue("iterations", out var iterationsValue) && iterationsValue is not null) + { + instance.Iterations = Convert.ToInt32(iterationsValue); + } + + if (data.TryGetValue("status", out var statusValue) && statusValue is not null) + { + instance.Status = Enum.Parse(statusValue?.ToString()!, true); + } + + if (data.TryGetValue("response", out var responseValue) && responseValue is not null) + { + instance.Response = responseValue; + } + + if (data.TryGetValue("durationMs", out var durationMsValue) && durationMsValue is not null) + { + instance.DurationMs = Convert.ToDouble(durationMsValue); + } + + if (context is not null) + { + instance = context.ProcessOutput(instance); + } + return instance; + } + + + #endregion + + #region Save Methods + + /// + /// Save the TurnEndPayload instance to a dictionary. + /// + /// Optional context with pre/post processing callbacks. + /// The dictionary representation of this instance. + public Dictionary Save(SaveContext? context = null) + { + var obj = this; + if (context is not null) + { + obj = context.ProcessObject(obj); + } + + + var result = new Dictionary(); + + + if (obj.Iterations is not null) + { + result["iterations"] = obj.Iterations; + } + + + if (obj.Status is not null) + { + result["status"] = obj.Status.Value.ToString().ToLowerInvariant(); + } + + + if (obj.Response is not null) + { + result["response"] = obj.Response; + } + + + if (obj.DurationMs is not null) + { + result["durationMs"] = obj.DurationMs; + } + + + if (context is not null) + { + result = context.ProcessDict(result); + } + + return result; + } + + + /// + /// Convert the TurnEndPayload instance to a YAML string. + /// + /// Optional context with pre/post processing callbacks. + /// The YAML string representation of this instance. + public string ToYaml(SaveContext? context = null) + { + context ??= new SaveContext(); + return context.ToYaml(Save(context)); + } + + /// + /// Convert the TurnEndPayload instance to a JSON string. + /// + /// Optional context with pre/post processing callbacks. + /// Whether to indent the output. Defaults to true. + /// The JSON string representation of this instance. + public string ToJson(SaveContext? context = null, bool indent = true) + { + context ??= new SaveContext(); + return context.ToJson(Save(context), indent); + } + + /// + /// Load a TurnEndPayload instance from a JSON string. + /// + /// The JSON string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded TurnEndPayload instance. + public static TurnEndPayload FromJson(string json, LoadContext? context = null) + { + using var doc = JsonDocument.Parse(json); + Dictionary dict; + dict = JsonSerializer.Deserialize>(json, JsonUtils.Options) + ?? throw new ArgumentException("Failed to parse JSON as dictionary"); + + return Load(dict, context); + } + + /// + /// Load a TurnEndPayload instance from a YAML string. + /// + /// The YAML string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded TurnEndPayload instance. + public static TurnEndPayload FromYaml(string yaml, LoadContext? context = null) + { + var dict = YamlUtils.Deserializer.Deserialize>(yaml) + ?? throw new ArgumentException("Failed to parse YAML as dictionary"); + + return Load(dict, context); + } + + #endregion +} diff --git a/runtime/csharp/Prompty.Core/Model/events/TurnEvent.cs b/runtime/csharp/Prompty.Core/Model/events/TurnEvent.cs new file mode 100644 index 00000000..24378f31 --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/TurnEvent.cs @@ -0,0 +1,262 @@ +// Copyright (c) Microsoft. All rights reserved. +using System.Text.Json; +using YamlDotNet.Serialization; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + +/// +/// A canonical event envelope emitted by the turn harness. The payload is kept +/// +/// JSON-shaped so runtimes can load all events even when newer payload types are +/// +/// added; event-specific typed payload models below define the canonical shapes. +/// +public partial class TurnEvent +{ + /// + /// The shorthand property name for this type, if any. + /// + public static string? ShorthandProperty => null; + + /// + /// Initializes a new instance of . + /// +#pragma warning disable CS8618 + public TurnEvent() + { + } +#pragma warning restore CS8618 + + /// + /// Unique identifier for this event + /// + public string Id { get; set; } = string.Empty; + + /// + /// Event type discriminator + /// + public TurnEventType Type { get; set; } = TurnEventType.TurnStart; + + /// + /// ISO 8601 UTC timestamp when the event was emitted + /// + public string Timestamp { get; set; } = string.Empty; + + /// + /// Stable identifier for the outer turn + /// + public string? TurnId { get; set; } + + /// + /// Zero-based agent-loop iteration associated with the event + /// + public int? Iteration { get; set; } + + /// + /// Parent event or span identifier for reconstructing event hierarchy + /// + public string? ParentId { get; set; } + + /// + /// Trace span identifier associated with this event + /// + public string? SpanId { get; set; } + + /// + /// Event-specific payload. Use the typed payload model matching 'type'. + /// + public IDictionary Payload { get; set; } = new Dictionary(); + + + + #region Load Methods + + /// + /// Load a TurnEvent instance from a dictionary. + /// + /// The dictionary containing the data. + /// Optional context with pre/post processing callbacks. + /// The loaded TurnEvent instance. + public static TurnEvent Load(Dictionary data, LoadContext? context = null) + { + if (context is not null) + { + data = context.ProcessInput(data); + } + + + // Create new instance + var instance = new TurnEvent(); + + + if (data.TryGetValue("id", out var idValue) && idValue is not null) + { + instance.Id = idValue?.ToString()!; + } + + if (data.TryGetValue("type", out var typeValue) && typeValue is not null) + { + instance.Type = Enum.Parse(typeValue?.ToString()!, true); + } + + if (data.TryGetValue("timestamp", out var timestampValue) && timestampValue is not null) + { + instance.Timestamp = timestampValue?.ToString()!; + } + + if (data.TryGetValue("turnId", out var turnIdValue) && turnIdValue is not null) + { + instance.TurnId = turnIdValue?.ToString()!; + } + + if (data.TryGetValue("iteration", out var iterationValue) && iterationValue is not null) + { + instance.Iteration = Convert.ToInt32(iterationValue); + } + + if (data.TryGetValue("parentId", out var parentIdValue) && parentIdValue is not null) + { + instance.ParentId = parentIdValue?.ToString()!; + } + + if (data.TryGetValue("spanId", out var spanIdValue) && spanIdValue is not null) + { + instance.SpanId = spanIdValue?.ToString()!; + } + + if (data.TryGetValue("payload", out var payloadValue) && payloadValue is not null) + { + instance.Payload = payloadValue.GetDictionary()!; + } + + if (context is not null) + { + instance = context.ProcessOutput(instance); + } + return instance; + } + + + #endregion + + #region Save Methods + + /// + /// Save the TurnEvent instance to a dictionary. + /// + /// Optional context with pre/post processing callbacks. + /// The dictionary representation of this instance. + public Dictionary Save(SaveContext? context = null) + { + var obj = this; + if (context is not null) + { + obj = context.ProcessObject(obj); + } + + + var result = new Dictionary(); + + + result["id"] = obj.Id; + + + result["type"] = obj.Type.ToString().ToLowerInvariant(); + + + result["timestamp"] = obj.Timestamp; + + + if (obj.TurnId is not null) + { + result["turnId"] = obj.TurnId; + } + + + if (obj.Iteration is not null) + { + result["iteration"] = obj.Iteration; + } + + + if (obj.ParentId is not null) + { + result["parentId"] = obj.ParentId; + } + + + if (obj.SpanId is not null) + { + result["spanId"] = obj.SpanId; + } + + + result["payload"] = obj.Payload; + + + if (context is not null) + { + result = context.ProcessDict(result); + } + + return result; + } + + + /// + /// Convert the TurnEvent instance to a YAML string. + /// + /// Optional context with pre/post processing callbacks. + /// The YAML string representation of this instance. + public string ToYaml(SaveContext? context = null) + { + context ??= new SaveContext(); + return context.ToYaml(Save(context)); + } + + /// + /// Convert the TurnEvent instance to a JSON string. + /// + /// Optional context with pre/post processing callbacks. + /// Whether to indent the output. Defaults to true. + /// The JSON string representation of this instance. + public string ToJson(SaveContext? context = null, bool indent = true) + { + context ??= new SaveContext(); + return context.ToJson(Save(context), indent); + } + + /// + /// Load a TurnEvent instance from a JSON string. + /// + /// The JSON string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded TurnEvent instance. + public static TurnEvent FromJson(string json, LoadContext? context = null) + { + using var doc = JsonDocument.Parse(json); + Dictionary dict; + dict = JsonSerializer.Deserialize>(json, JsonUtils.Options) + ?? throw new ArgumentException("Failed to parse JSON as dictionary"); + + return Load(dict, context); + } + + /// + /// Load a TurnEvent instance from a YAML string. + /// + /// The YAML string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded TurnEvent instance. + public static TurnEvent FromYaml(string yaml, LoadContext? context = null) + { + var dict = YamlUtils.Deserializer.Deserialize>(yaml) + ?? throw new ArgumentException("Failed to parse YAML as dictionary"); + + return Load(dict, context); + } + + #endregion +} diff --git a/runtime/csharp/Prompty.Core/Model/events/TurnEventType.cs b/runtime/csharp/Prompty.Core/Model/events/TurnEventType.cs new file mode 100644 index 00000000..99bccc9f --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/TurnEventType.cs @@ -0,0 +1,71 @@ +// +// Code generated by Prompty emitter; DO NOT EDIT. + +using System.Text.Json.Serialization; + +namespace Prompty.Core; + +[JsonConverter(typeof(JsonStringEnumConverter))] +public enum TurnEventType +{ + [JsonPropertyName("turn_start")] + TurnStart, + + [JsonPropertyName("turn_end")] + TurnEnd, + + [JsonPropertyName("llm_start")] + LlmStart, + + [JsonPropertyName("llm_complete")] + LlmComplete, + + [JsonPropertyName("retry")] + Retry, + + [JsonPropertyName("permission_requested")] + PermissionRequested, + + [JsonPropertyName("permission_completed")] + PermissionCompleted, + + [JsonPropertyName("token")] + Token, + + [JsonPropertyName("thinking")] + Thinking, + + [JsonPropertyName("tool_call_start")] + ToolCallStart, + + [JsonPropertyName("tool_call_complete")] + ToolCallComplete, + + [JsonPropertyName("tool_result")] + ToolResult, + + [JsonPropertyName("status")] + Status, + + [JsonPropertyName("messages_updated")] + MessagesUpdated, + + [JsonPropertyName("done")] + Done, + + [JsonPropertyName("error")] + Error, + + [JsonPropertyName("cancelled")] + Cancelled, + + [JsonPropertyName("compaction_start")] + CompactionStart, + + [JsonPropertyName("compaction_complete")] + CompactionComplete, + + [JsonPropertyName("compaction_failed")] + CompactionFailed, + +} diff --git a/runtime/csharp/Prompty.Core/Model/events/TurnStartPayload.cs b/runtime/csharp/Prompty.Core/Model/events/TurnStartPayload.cs new file mode 100644 index 00000000..45e59348 --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/TurnStartPayload.cs @@ -0,0 +1,190 @@ +// Copyright (c) Microsoft. All rights reserved. +using System.Text.Json; +using YamlDotNet.Serialization; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + +/// +/// Payload for "turn_start" events — a turn is beginning. +/// +public partial class TurnStartPayload +{ + /// + /// The shorthand property name for this type, if any. + /// + public static string? ShorthandProperty => null; + + /// + /// Initializes a new instance of . + /// +#pragma warning disable CS8618 + public TurnStartPayload() + { + } +#pragma warning restore CS8618 + + /// + /// Name of the loaded prompt/agent, when available + /// + public string? Agent { get; set; } + + /// + /// Input values supplied to the turn after host-side sanitization + /// + public IDictionary? Inputs { get; set; } + + /// + /// Configured maximum tool-call iterations + /// + public int? MaxIterations { get; set; } + + + + #region Load Methods + + /// + /// Load a TurnStartPayload instance from a dictionary. + /// + /// The dictionary containing the data. + /// Optional context with pre/post processing callbacks. + /// The loaded TurnStartPayload instance. + public static TurnStartPayload Load(Dictionary data, LoadContext? context = null) + { + if (context is not null) + { + data = context.ProcessInput(data); + } + + + // Create new instance + var instance = new TurnStartPayload(); + + + if (data.TryGetValue("agent", out var agentValue) && agentValue is not null) + { + instance.Agent = agentValue?.ToString()!; + } + + if (data.TryGetValue("inputs", out var inputsValue) && inputsValue is not null) + { + instance.Inputs = inputsValue.GetDictionary()!; + } + + if (data.TryGetValue("maxIterations", out var maxIterationsValue) && maxIterationsValue is not null) + { + instance.MaxIterations = Convert.ToInt32(maxIterationsValue); + } + + if (context is not null) + { + instance = context.ProcessOutput(instance); + } + return instance; + } + + + #endregion + + #region Save Methods + + /// + /// Save the TurnStartPayload instance to a dictionary. + /// + /// Optional context with pre/post processing callbacks. + /// The dictionary representation of this instance. + public Dictionary Save(SaveContext? context = null) + { + var obj = this; + if (context is not null) + { + obj = context.ProcessObject(obj); + } + + + var result = new Dictionary(); + + + if (obj.Agent is not null) + { + result["agent"] = obj.Agent; + } + + + if (obj.Inputs is not null) + { + result["inputs"] = obj.Inputs; + } + + + if (obj.MaxIterations is not null) + { + result["maxIterations"] = obj.MaxIterations; + } + + + if (context is not null) + { + result = context.ProcessDict(result); + } + + return result; + } + + + /// + /// Convert the TurnStartPayload instance to a YAML string. + /// + /// Optional context with pre/post processing callbacks. + /// The YAML string representation of this instance. + public string ToYaml(SaveContext? context = null) + { + context ??= new SaveContext(); + return context.ToYaml(Save(context)); + } + + /// + /// Convert the TurnStartPayload instance to a JSON string. + /// + /// Optional context with pre/post processing callbacks. + /// Whether to indent the output. Defaults to true. + /// The JSON string representation of this instance. + public string ToJson(SaveContext? context = null, bool indent = true) + { + context ??= new SaveContext(); + return context.ToJson(Save(context), indent); + } + + /// + /// Load a TurnStartPayload instance from a JSON string. + /// + /// The JSON string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded TurnStartPayload instance. + public static TurnStartPayload FromJson(string json, LoadContext? context = null) + { + using var doc = JsonDocument.Parse(json); + Dictionary dict; + dict = JsonSerializer.Deserialize>(json, JsonUtils.Options) + ?? throw new ArgumentException("Failed to parse JSON as dictionary"); + + return Load(dict, context); + } + + /// + /// Load a TurnStartPayload instance from a YAML string. + /// + /// The YAML string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded TurnStartPayload instance. + public static TurnStartPayload FromYaml(string yaml, LoadContext? context = null) + { + var dict = YamlUtils.Deserializer.Deserialize>(yaml) + ?? throw new ArgumentException("Failed to parse YAML as dictionary"); + + return Load(dict, context); + } + + #endregion +} diff --git a/runtime/csharp/Prompty.Core/Model/events/TurnStatus.cs b/runtime/csharp/Prompty.Core/Model/events/TurnStatus.cs new file mode 100644 index 00000000..9e12bed8 --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/TurnStatus.cs @@ -0,0 +1,20 @@ +// +// Code generated by Prompty emitter; DO NOT EDIT. + +using System.Text.Json.Serialization; + +namespace Prompty.Core; + +[JsonConverter(typeof(JsonStringEnumConverter))] +public enum TurnStatus +{ + [JsonPropertyName("success")] + Success, + + [JsonPropertyName("error")] + Error, + + [JsonPropertyName("cancelled")] + Cancelled, + +} diff --git a/runtime/csharp/Prompty.Core/Model/events/TurnSummary.cs b/runtime/csharp/Prompty.Core/Model/events/TurnSummary.cs new file mode 100644 index 00000000..1dd28893 --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/TurnSummary.cs @@ -0,0 +1,261 @@ +// Copyright (c) Microsoft. All rights reserved. +using System.Text.Json; +using YamlDotNet.Serialization; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + +/// +/// Summary statistics for a completed turn trace. +/// +public partial class TurnSummary +{ + /// + /// The shorthand property name for this type, if any. + /// + public static string? ShorthandProperty => null; + + /// + /// Initializes a new instance of . + /// +#pragma warning disable CS8618 + public TurnSummary() + { + } +#pragma warning restore CS8618 + + /// + /// Stable identifier for the outer turn + /// + public string TurnId { get; set; } = string.Empty; + + /// + /// Final turn status: 'success', 'error', or 'cancelled' + /// + public string Status { get; set; } = string.Empty; + + /// + /// Number of agent-loop iterations + /// + public int Iterations { get; set; } + + /// + /// Number of LLM calls made during the turn + /// + public int? LlmCalls { get; set; } + + /// + /// Number of tool calls dispatched during the turn + /// + public int? ToolCalls { get; set; } + + /// + /// Number of retry events during the turn + /// + public int? Retries { get; set; } + + /// + /// Aggregated token usage for the turn + /// + public TokenUsage? Usage { get; set; } + + /// + /// Total elapsed turn duration in milliseconds + /// + public double? DurationMs { get; set; } + + + + #region Load Methods + + /// + /// Load a TurnSummary instance from a dictionary. + /// + /// The dictionary containing the data. + /// Optional context with pre/post processing callbacks. + /// The loaded TurnSummary instance. + public static TurnSummary Load(Dictionary data, LoadContext? context = null) + { + if (context is not null) + { + data = context.ProcessInput(data); + } + + + // Create new instance + var instance = new TurnSummary(); + + + if (data.TryGetValue("turnId", out var turnIdValue) && turnIdValue is not null) + { + instance.TurnId = turnIdValue?.ToString()!; + } + + if (data.TryGetValue("status", out var statusValue) && statusValue is not null) + { + instance.Status = statusValue?.ToString()!; + } + + if (data.TryGetValue("iterations", out var iterationsValue) && iterationsValue is not null) + { + instance.Iterations = Convert.ToInt32(iterationsValue); + } + + if (data.TryGetValue("llmCalls", out var llmCallsValue) && llmCallsValue is not null) + { + instance.LlmCalls = Convert.ToInt32(llmCallsValue); + } + + if (data.TryGetValue("toolCalls", out var toolCallsValue) && toolCallsValue is not null) + { + instance.ToolCalls = Convert.ToInt32(toolCallsValue); + } + + if (data.TryGetValue("retries", out var retriesValue) && retriesValue is not null) + { + instance.Retries = Convert.ToInt32(retriesValue); + } + + if (data.TryGetValue("usage", out var usageValue) && usageValue is not null) + { + instance.Usage = TokenUsage.Load(usageValue.GetDictionary(TokenUsage.ShorthandProperty), context); + } + + if (data.TryGetValue("durationMs", out var durationMsValue) && durationMsValue is not null) + { + instance.DurationMs = Convert.ToDouble(durationMsValue); + } + + if (context is not null) + { + instance = context.ProcessOutput(instance); + } + return instance; + } + + + #endregion + + #region Save Methods + + /// + /// Save the TurnSummary instance to a dictionary. + /// + /// Optional context with pre/post processing callbacks. + /// The dictionary representation of this instance. + public Dictionary Save(SaveContext? context = null) + { + var obj = this; + if (context is not null) + { + obj = context.ProcessObject(obj); + } + + + var result = new Dictionary(); + + + result["turnId"] = obj.TurnId; + + + result["status"] = obj.Status; + + + result["iterations"] = obj.Iterations; + + + if (obj.LlmCalls is not null) + { + result["llmCalls"] = obj.LlmCalls; + } + + + if (obj.ToolCalls is not null) + { + result["toolCalls"] = obj.ToolCalls; + } + + + if (obj.Retries is not null) + { + result["retries"] = obj.Retries; + } + + + if (obj.Usage is not null) + { + result["usage"] = obj.Usage?.Save(context); + } + + + if (obj.DurationMs is not null) + { + result["durationMs"] = obj.DurationMs; + } + + + if (context is not null) + { + result = context.ProcessDict(result); + } + + return result; + } + + + /// + /// Convert the TurnSummary instance to a YAML string. + /// + /// Optional context with pre/post processing callbacks. + /// The YAML string representation of this instance. + public string ToYaml(SaveContext? context = null) + { + context ??= new SaveContext(); + return context.ToYaml(Save(context)); + } + + /// + /// Convert the TurnSummary instance to a JSON string. + /// + /// Optional context with pre/post processing callbacks. + /// Whether to indent the output. Defaults to true. + /// The JSON string representation of this instance. + public string ToJson(SaveContext? context = null, bool indent = true) + { + context ??= new SaveContext(); + return context.ToJson(Save(context), indent); + } + + /// + /// Load a TurnSummary instance from a JSON string. + /// + /// The JSON string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded TurnSummary instance. + public static TurnSummary FromJson(string json, LoadContext? context = null) + { + using var doc = JsonDocument.Parse(json); + Dictionary dict; + dict = JsonSerializer.Deserialize>(json, JsonUtils.Options) + ?? throw new ArgumentException("Failed to parse JSON as dictionary"); + + return Load(dict, context); + } + + /// + /// Load a TurnSummary instance from a YAML string. + /// + /// The YAML string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded TurnSummary instance. + public static TurnSummary FromYaml(string yaml, LoadContext? context = null) + { + var dict = YamlUtils.Deserializer.Deserialize>(yaml) + ?? throw new ArgumentException("Failed to parse YAML as dictionary"); + + return Load(dict, context); + } + + #endregion +} diff --git a/runtime/csharp/Prompty.Core/Model/events/TurnTrace.cs b/runtime/csharp/Prompty.Core/Model/events/TurnTrace.cs new file mode 100644 index 00000000..ab7e8703 --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/TurnTrace.cs @@ -0,0 +1,283 @@ +// Copyright (c) Microsoft. All rights reserved. +using System.Text.Json; +using YamlDotNet.Serialization; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + +/// +/// Portable JSONL/replay container for a recorded turn harness run. +/// +public partial class TurnTrace +{ + /// + /// The shorthand property name for this type, if any. + /// + public static string? ShorthandProperty => null; + + /// + /// Initializes a new instance of . + /// +#pragma warning disable CS8618 + public TurnTrace() + { + } +#pragma warning restore CS8618 + + /// + /// Trace schema version + /// + public string Version { get; set; } = "1"; + + /// + /// Runtime name that produced the trace + /// + public string? Runtime { get; set; } + + /// + /// Prompty library version that produced the trace + /// + public string? PromptyVersion { get; set; } + + /// + /// Recorded turn events in emission order + /// + public IList Events { get; set; } = []; + + /// + /// Optional summary computed from the event stream + /// + public TurnSummary? Summary { get; set; } + + + + #region Load Methods + + /// + /// Load a TurnTrace instance from a dictionary. + /// + /// The dictionary containing the data. + /// Optional context with pre/post processing callbacks. + /// The loaded TurnTrace instance. + public static TurnTrace Load(Dictionary data, LoadContext? context = null) + { + if (context is not null) + { + data = context.ProcessInput(data); + } + + + // Create new instance + var instance = new TurnTrace(); + + + if (data.TryGetValue("version", out var versionValue) && versionValue is not null) + { + instance.Version = versionValue?.ToString()!; + } + + if (data.TryGetValue("runtime", out var runtimeValue) && runtimeValue is not null) + { + instance.Runtime = runtimeValue?.ToString()!; + } + + if (data.TryGetValue("promptyVersion", out var promptyVersionValue) && promptyVersionValue is not null) + { + instance.PromptyVersion = promptyVersionValue?.ToString()!; + } + + if (data.TryGetValue("events", out var eventsValue) && eventsValue is not null) + { + instance.Events = LoadEvents(eventsValue, context); + } + + if (data.TryGetValue("summary", out var summaryValue) && summaryValue is not null) + { + instance.Summary = TurnSummary.Load(summaryValue.GetDictionary(TurnSummary.ShorthandProperty), context); + } + + if (context is not null) + { + instance = context.ProcessOutput(instance); + } + return instance; + } + + + /// + /// Load a list of TurnEvent from a dictionary or list. + /// + public static IList LoadEvents(object data, LoadContext? context) + { + var result = new List(); + + if (data is Dictionary dict) + { + // Convert named dictionary to list + foreach (var kvp in dict) + { + if (kvp.Value is IEnumerable) + { + throw new ArgumentException( + $"Invalid 'events' format: key '{kvp.Key}' has an array value. " + + $"'events' must be a flat list of objects or a name-keyed dict — " + + "not a nested {" + kvp.Key + ": [...]} structure."); + } + var itemDict = kvp.Value.GetDictionary(); + if (itemDict.Count > 0) + { + // Value is an object, add name to it + itemDict["name"] = kvp.Key; + result.Add(TurnEvent.Load(itemDict, context)); + } + else + { + // Value is a scalar, use it as the primary property + var newDict = new Dictionary + { + ["name"] = kvp.Key, + ["id"] = kvp.Value + }; + result.Add(TurnEvent.Load(newDict, context)); + } + } + } + else if (data is IEnumerable list) + { + foreach (var item in list) + { + var itemDict = item.GetDictionary(TurnEvent.ShorthandProperty); + if (itemDict.Count > 0) + { + result.Add(TurnEvent.Load(itemDict, context)); + } + } + } + + return result; + } + + + #endregion + + #region Save Methods + + /// + /// Save the TurnTrace instance to a dictionary. + /// + /// Optional context with pre/post processing callbacks. + /// The dictionary representation of this instance. + public Dictionary Save(SaveContext? context = null) + { + var obj = this; + if (context is not null) + { + obj = context.ProcessObject(obj); + } + + + var result = new Dictionary(); + + + result["version"] = obj.Version; + + + if (obj.Runtime is not null) + { + result["runtime"] = obj.Runtime; + } + + + if (obj.PromptyVersion is not null) + { + result["promptyVersion"] = obj.PromptyVersion; + } + + + result["events"] = SaveEvents(obj.Events, context); + + + if (obj.Summary is not null) + { + result["summary"] = obj.Summary?.Save(context); + } + + + if (context is not null) + { + result = context.ProcessDict(result); + } + + return result; + } + + + /// + /// Save a list of TurnEvent to object or array format. + /// + public static object SaveEvents(IList items, SaveContext? context) + { + context ??= new SaveContext(); + + // This collection type does not have a 'name' property, only array format is supported + return items.Select(item => item.Save(context)).ToList(); + + } + + + /// + /// Convert the TurnTrace instance to a YAML string. + /// + /// Optional context with pre/post processing callbacks. + /// The YAML string representation of this instance. + public string ToYaml(SaveContext? context = null) + { + context ??= new SaveContext(); + return context.ToYaml(Save(context)); + } + + /// + /// Convert the TurnTrace instance to a JSON string. + /// + /// Optional context with pre/post processing callbacks. + /// Whether to indent the output. Defaults to true. + /// The JSON string representation of this instance. + public string ToJson(SaveContext? context = null, bool indent = true) + { + context ??= new SaveContext(); + return context.ToJson(Save(context), indent); + } + + /// + /// Load a TurnTrace instance from a JSON string. + /// + /// The JSON string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded TurnTrace instance. + public static TurnTrace FromJson(string json, LoadContext? context = null) + { + using var doc = JsonDocument.Parse(json); + Dictionary dict; + dict = JsonSerializer.Deserialize>(json, JsonUtils.Options) + ?? throw new ArgumentException("Failed to parse JSON as dictionary"); + + return Load(dict, context); + } + + /// + /// Load a TurnTrace instance from a YAML string. + /// + /// The YAML string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded TurnTrace instance. + public static TurnTrace FromYaml(string yaml, LoadContext? context = null) + { + var dict = YamlUtils.Deserializer.Deserialize>(yaml) + ?? throw new ArgumentException("Failed to parse YAML as dictionary"); + + return Load(dict, context); + } + + #endregion +} diff --git a/runtime/csharp/Prompty.Core/Model/model/Model.cs b/runtime/csharp/Prompty.Core/Model/model/Model.cs index 26ed0117..4aa15d9b 100644 --- a/runtime/csharp/Prompty.Core/Model/model/Model.cs +++ b/runtime/csharp/Prompty.Core/Model/model/Model.cs @@ -8,9 +8,9 @@ namespace Prompty.Core; /// /// Model for defining the structure and behavior of AI agents. -/// +/// /// This model includes properties for specifying the model's provider, connection details, and various options. -/// +/// /// It allows for flexible configuration of AI models to suit different use cases and requirements. /// public partial class Model diff --git a/runtime/csharp/Prompty.Core/Model/model/ModelInfo.cs b/runtime/csharp/Prompty.Core/Model/model/ModelInfo.cs index 14620536..4ff4a573 100644 --- a/runtime/csharp/Prompty.Core/Model/model/ModelInfo.cs +++ b/runtime/csharp/Prompty.Core/Model/model/ModelInfo.cs @@ -8,13 +8,13 @@ namespace Prompty.Core; /// /// Information about a model available from a provider. Used by provider-level -/// +/// /// model discovery to report which models are available and their capabilities. -/// +/// /// Not all providers return all fields — implementations SHOULD populate as -/// +/// /// many fields as the provider's API supports and MAY enrich sparse results -/// +/// /// from a built-in lookup table of known models. /// public partial class ModelInfo diff --git a/runtime/csharp/Prompty.Core/Model/model/TokenUsage.cs b/runtime/csharp/Prompty.Core/Model/model/TokenUsage.cs index ace9cff2..1395b9eb 100644 --- a/runtime/csharp/Prompty.Core/Model/model/TokenUsage.cs +++ b/runtime/csharp/Prompty.Core/Model/model/TokenUsage.cs @@ -8,9 +8,9 @@ namespace Prompty.Core; /// /// Tracks token consumption for a single LLM call. Provider-specific field -/// +/// /// names (e.g., OpenAI's `prompt_tokens` vs Anthropic's `input_tokens`) -/// +/// /// are mapped via `knownAs` augments in the wire directory. /// public partial class TokenUsage diff --git a/runtime/csharp/Prompty.Core/Model/pipeline/CompactionConfig.cs b/runtime/csharp/Prompty.Core/Model/pipeline/CompactionConfig.cs index cd757c3e..ae7cc9b1 100644 --- a/runtime/csharp/Prompty.Core/Model/pipeline/CompactionConfig.cs +++ b/runtime/csharp/Prompty.Core/Model/pipeline/CompactionConfig.cs @@ -8,9 +8,9 @@ namespace Prompty.Core; /// /// Configuration for context window compaction. When the message history -/// +/// /// exceeds the context budget, the compaction strategy is applied to -/// +/// /// reduce the message list while preserving essential information. /// public partial class CompactionConfig diff --git a/runtime/csharp/Prompty.Core/Model/pipeline/Executor.cs b/runtime/csharp/Prompty.Core/Model/pipeline/Executor.cs index 3ed3cd9b..730bbc48 100644 --- a/runtime/csharp/Prompty.Core/Model/pipeline/Executor.cs +++ b/runtime/csharp/Prompty.Core/Model/pipeline/Executor.cs @@ -16,7 +16,7 @@ public interface IExecutor /// /// Call an LLM provider and return a streaming response. Returns a language-specific async iterable/stream of raw chunks. Not all providers support streaming; the default implementation should signal lack of support. /// - Task ExecuteStreamAsync(Prompty agent, List messages) => Task.FromResult(default); + Task ExecuteStreamAsync(Prompty agent, List messages) => Task.FromResult(default!); /// /// Format tool call results into messages for the next iteration /// diff --git a/runtime/csharp/Prompty.Core/Model/pipeline/Parser.cs b/runtime/csharp/Prompty.Core/Model/pipeline/Parser.cs index c70c01fb..a50f65c4 100644 --- a/runtime/csharp/Prompty.Core/Model/pipeline/Parser.cs +++ b/runtime/csharp/Prompty.Core/Model/pipeline/Parser.cs @@ -12,7 +12,7 @@ public interface IParser /// /// Pre-process a template before rendering, returning modified template and context /// - object? PreRender(string template) => default; + object? PreRender(string template) => default!; /// /// Parse rendered text into a structured message array /// diff --git a/runtime/csharp/Prompty.Core/Model/pipeline/Processor.cs b/runtime/csharp/Prompty.Core/Model/pipeline/Processor.cs index c9d42f2d..aa82e37d 100644 --- a/runtime/csharp/Prompty.Core/Model/pipeline/Processor.cs +++ b/runtime/csharp/Prompty.Core/Model/pipeline/Processor.cs @@ -16,5 +16,5 @@ public interface IProcessor /// /// Process a streaming response into a stream of StreamChunk items. Takes raw chunks from the executor and yields processed text, thinking, tool, or error chunks. Not all providers support streaming; the default implementation should signal lack of support. /// - Task ProcessStreamAsync(object stream) => Task.FromResult(default); + Task ProcessStreamAsync(object stream) => Task.FromResult(default!); } diff --git a/runtime/csharp/Prompty.Core/Model/pipeline/TurnOptions.cs b/runtime/csharp/Prompty.Core/Model/pipeline/TurnOptions.cs index 99d25995..5a001022 100644 --- a/runtime/csharp/Prompty.Core/Model/pipeline/TurnOptions.cs +++ b/runtime/csharp/Prompty.Core/Model/pipeline/TurnOptions.cs @@ -8,13 +8,13 @@ namespace Prompty.Core; /// /// Configuration for the agent loop's turn() function. Controls iteration -/// +/// /// limits, retry policy, context management, and execution behavior. -/// +/// /// Runtimes accept these as either a TurnOptions object or individual -/// +/// /// keyword/named parameters — the TypeSpec model defines the canonical -/// +/// /// field set. /// public partial class TurnOptions diff --git a/runtime/csharp/Prompty.Core/Model/streaming/StreamOptions.cs b/runtime/csharp/Prompty.Core/Model/streaming/StreamOptions.cs index 02fb105d..dfccd58e 100644 --- a/runtime/csharp/Prompty.Core/Model/streaming/StreamOptions.cs +++ b/runtime/csharp/Prompty.Core/Model/streaming/StreamOptions.cs @@ -8,7 +8,7 @@ namespace Prompty.Core; /// /// Options controlling streaming behavior for LLM API calls. -/// +/// /// Passed alongside the model options when streaming is enabled. /// public partial class StreamOptions diff --git a/runtime/csharp/Prompty.Core/Model/template/Template.cs b/runtime/csharp/Prompty.Core/Model/template/Template.cs index 2484a19c..b33d35cf 100644 --- a/runtime/csharp/Prompty.Core/Model/template/Template.cs +++ b/runtime/csharp/Prompty.Core/Model/template/Template.cs @@ -8,15 +8,15 @@ namespace Prompty.Core; /// /// Template model for defining prompt templates. -/// +/// /// This model specifies the rendering engine used for slot filling prompts, -/// +/// /// the parser used to process the rendered template into API-compatible format, -/// +/// /// and additional options for the template engine. -/// +/// /// It allows for the creation of reusable templates that can be filled with dynamic data -/// +/// /// and processed to generate prompts for AI models. /// public partial class Template diff --git a/runtime/csharp/Prompty.Core/Model/tools/CustomTool.cs b/runtime/csharp/Prompty.Core/Model/tools/CustomTool.cs index f6cef50c..d7f10e50 100644 --- a/runtime/csharp/Prompty.Core/Model/tools/CustomTool.cs +++ b/runtime/csharp/Prompty.Core/Model/tools/CustomTool.cs @@ -8,13 +8,13 @@ namespace Prompty.Core; /// /// Represents a generic server tool that runs on a server -/// +/// /// This tool kind is designed for operations that require server-side execution -/// +/// /// It may include features such as authentication, data storage, and long-running processes -/// +/// /// This tool kind is ideal for tasks that involve complex computations or access to secure resources -/// +/// /// Server tools can be used to offload heavy processing from client applications /// public partial class CustomTool : Tool diff --git a/runtime/csharp/Prompty.Core/Model/tools/McpApprovalMode.cs b/runtime/csharp/Prompty.Core/Model/tools/McpApprovalMode.cs index de02042f..4379da7b 100644 --- a/runtime/csharp/Prompty.Core/Model/tools/McpApprovalMode.cs +++ b/runtime/csharp/Prompty.Core/Model/tools/McpApprovalMode.cs @@ -8,9 +8,9 @@ namespace Prompty.Core; /// /// The approval mode for MCP server tools. -/// +/// /// When kind is "specify", use alwaysRequireApprovalTools and neverRequireApprovalTools -/// +/// /// to control per-tool approval. For "always" and "never", those fields are ignored. /// public partial class McpApprovalMode diff --git a/runtime/csharp/Prompty.Core/Model/tools/PromptyTool.cs b/runtime/csharp/Prompty.Core/Model/tools/PromptyTool.cs index b621e826..3b9135b5 100644 --- a/runtime/csharp/Prompty.Core/Model/tools/PromptyTool.cs +++ b/runtime/csharp/Prompty.Core/Model/tools/PromptyTool.cs @@ -8,9 +8,9 @@ namespace Prompty.Core; /// /// A tool that references another .prompty file to be invoked as a tool. -/// +/// /// The child prompty is executed as a single prompt invocation. Nested agent -/// +/// /// loops are intentionally not started from PromptyTool. /// public partial class PromptyTool : Tool diff --git a/runtime/csharp/Prompty.Core/Model/tools/ToolContext.cs b/runtime/csharp/Prompty.Core/Model/tools/ToolContext.cs index 7e7e3d72..22d4b9da 100644 --- a/runtime/csharp/Prompty.Core/Model/tools/ToolContext.cs +++ b/runtime/csharp/Prompty.Core/Model/tools/ToolContext.cs @@ -8,9 +8,9 @@ namespace Prompty.Core; /// /// Context passed to tool handlers during agent loop execution. Provides -/// +/// /// access to the agent configuration, current conversation state, and -/// +/// /// arbitrary metadata for tool implementations that need broader context. /// public partial class ToolContext diff --git a/runtime/csharp/Prompty.Core/Model/tools/ToolDispatchResult.cs b/runtime/csharp/Prompty.Core/Model/tools/ToolDispatchResult.cs index 5fa86f43..730411ce 100644 --- a/runtime/csharp/Prompty.Core/Model/tools/ToolDispatchResult.cs +++ b/runtime/csharp/Prompty.Core/Model/tools/ToolDispatchResult.cs @@ -8,9 +8,9 @@ namespace Prompty.Core; /// /// The result of dispatching a single tool call. Pairs the tool call -/// +/// /// identifier with the tool's name and result for correlation in the -/// +/// /// agent loop's message assembly. /// public partial class ToolDispatchResult diff --git a/runtime/csharp/Prompty.Core/Model/tracing/TraceSpan.cs b/runtime/csharp/Prompty.Core/Model/tracing/TraceSpan.cs index 5c7f746f..c7bd178d 100644 --- a/runtime/csharp/Prompty.Core/Model/tracing/TraceSpan.cs +++ b/runtime/csharp/Prompty.Core/Model/tracing/TraceSpan.cs @@ -8,9 +8,9 @@ namespace Prompty.Core; /// /// A single trace span capturing one pipeline stage or function invocation. -/// +/// /// Spans nest via the `__frames` field to form a tree representing the -/// +/// /// full execution (§3.6.1). /// public partial class TraceSpan diff --git a/runtime/csharp/Prompty.Core/Model/wire/AnthropicImageBlock.cs b/runtime/csharp/Prompty.Core/Model/wire/AnthropicImageBlock.cs index cb38ff9f..140d05f8 100644 --- a/runtime/csharp/Prompty.Core/Model/wire/AnthropicImageBlock.cs +++ b/runtime/csharp/Prompty.Core/Model/wire/AnthropicImageBlock.cs @@ -8,7 +8,7 @@ namespace Prompty.Core; /// /// An image content block using base64-encoded data. -/// +/// /// Anthropic requires images as base64 with an explicit media type. /// public partial class AnthropicImageBlock diff --git a/runtime/csharp/Prompty.Core/Model/wire/AnthropicToolDefinition.cs b/runtime/csharp/Prompty.Core/Model/wire/AnthropicToolDefinition.cs index 8ccddd4f..e1aa5ac9 100644 --- a/runtime/csharp/Prompty.Core/Model/wire/AnthropicToolDefinition.cs +++ b/runtime/csharp/Prompty.Core/Model/wire/AnthropicToolDefinition.cs @@ -8,9 +8,9 @@ namespace Prompty.Core; /// /// A tool definition in Anthropic's format. Unlike OpenAI which wraps -/// +/// /// tools in `{type: "function", function: {...}}`, Anthropic uses a -/// +/// /// flat structure with `input_schema` (§7.5). /// public partial class AnthropicToolDefinition diff --git a/runtime/csharp/Prompty.Core/Model/wire/AnthropicToolUseBlock.cs b/runtime/csharp/Prompty.Core/Model/wire/AnthropicToolUseBlock.cs index 74d9e54b..574e8f2e 100644 --- a/runtime/csharp/Prompty.Core/Model/wire/AnthropicToolUseBlock.cs +++ b/runtime/csharp/Prompty.Core/Model/wire/AnthropicToolUseBlock.cs @@ -8,7 +8,7 @@ namespace Prompty.Core; /// /// A tool use content block returned in an assistant message when -/// +/// /// the model wants to invoke a tool. /// public partial class AnthropicToolUseBlock diff --git a/runtime/csharp/Prompty.Core/Model/wire/AnthropicWireMessage.cs b/runtime/csharp/Prompty.Core/Model/wire/AnthropicWireMessage.cs index 5d03e795..4dfe2332 100644 --- a/runtime/csharp/Prompty.Core/Model/wire/AnthropicWireMessage.cs +++ b/runtime/csharp/Prompty.Core/Model/wire/AnthropicWireMessage.cs @@ -8,9 +8,9 @@ namespace Prompty.Core; /// /// A single message in the Anthropic Messages API wire format. -/// +/// /// Anthropic always uses the array-of-blocks form for content, -/// +/// /// even when there is only one text block (§7.5). /// public partial class AnthropicWireMessage diff --git a/runtime/csharp/Prompty.Core/Pipeline.cs b/runtime/csharp/Prompty.Core/Pipeline.cs index 1c5802a9..249beb9c 100644 --- a/runtime/csharp/Prompty.Core/Pipeline.cs +++ b/runtime/csharp/Prompty.Core/Pipeline.cs @@ -10,6 +10,20 @@ namespace Prompty.Core; /// public static class Pipeline { + private static void EmitFailedTurnEnd(EventCallback? onEvent, Exception exception, int iterations, object? response = null) + { + var payload = new Dictionary + { + ["iterations"] = iterations, + ["status"] = exception is OperationCanceledException ? "cancelled" : "error" + }; + if (response is not null) + { + payload["response"] = response; + } + AgentEvents.EmitEvent(onEvent, AgentEventType.TurnEnd, payload); + } + // ----------------------------------------------------------------------- // Input Validation // ----------------------------------------------------------------------- @@ -241,6 +255,13 @@ public static async Task TurnAsync( emit("signature", "prompty.turn"); emit("inputs", new Dictionary { ["agent"] = agent.Name, ["label"] = label, ["maxIterations"] = maxIterations }); var messages = await PrepareAsync(agent, inputs); + AgentEvents.EmitEvent(onEvent, AgentEventType.TurnStart, + new Dictionary + { + ["agent"] = agent.Name, + ["inputs"] = inputs ?? new Dictionary(), + ["maxIterations"] = maxIterations + }); // Simple path: no tools on agent, no user tools, and no agent-loop features → single execute + process var hasAgentTools = agent.Tools is not null && agent.Tools.Count > 0; @@ -248,9 +269,44 @@ public static async Task TurnAsync( var hasAgentFeatures = guardrails is not null || steering is not null || contextBudget is not null; if (!hasAgentTools && !hasUserTools && !hasAgentFeatures) { - var response = await ExecuteAsync(agent, messages); - if (raw) return response; - return await ProcessAsync(agent, response); + AgentEvents.EmitEvent(onEvent, AgentEventType.LlmStart, + new Dictionary + { + ["provider"] = agent.Model?.Provider, + ["modelId"] = agent.Model?.Id, + ["messageCount"] = messages.Count, + ["attempt"] = 0 + }); + object response; + try + { + response = await ExecuteAsync(agent, messages); + } + catch (Exception ex) + { + EmitFailedTurnEnd(onEvent, ex, 0); + throw; + } + AgentEvents.EmitEvent(onEvent, AgentEventType.LlmComplete, new Dictionary()); + if (raw) + { + AgentEvents.EmitEvent(onEvent, AgentEventType.TurnEnd, + new Dictionary { ["iterations"] = 0, ["status"] = "success", ["response"] = response }); + return response; + } + object processed; + try + { + processed = await ProcessAsync(agent, response); + } + catch (Exception ex) + { + EmitFailedTurnEnd(onEvent, ex, 0, response); + throw; + } + AgentEvents.EmitEvent(onEvent, AgentEventType.TurnEnd, + new Dictionary { ["iterations"] = 0, ["status"] = "success", ["response"] = processed }); + return processed; } // Agent loop: execute → check tool_calls → dispatch tools → loop @@ -262,6 +318,7 @@ public static async Task TurnAsync( { if (iteration >= maxIterations) { + EmitFailedTurnEnd(onEvent, new InvalidOperationException("Agent loop exceeded maximum iterations."), iteration); throw new InvalidOperationException( $"Agent loop exceeded maximum iterations ({maxIterations})."); } @@ -275,6 +332,7 @@ public static async Task TurnAsync( { AgentEvents.EmitEvent(onEvent, AgentEventType.Cancelled, new Dictionary { ["iteration"] = iteration, ["reason"] = "cancellation_requested" }); + EmitFailedTurnEnd(onEvent, new OperationCanceledException(), iteration); throw; } @@ -314,6 +372,7 @@ public static async Task TurnAsync( { AgentEvents.EmitEvent(onEvent, AgentEventType.Error, new Dictionary { ["guardrail"] = "input", ["reason"] = inputCheck.Reason }); + EmitFailedTurnEnd(onEvent, new GuardrailError(inputCheck.Reason ?? "Input guardrail denied"), iteration); throw new GuardrailError(inputCheck.Reason ?? "Input guardrail denied"); } if (inputCheck.Rewrite is List rewrittenMessages) @@ -331,29 +390,66 @@ public static async Task TurnAsync( { AgentEvents.EmitEvent(onEvent, AgentEventType.Cancelled, new Dictionary { ["iteration"] = iteration, ["reason"] = "cancelled_before_llm" }); + EmitFailedTurnEnd(onEvent, new OperationCanceledException(), iteration); throw; } AgentEvents.EmitEvent(onEvent, AgentEventType.Status, new Dictionary { ["iteration"] = iteration, ["phase"] = "executing" }); - response2 = await InvokeWithRetryAsync(agent, messages, maxLlmRetries, onEvent, cancellationToken); + AgentEvents.EmitEvent(onEvent, AgentEventType.LlmStart, + new Dictionary + { + ["provider"] = agent.Model?.Provider, + ["modelId"] = agent.Model?.Id, + ["messageCount"] = messages.Count, + ["attempt"] = 0, + ["iteration"] = iteration + }); + try + { + response2 = await InvokeWithRetryAsync(agent, messages, maxLlmRetries, onEvent, cancellationToken); + } + catch (Exception ex) + { + EmitFailedTurnEnd(onEvent, ex, iteration); + throw; + } + AgentEvents.EmitEvent(onEvent, AgentEventType.LlmComplete, + new Dictionary { ["iteration"] = iteration }); // If response is a stream, consume it fully before processing. if (response2 is PromptyStream stream) { - await foreach (var chunk in stream) + try { - if (chunk is string tokenText && tokenText.Length > 0) + await foreach (var chunk in stream) { - AgentEvents.EmitEvent(onEvent, AgentEventType.Token, - new Dictionary { ["token"] = tokenText }); + if (chunk is string tokenText && tokenText.Length > 0) + { + AgentEvents.EmitEvent(onEvent, AgentEventType.Token, + new Dictionary { ["token"] = tokenText }); + } } } + catch (Exception ex) + { + EmitFailedTurnEnd(onEvent, ex, iteration, response2); + throw; + } response2 = stream; } - var result = raw ? response2! : await ProcessAsync(agent, response2!); + object result; + try + { + result = raw ? response2! : await ProcessAsync(agent, response2!); + } + catch (Exception ex) + { + EmitFailedTurnEnd(onEvent, ex, iteration, response2); + throw; + } if (result is ToolCallResult toolResult && toolResult.ToolCalls.Count > 0) { @@ -379,6 +475,8 @@ public static async Task TurnAsync( var deniedMsg = $"Tool denied by guardrail: {toolCheck.Reason}"; AgentEvents.EmitEvent(onEvent, AgentEventType.ToolResult, new Dictionary { ["tool"] = call.Name, ["result"] = deniedMsg }); + AgentEvents.EmitEvent(onEvent, AgentEventType.ToolCallComplete, + new Dictionary { ["name"] = call.Name, ["success"] = false, ["result"] = deniedMsg, ["errorKind"] = "guardrail_denied" }); tasks.Add(Task.FromResult((capturedIndex, deniedMsg))); continue; } @@ -393,6 +491,7 @@ public static async Task TurnAsync( tasks.Add(Task.Run(async () => { + var toolStarted = DateTimeOffset.UtcNow; string toolResponse; try { @@ -408,11 +507,29 @@ public static async Task TurnAsync( AgentEvents.EmitEvent(onEvent, AgentEventType.Error, new Dictionary { ["tool"] = call.Name, ["error"] = ex.Message }); } + AgentEvents.EmitEvent(onEvent, AgentEventType.ToolCallComplete, + new Dictionary + { + ["name"] = call.Name, + ["success"] = !toolResponse.StartsWith("Error:", StringComparison.Ordinal), + ["result"] = toolResponse, + ["durationMs"] = (DateTimeOffset.UtcNow - toolStarted).TotalMilliseconds, + ["errorKind"] = toolResponse.StartsWith("Error:", StringComparison.Ordinal) ? "tool_error" : null + }); return (capturedIndex, toolResponse); })); } - var completed = await Task.WhenAll(tasks); + (int Index, string Result)[] completed; + try + { + completed = await Task.WhenAll(tasks); + } + catch (Exception ex) + { + EmitFailedTurnEnd(onEvent, ex, iteration); + throw; + } // Maintain order var ordered = new string[toolResult.ToolCalls.Count]; foreach (var (index, res) in completed) @@ -442,6 +559,8 @@ public static async Task TurnAsync( var deniedMsg = $"Tool denied by guardrail: {toolCheck.Reason}"; AgentEvents.EmitEvent(onEvent, AgentEventType.ToolResult, new Dictionary { ["tool"] = call.Name, ["result"] = deniedMsg }); + AgentEvents.EmitEvent(onEvent, AgentEventType.ToolCallComplete, + new Dictionary { ["name"] = call.Name, ["success"] = false, ["result"] = deniedMsg, ["errorKind"] = "guardrail_denied" }); toolResults.Add(deniedMsg); continue; } @@ -454,6 +573,7 @@ public static async Task TurnAsync( AgentEvents.EmitEvent(onEvent, AgentEventType.ToolCallStart, new Dictionary { ["tool"] = call.Name, ["arguments"] = call.Arguments }); + var toolStarted = DateTimeOffset.UtcNow; string toolResponse; try { @@ -469,16 +589,39 @@ public static async Task TurnAsync( AgentEvents.EmitEvent(onEvent, AgentEventType.Error, new Dictionary { ["tool"] = call.Name, ["error"] = ex.Message }); } + catch (OperationCanceledException ex) + { + EmitFailedTurnEnd(onEvent, ex, iteration); + throw; + } toolResults.Add(toolResponse); AgentEvents.EmitEvent(onEvent, AgentEventType.ToolResult, new Dictionary { ["tool"] = call.Name, ["result"] = toolResponse }); + AgentEvents.EmitEvent(onEvent, AgentEventType.ToolCallComplete, + new Dictionary + { + ["name"] = call.Name, + ["success"] = !toolResponse.StartsWith("Error:", StringComparison.Ordinal), + ["result"] = toolResponse, + ["durationMs"] = (DateTimeOffset.UtcNow - toolStarted).TotalMilliseconds, + ["errorKind"] = toolResponse.StartsWith("Error:", StringComparison.Ordinal) ? "tool_error" : null + }); } } // Delegate message formatting to the executor (provider-specific) - var toolMessages = executor.FormatToolMessages( - response2, toolResult.ToolCalls, toolResults, toolResult.Content); + List toolMessages; + try + { + toolMessages = executor.FormatToolMessages( + response2, toolResult.ToolCalls, toolResults, toolResult.Content); + } + catch (Exception ex) + { + EmitFailedTurnEnd(onEvent, ex, iteration, response2); + throw; + } messages.AddRange(toolMessages); AgentEvents.EmitEvent(onEvent, AgentEventType.MessagesUpdated, @@ -510,6 +653,7 @@ public static async Task TurnAsync( { AgentEvents.EmitEvent(onEvent, AgentEventType.Error, new Dictionary { ["guardrail"] = "output", ["reason"] = outputCheck.Reason }); + EmitFailedTurnEnd(onEvent, new GuardrailError(outputCheck.Reason ?? "Output guardrail denied"), iteration + 1, result); throw new GuardrailError(outputCheck.Reason ?? "Output guardrail denied"); } if (outputCheck.Rewrite is not null) @@ -520,6 +664,8 @@ public static async Task TurnAsync( AgentEvents.EmitEvent(onEvent, AgentEventType.Done, new Dictionary { ["iterations"] = iteration + 1 }); + AgentEvents.EmitEvent(onEvent, AgentEventType.TurnEnd, + new Dictionary { ["iterations"] = iteration + 1, ["status"] = "success", ["response"] = result }); return result!; } @@ -713,6 +859,14 @@ private static async Task InvokeWithRetryAsync( { ["message"] = $"LLM call failed, retrying (attempt {attempts + 1}/{maxRetries})..." }); + AgentEvents.EmitEvent(onEvent, AgentEventType.Retry, + new Dictionary + { + ["operation"] = "llm", + ["attempt"] = attempts + 1, + ["maxAttempts"] = maxRetries, + ["reason"] = ex.Message + }); // Exponential backoff with jitter, capped at 60s var backoff = Math.Min(Math.Pow(2, attempts) + Random.Shared.NextDouble(), 60); diff --git a/runtime/go/prompty/model/compaction_complete_payload.go b/runtime/go/prompty/model/compaction_complete_payload.go index 09657dcb..200fc406 100644 --- a/runtime/go/prompty/model/compaction_complete_payload.go +++ b/runtime/go/prompty/model/compaction_complete_payload.go @@ -12,8 +12,9 @@ import ( // CompactionCompletePayload represents Payload for "compaction_complete" events — context compaction finished. type CompactionCompletePayload struct { - Removed int32 `json:"removed" yaml:"removed"` - Remaining int32 `json:"remaining" yaml:"remaining"` + Removed int32 `json:"removed" yaml:"removed"` + Remaining int32 `json:"remaining" yaml:"remaining"` + SummaryLength *int32 `json:"summaryLength,omitempty" yaml:"summaryLength,omitempty"` } // LoadCompactionCompletePayload creates a CompactionCompletePayload from a map[string]interface{} @@ -50,6 +51,20 @@ func LoadCompactionCompletePayload(data interface{}, ctx *LoadContext) (Compacti } result.Remaining = v } + if val, ok := m["summaryLength"]; ok && val != nil { // Handle various numeric types from JSON/YAML/roundtrip + var v int32 + switch n := val.(type) { + case int: + v = int32(n) + case int32: + v = int32(n) + case int64: + v = int32(n) + case float64: + v = int32(n) + } + result.SummaryLength = &v + } } return result, nil @@ -60,6 +75,9 @@ func (obj *CompactionCompletePayload) Save(ctx *SaveContext) map[string]interfac result := make(map[string]interface{}) result["removed"] = obj.Removed result["remaining"] = obj.Remaining + if obj.SummaryLength != nil { + result["summaryLength"] = *obj.SummaryLength + } return result } diff --git a/runtime/go/prompty/model/compaction_complete_payload_test.go b/runtime/go/prompty/model/compaction_complete_payload_test.go index c189204b..48857482 100644 --- a/runtime/go/prompty/model/compaction_complete_payload_test.go +++ b/runtime/go/prompty/model/compaction_complete_payload_test.go @@ -16,7 +16,8 @@ func TestCompactionCompletePayloadLoadJSON(t *testing.T) { jsonData := ` { "removed": 5, - "remaining": 3 + "remaining": 3, + "summaryLength": 1200 } ` var data map[string]interface{} @@ -35,6 +36,9 @@ func TestCompactionCompletePayloadLoadJSON(t *testing.T) { if instance.Remaining != 3 { t.Errorf(`Expected Remaining to be 3, got %v`, instance.Remaining) } + if instance.SummaryLength == nil || *instance.SummaryLength != 1200 { + t.Errorf(`Expected SummaryLength to be 1200, got %v`, instance.SummaryLength) + } } // TestCompactionCompletePayloadLoadYAML tests loading CompactionCompletePayload from YAML @@ -42,6 +46,7 @@ func TestCompactionCompletePayloadLoadYAML(t *testing.T) { yamlData := ` removed: 5 remaining: 3 +summaryLength: 1200 ` var data map[string]interface{} @@ -60,6 +65,9 @@ remaining: 3 if instance.Remaining != 3 { t.Errorf(`Expected Remaining to be 3, got %v`, instance.Remaining) } + if instance.SummaryLength == nil || *instance.SummaryLength != 1200 { + t.Errorf(`Expected SummaryLength to be 1200, got %v`, instance.SummaryLength) + } } // TestCompactionCompletePayloadRoundtrip tests load -> save -> load produces equivalent data @@ -67,7 +75,8 @@ func TestCompactionCompletePayloadRoundtrip(t *testing.T) { jsonData := ` { "removed": 5, - "remaining": 3 + "remaining": 3, + "summaryLength": 1200 } ` var data map[string]interface{} @@ -93,6 +102,9 @@ func TestCompactionCompletePayloadRoundtrip(t *testing.T) { if reloaded.Remaining != 3 { t.Errorf(`Expected Remaining to be 3, got %v`, reloaded.Remaining) } + if reloaded.SummaryLength == nil || *reloaded.SummaryLength != 1200 { + t.Errorf(`Expected SummaryLength to be 1200, got %v`, reloaded.SummaryLength) + } } // TestCompactionCompletePayloadToJSON tests that ToJSON produces valid JSON @@ -100,7 +112,8 @@ func TestCompactionCompletePayloadToJSON(t *testing.T) { jsonData := ` { "removed": 5, - "remaining": 3 + "remaining": 3, + "summaryLength": 1200 } ` var data map[string]interface{} @@ -129,7 +142,8 @@ func TestCompactionCompletePayloadToYAML(t *testing.T) { jsonData := ` { "removed": 5, - "remaining": 3 + "remaining": 3, + "summaryLength": 1200 } ` var data map[string]interface{} diff --git a/runtime/go/prompty/model/compaction_start_payload.go b/runtime/go/prompty/model/compaction_start_payload.go new file mode 100644 index 00000000..9bb287ef --- /dev/null +++ b/runtime/go/prompty/model/compaction_start_payload.go @@ -0,0 +1,91 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: events + +package prompty + +import ( + "encoding/json" + + "gopkg.in/yaml.v3" +) + +// CompactionStartPayload represents Payload for "compaction_start" events — context compaction is beginning. + +type CompactionStartPayload struct { + DroppedCount int32 `json:"droppedCount" yaml:"droppedCount"` +} + +// LoadCompactionStartPayload creates a CompactionStartPayload from a map[string]interface{} +func LoadCompactionStartPayload(data interface{}, ctx *LoadContext) (CompactionStartPayload, error) { + result := CompactionStartPayload{} + + // Load from map + if m, ok := data.(map[string]interface{}); ok { + if val, ok := m["droppedCount"]; ok && val != nil { // Handle various numeric types from JSON/YAML/roundtrip + var v int32 + switch n := val.(type) { + case int: + v = int32(n) + case int32: + v = int32(n) + case int64: + v = int32(n) + case float64: + v = int32(n) + } + result.DroppedCount = v + } + } + + return result, nil +} + +// Save serializes CompactionStartPayload to map[string]interface{} +func (obj *CompactionStartPayload) Save(ctx *SaveContext) map[string]interface{} { + result := make(map[string]interface{}) + result["droppedCount"] = obj.DroppedCount + + return result +} + +// ToJSON serializes CompactionStartPayload to JSON string +func (obj *CompactionStartPayload) ToJSON() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := json.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// ToYAML serializes CompactionStartPayload to YAML string +func (obj *CompactionStartPayload) ToYAML() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := yaml.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// FromJSON creates CompactionStartPayload from JSON string +func CompactionStartPayloadFromJSON(jsonStr string) (CompactionStartPayload, error) { + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { + return CompactionStartPayload{}, err + } + ctx := NewLoadContext() + return LoadCompactionStartPayload(data, ctx) +} + +// FromYAML creates CompactionStartPayload from YAML string +func CompactionStartPayloadFromYAML(yamlStr string) (CompactionStartPayload, error) { + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlStr), &data); err != nil { + return CompactionStartPayload{}, err + } + ctx := NewLoadContext() + return LoadCompactionStartPayload(data, ctx) +} diff --git a/runtime/go/prompty/model/compaction_start_payload_test.go b/runtime/go/prompty/model/compaction_start_payload_test.go new file mode 100644 index 00000000..5864f038 --- /dev/null +++ b/runtime/go/prompty/model/compaction_start_payload_test.go @@ -0,0 +1,140 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +package prompty_test + +import ( + "encoding/json" + "testing" + + "gopkg.in/yaml.v3" + + "prompty/model" +) + +// TestCompactionStartPayloadLoadJSON tests loading CompactionStartPayload from JSON +func TestCompactionStartPayloadLoadJSON(t *testing.T) { + jsonData := ` +{ + "droppedCount": 5 +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadCompactionStartPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load CompactionStartPayload: %v", err) + } + if instance.DroppedCount != 5 { + t.Errorf(`Expected DroppedCount to be 5, got %v`, instance.DroppedCount) + } +} + +// TestCompactionStartPayloadLoadYAML tests loading CompactionStartPayload from YAML +func TestCompactionStartPayloadLoadYAML(t *testing.T) { + yamlData := ` +droppedCount: 5 + +` + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlData), &data); err != nil { + t.Fatalf("Failed to parse YAML: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadCompactionStartPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load CompactionStartPayload: %v", err) + } + if instance.DroppedCount != 5 { + t.Errorf(`Expected DroppedCount to be 5, got %v`, instance.DroppedCount) + } +} + +// TestCompactionStartPayloadRoundtrip tests load -> save -> load produces equivalent data +func TestCompactionStartPayloadRoundtrip(t *testing.T) { + jsonData := ` +{ + "droppedCount": 5 +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + loadCtx := prompty.NewLoadContext() + instance, err := prompty.LoadCompactionStartPayload(data, loadCtx) + if err != nil { + t.Fatalf("Failed to load CompactionStartPayload: %v", err) + } + saveCtx := prompty.NewSaveContext() + savedData := instance.Save(saveCtx) + + reloaded, err := prompty.LoadCompactionStartPayload(savedData, loadCtx) + if err != nil { + t.Fatalf("Failed to reload CompactionStartPayload: %v", err) + } + if reloaded.DroppedCount != 5 { + t.Errorf(`Expected DroppedCount to be 5, got %v`, reloaded.DroppedCount) + } +} + +// TestCompactionStartPayloadToJSON tests that ToJSON produces valid JSON +func TestCompactionStartPayloadToJSON(t *testing.T) { + jsonData := ` +{ + "droppedCount": 5 +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadCompactionStartPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load CompactionStartPayload: %v", err) + } + jsonOutput, err := instance.ToJSON() + if err != nil { + t.Fatalf("Failed to convert to JSON: %v", err) + } + + var parsed map[string]interface{} + if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated JSON: %v", err) + } +} + +// TestCompactionStartPayloadToYAML tests that ToYAML produces valid YAML +func TestCompactionStartPayloadToYAML(t *testing.T) { + jsonData := ` +{ + "droppedCount": 5 +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadCompactionStartPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load CompactionStartPayload: %v", err) + } + yamlOutput, err := instance.ToYAML() + if err != nil { + t.Fatalf("Failed to convert to YAML: %v", err) + } + + var parsed map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated YAML: %v", err) + } +} diff --git a/runtime/go/prompty/model/done_event_payload.go b/runtime/go/prompty/model/done_event_payload.go index 00eae878..ec35cdb0 100644 --- a/runtime/go/prompty/model/done_event_payload.go +++ b/runtime/go/prompty/model/done_event_payload.go @@ -12,8 +12,8 @@ import ( // DoneEventPayload represents Payload for "done" events — the agent loop completed successfully. type DoneEventPayload struct { - Response string `json:"response" yaml:"response"` - Messages []Message `json:"messages" yaml:"messages"` + Response interface{} `json:"response" yaml:"response"` + Messages []Message `json:"messages" yaml:"messages"` } // LoadDoneEventPayload creates a DoneEventPayload from a map[string]interface{} @@ -23,7 +23,7 @@ func LoadDoneEventPayload(data interface{}, ctx *LoadContext) (DoneEventPayload, // Load from map if m, ok := data.(map[string]interface{}); ok { if val, ok := m["response"]; ok && val != nil { - result.Response = string(val.(string)) + result.Response = val } if val, ok := m["messages"]; ok && val != nil { if arr, ok := val.([]interface{}); ok { diff --git a/runtime/go/prompty/model/done_event_payload_test.go b/runtime/go/prompty/model/done_event_payload_test.go index 08fabf2f..3df1459b 100644 --- a/runtime/go/prompty/model/done_event_payload_test.go +++ b/runtime/go/prompty/model/done_event_payload_test.go @@ -1,140 +1,3 @@ // Code generated by Prompty emitter; DO NOT EDIT. package prompty_test - -import ( - "encoding/json" - "testing" - - "gopkg.in/yaml.v3" - - "prompty/model" -) - -// TestDoneEventPayloadLoadJSON tests loading DoneEventPayload from JSON -func TestDoneEventPayloadLoadJSON(t *testing.T) { - jsonData := ` -{ - "response": "The weather in Paris is 72°F and sunny." -} -` - var data map[string]interface{} - if err := json.Unmarshal([]byte(jsonData), &data); err != nil { - t.Fatalf("Failed to parse JSON: %v", err) - } - - ctx := prompty.NewLoadContext() - instance, err := prompty.LoadDoneEventPayload(data, ctx) - if err != nil { - t.Fatalf("Failed to load DoneEventPayload: %v", err) - } - if instance.Response != "The weather in Paris is 72°F and sunny." { - t.Errorf(`Expected Response to be "The weather in Paris is 72°F and sunny.", got %v`, instance.Response) - } -} - -// TestDoneEventPayloadLoadYAML tests loading DoneEventPayload from YAML -func TestDoneEventPayloadLoadYAML(t *testing.T) { - yamlData := ` -response: The weather in Paris is 72°F and sunny. - -` - var data map[string]interface{} - if err := yaml.Unmarshal([]byte(yamlData), &data); err != nil { - t.Fatalf("Failed to parse YAML: %v", err) - } - - ctx := prompty.NewLoadContext() - instance, err := prompty.LoadDoneEventPayload(data, ctx) - if err != nil { - t.Fatalf("Failed to load DoneEventPayload: %v", err) - } - if instance.Response != "The weather in Paris is 72°F and sunny." { - t.Errorf(`Expected Response to be "The weather in Paris is 72°F and sunny.", got %v`, instance.Response) - } -} - -// TestDoneEventPayloadRoundtrip tests load -> save -> load produces equivalent data -func TestDoneEventPayloadRoundtrip(t *testing.T) { - jsonData := ` -{ - "response": "The weather in Paris is 72°F and sunny." -} -` - var data map[string]interface{} - if err := json.Unmarshal([]byte(jsonData), &data); err != nil { - t.Fatalf("Failed to parse JSON: %v", err) - } - - loadCtx := prompty.NewLoadContext() - instance, err := prompty.LoadDoneEventPayload(data, loadCtx) - if err != nil { - t.Fatalf("Failed to load DoneEventPayload: %v", err) - } - saveCtx := prompty.NewSaveContext() - savedData := instance.Save(saveCtx) - - reloaded, err := prompty.LoadDoneEventPayload(savedData, loadCtx) - if err != nil { - t.Fatalf("Failed to reload DoneEventPayload: %v", err) - } - if reloaded.Response != "The weather in Paris is 72°F and sunny." { - t.Errorf(`Expected Response to be "The weather in Paris is 72°F and sunny.", got %v`, reloaded.Response) - } -} - -// TestDoneEventPayloadToJSON tests that ToJSON produces valid JSON -func TestDoneEventPayloadToJSON(t *testing.T) { - jsonData := ` -{ - "response": "The weather in Paris is 72°F and sunny." -} -` - var data map[string]interface{} - if err := json.Unmarshal([]byte(jsonData), &data); err != nil { - t.Fatalf("Failed to parse JSON: %v", err) - } - - ctx := prompty.NewLoadContext() - instance, err := prompty.LoadDoneEventPayload(data, ctx) - if err != nil { - t.Fatalf("Failed to load DoneEventPayload: %v", err) - } - jsonOutput, err := instance.ToJSON() - if err != nil { - t.Fatalf("Failed to convert to JSON: %v", err) - } - - var parsed map[string]interface{} - if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { - t.Fatalf("Failed to parse generated JSON: %v", err) - } -} - -// TestDoneEventPayloadToYAML tests that ToYAML produces valid YAML -func TestDoneEventPayloadToYAML(t *testing.T) { - jsonData := ` -{ - "response": "The weather in Paris is 72°F and sunny." -} -` - var data map[string]interface{} - if err := json.Unmarshal([]byte(jsonData), &data); err != nil { - t.Fatalf("Failed to parse JSON: %v", err) - } - - ctx := prompty.NewLoadContext() - instance, err := prompty.LoadDoneEventPayload(data, ctx) - if err != nil { - t.Fatalf("Failed to load DoneEventPayload: %v", err) - } - yamlOutput, err := instance.ToYAML() - if err != nil { - t.Fatalf("Failed to convert to YAML: %v", err) - } - - var parsed map[string]interface{} - if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { - t.Fatalf("Failed to parse generated YAML: %v", err) - } -} diff --git a/runtime/go/prompty/model/error_event_payload.go b/runtime/go/prompty/model/error_event_payload.go index 9e3dd0d0..225b7eca 100644 --- a/runtime/go/prompty/model/error_event_payload.go +++ b/runtime/go/prompty/model/error_event_payload.go @@ -12,7 +12,9 @@ import ( // ErrorEventPayload represents Payload for "error" events — an error occurred during the loop. type ErrorEventPayload struct { - Message string `json:"message" yaml:"message"` + Message string `json:"message" yaml:"message"` + ErrorKind *string `json:"errorKind,omitempty" yaml:"errorKind,omitempty"` + Phase *string `json:"phase,omitempty" yaml:"phase,omitempty"` } // LoadErrorEventPayload creates a ErrorEventPayload from a map[string]interface{} @@ -24,6 +26,14 @@ func LoadErrorEventPayload(data interface{}, ctx *LoadContext) (ErrorEventPayloa if val, ok := m["message"]; ok && val != nil { result.Message = string(val.(string)) } + if val, ok := m["errorKind"]; ok && val != nil { + v := string(val.(string)) + result.ErrorKind = &v + } + if val, ok := m["phase"]; ok && val != nil { + v := string(val.(string)) + result.Phase = &v + } } return result, nil @@ -33,6 +43,12 @@ func LoadErrorEventPayload(data interface{}, ctx *LoadContext) (ErrorEventPayloa func (obj *ErrorEventPayload) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["message"] = obj.Message + if obj.ErrorKind != nil { + result["errorKind"] = *obj.ErrorKind + } + if obj.Phase != nil { + result["phase"] = *obj.Phase + } return result } diff --git a/runtime/go/prompty/model/error_event_payload_test.go b/runtime/go/prompty/model/error_event_payload_test.go index b1f93ef5..fa37d308 100644 --- a/runtime/go/prompty/model/error_event_payload_test.go +++ b/runtime/go/prompty/model/error_event_payload_test.go @@ -15,7 +15,9 @@ import ( func TestErrorEventPayloadLoadJSON(t *testing.T) { jsonData := ` { - "message": "Rate limit exceeded" + "message": "Rate limit exceeded", + "errorKind": "rate_limit", + "phase": "llm" } ` var data map[string]interface{} @@ -31,12 +33,20 @@ func TestErrorEventPayloadLoadJSON(t *testing.T) { if instance.Message != "Rate limit exceeded" { t.Errorf(`Expected Message to be "Rate limit exceeded", got %v`, instance.Message) } + if instance.ErrorKind == nil || *instance.ErrorKind != "rate_limit" { + t.Errorf(`Expected ErrorKind to be "rate_limit", got %v`, instance.ErrorKind) + } + if instance.Phase == nil || *instance.Phase != "llm" { + t.Errorf(`Expected Phase to be "llm", got %v`, instance.Phase) + } } // TestErrorEventPayloadLoadYAML tests loading ErrorEventPayload from YAML func TestErrorEventPayloadLoadYAML(t *testing.T) { yamlData := ` message: Rate limit exceeded +errorKind: rate_limit +phase: llm ` var data map[string]interface{} @@ -52,13 +62,21 @@ message: Rate limit exceeded if instance.Message != "Rate limit exceeded" { t.Errorf(`Expected Message to be "Rate limit exceeded", got %v`, instance.Message) } + if instance.ErrorKind == nil || *instance.ErrorKind != "rate_limit" { + t.Errorf(`Expected ErrorKind to be "rate_limit", got %v`, instance.ErrorKind) + } + if instance.Phase == nil || *instance.Phase != "llm" { + t.Errorf(`Expected Phase to be "llm", got %v`, instance.Phase) + } } // TestErrorEventPayloadRoundtrip tests load -> save -> load produces equivalent data func TestErrorEventPayloadRoundtrip(t *testing.T) { jsonData := ` { - "message": "Rate limit exceeded" + "message": "Rate limit exceeded", + "errorKind": "rate_limit", + "phase": "llm" } ` var data map[string]interface{} @@ -81,13 +99,21 @@ func TestErrorEventPayloadRoundtrip(t *testing.T) { if reloaded.Message != "Rate limit exceeded" { t.Errorf(`Expected Message to be "Rate limit exceeded", got %v`, reloaded.Message) } + if reloaded.ErrorKind == nil || *reloaded.ErrorKind != "rate_limit" { + t.Errorf(`Expected ErrorKind to be "rate_limit", got %v`, reloaded.ErrorKind) + } + if reloaded.Phase == nil || *reloaded.Phase != "llm" { + t.Errorf(`Expected Phase to be "llm", got %v`, reloaded.Phase) + } } // TestErrorEventPayloadToJSON tests that ToJSON produces valid JSON func TestErrorEventPayloadToJSON(t *testing.T) { jsonData := ` { - "message": "Rate limit exceeded" + "message": "Rate limit exceeded", + "errorKind": "rate_limit", + "phase": "llm" } ` var data map[string]interface{} @@ -115,7 +141,9 @@ func TestErrorEventPayloadToJSON(t *testing.T) { func TestErrorEventPayloadToYAML(t *testing.T) { jsonData := ` { - "message": "Rate limit exceeded" + "message": "Rate limit exceeded", + "errorKind": "rate_limit", + "phase": "llm" } ` var data map[string]interface{} diff --git a/runtime/go/prompty/model/llm_complete_payload.go b/runtime/go/prompty/model/llm_complete_payload.go new file mode 100644 index 00000000..ec4bc18c --- /dev/null +++ b/runtime/go/prompty/model/llm_complete_payload.go @@ -0,0 +1,121 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: events + +package prompty + +import ( + "encoding/json" + + "gopkg.in/yaml.v3" +) + +// LlmCompletePayload represents Payload for "llm_complete" events — an LLM request completed. + +type LlmCompletePayload struct { + RequestId *string `json:"requestId,omitempty" yaml:"requestId,omitempty"` + ServiceRequestId *string `json:"serviceRequestId,omitempty" yaml:"serviceRequestId,omitempty"` + Usage *TokenUsage `json:"usage,omitempty" yaml:"usage,omitempty"` + DurationMs *float64 `json:"durationMs,omitempty" yaml:"durationMs,omitempty"` +} + +// LoadLlmCompletePayload creates a LlmCompletePayload from a map[string]interface{} +func LoadLlmCompletePayload(data interface{}, ctx *LoadContext) (LlmCompletePayload, error) { + result := LlmCompletePayload{} + + // Load from map + if m, ok := data.(map[string]interface{}); ok { + if val, ok := m["requestId"]; ok && val != nil { + v := string(val.(string)) + result.RequestId = &v + } + if val, ok := m["serviceRequestId"]; ok && val != nil { + v := string(val.(string)) + result.ServiceRequestId = &v + } + if val, ok := m["usage"]; ok && val != nil { + if m, ok := val.(map[string]interface{}); ok { + loaded, _ := LoadTokenUsage(m, ctx) + result.Usage = &loaded + } + } + if val, ok := m["durationMs"]; ok && val != nil { // Handle various numeric types from JSON/YAML/roundtrip + var v float64 + switch n := val.(type) { + case int: + v = float64(n) + case int32: + v = float64(n) + case int64: + v = float64(n) + case float32: + v = float64(n) + case float64: + v = n + } + result.DurationMs = &v + } + } + + return result, nil +} + +// Save serializes LlmCompletePayload to map[string]interface{} +func (obj *LlmCompletePayload) Save(ctx *SaveContext) map[string]interface{} { + result := make(map[string]interface{}) + if obj.RequestId != nil { + result["requestId"] = *obj.RequestId + } + if obj.ServiceRequestId != nil { + result["serviceRequestId"] = *obj.ServiceRequestId + } + if obj.Usage != nil { + result["usage"] = obj.Usage.Save(ctx) + } + if obj.DurationMs != nil { + result["durationMs"] = *obj.DurationMs + } + + return result +} + +// ToJSON serializes LlmCompletePayload to JSON string +func (obj *LlmCompletePayload) ToJSON() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := json.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// ToYAML serializes LlmCompletePayload to YAML string +func (obj *LlmCompletePayload) ToYAML() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := yaml.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// FromJSON creates LlmCompletePayload from JSON string +func LlmCompletePayloadFromJSON(jsonStr string) (LlmCompletePayload, error) { + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { + return LlmCompletePayload{}, err + } + ctx := NewLoadContext() + return LoadLlmCompletePayload(data, ctx) +} + +// FromYAML creates LlmCompletePayload from YAML string +func LlmCompletePayloadFromYAML(yamlStr string) (LlmCompletePayload, error) { + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlStr), &data); err != nil { + return LlmCompletePayload{}, err + } + ctx := NewLoadContext() + return LoadLlmCompletePayload(data, ctx) +} diff --git a/runtime/go/prompty/model/llm_complete_payload_test.go b/runtime/go/prompty/model/llm_complete_payload_test.go new file mode 100644 index 00000000..be9d3029 --- /dev/null +++ b/runtime/go/prompty/model/llm_complete_payload_test.go @@ -0,0 +1,168 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +package prompty_test + +import ( + "encoding/json" + "testing" + + "gopkg.in/yaml.v3" + + "prompty/model" +) + +// TestLlmCompletePayloadLoadJSON tests loading LlmCompletePayload from JSON +func TestLlmCompletePayloadLoadJSON(t *testing.T) { + jsonData := ` +{ + "requestId": "req_abc123", + "serviceRequestId": "srv_abc123", + "durationMs": 820 +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadLlmCompletePayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load LlmCompletePayload: %v", err) + } + if instance.RequestId == nil || *instance.RequestId != "req_abc123" { + t.Errorf(`Expected RequestId to be "req_abc123", got %v`, instance.RequestId) + } + if instance.ServiceRequestId == nil || *instance.ServiceRequestId != "srv_abc123" { + t.Errorf(`Expected ServiceRequestId to be "srv_abc123", got %v`, instance.ServiceRequestId) + } + if instance.DurationMs == nil || *instance.DurationMs != 820 { + t.Errorf(`Expected DurationMs to be 820, got %v`, instance.DurationMs) + } +} + +// TestLlmCompletePayloadLoadYAML tests loading LlmCompletePayload from YAML +func TestLlmCompletePayloadLoadYAML(t *testing.T) { + yamlData := ` +requestId: req_abc123 +serviceRequestId: srv_abc123 +durationMs: 820 + +` + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlData), &data); err != nil { + t.Fatalf("Failed to parse YAML: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadLlmCompletePayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load LlmCompletePayload: %v", err) + } + if instance.RequestId == nil || *instance.RequestId != "req_abc123" { + t.Errorf(`Expected RequestId to be "req_abc123", got %v`, instance.RequestId) + } + if instance.ServiceRequestId == nil || *instance.ServiceRequestId != "srv_abc123" { + t.Errorf(`Expected ServiceRequestId to be "srv_abc123", got %v`, instance.ServiceRequestId) + } + if instance.DurationMs == nil || *instance.DurationMs != 820 { + t.Errorf(`Expected DurationMs to be 820, got %v`, instance.DurationMs) + } +} + +// TestLlmCompletePayloadRoundtrip tests load -> save -> load produces equivalent data +func TestLlmCompletePayloadRoundtrip(t *testing.T) { + jsonData := ` +{ + "requestId": "req_abc123", + "serviceRequestId": "srv_abc123", + "durationMs": 820 +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + loadCtx := prompty.NewLoadContext() + instance, err := prompty.LoadLlmCompletePayload(data, loadCtx) + if err != nil { + t.Fatalf("Failed to load LlmCompletePayload: %v", err) + } + saveCtx := prompty.NewSaveContext() + savedData := instance.Save(saveCtx) + + reloaded, err := prompty.LoadLlmCompletePayload(savedData, loadCtx) + if err != nil { + t.Fatalf("Failed to reload LlmCompletePayload: %v", err) + } + if reloaded.RequestId == nil || *reloaded.RequestId != "req_abc123" { + t.Errorf(`Expected RequestId to be "req_abc123", got %v`, reloaded.RequestId) + } + if reloaded.ServiceRequestId == nil || *reloaded.ServiceRequestId != "srv_abc123" { + t.Errorf(`Expected ServiceRequestId to be "srv_abc123", got %v`, reloaded.ServiceRequestId) + } + if reloaded.DurationMs == nil || *reloaded.DurationMs != 820 { + t.Errorf(`Expected DurationMs to be 820, got %v`, reloaded.DurationMs) + } +} + +// TestLlmCompletePayloadToJSON tests that ToJSON produces valid JSON +func TestLlmCompletePayloadToJSON(t *testing.T) { + jsonData := ` +{ + "requestId": "req_abc123", + "serviceRequestId": "srv_abc123", + "durationMs": 820 +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadLlmCompletePayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load LlmCompletePayload: %v", err) + } + jsonOutput, err := instance.ToJSON() + if err != nil { + t.Fatalf("Failed to convert to JSON: %v", err) + } + + var parsed map[string]interface{} + if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated JSON: %v", err) + } +} + +// TestLlmCompletePayloadToYAML tests that ToYAML produces valid YAML +func TestLlmCompletePayloadToYAML(t *testing.T) { + jsonData := ` +{ + "requestId": "req_abc123", + "serviceRequestId": "srv_abc123", + "durationMs": 820 +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadLlmCompletePayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load LlmCompletePayload: %v", err) + } + yamlOutput, err := instance.ToYAML() + if err != nil { + t.Fatalf("Failed to convert to YAML: %v", err) + } + + var parsed map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated YAML: %v", err) + } +} diff --git a/runtime/go/prompty/model/llm_start_payload.go b/runtime/go/prompty/model/llm_start_payload.go new file mode 100644 index 00000000..b0935e75 --- /dev/null +++ b/runtime/go/prompty/model/llm_start_payload.go @@ -0,0 +1,127 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: events + +package prompty + +import ( + "encoding/json" + + "gopkg.in/yaml.v3" +) + +// LlmStartPayload represents Payload for "llm_start" events — an LLM request is about to be sent. + +type LlmStartPayload struct { + Provider *string `json:"provider,omitempty" yaml:"provider,omitempty"` + ModelId *string `json:"modelId,omitempty" yaml:"modelId,omitempty"` + MessageCount *int32 `json:"messageCount,omitempty" yaml:"messageCount,omitempty"` + Attempt *int32 `json:"attempt,omitempty" yaml:"attempt,omitempty"` +} + +// LoadLlmStartPayload creates a LlmStartPayload from a map[string]interface{} +func LoadLlmStartPayload(data interface{}, ctx *LoadContext) (LlmStartPayload, error) { + result := LlmStartPayload{} + + // Load from map + if m, ok := data.(map[string]interface{}); ok { + if val, ok := m["provider"]; ok && val != nil { + v := string(val.(string)) + result.Provider = &v + } + if val, ok := m["modelId"]; ok && val != nil { + v := string(val.(string)) + result.ModelId = &v + } + if val, ok := m["messageCount"]; ok && val != nil { // Handle various numeric types from JSON/YAML/roundtrip + var v int32 + switch n := val.(type) { + case int: + v = int32(n) + case int32: + v = int32(n) + case int64: + v = int32(n) + case float64: + v = int32(n) + } + result.MessageCount = &v + } + if val, ok := m["attempt"]; ok && val != nil { // Handle various numeric types from JSON/YAML/roundtrip + var v int32 + switch n := val.(type) { + case int: + v = int32(n) + case int32: + v = int32(n) + case int64: + v = int32(n) + case float64: + v = int32(n) + } + result.Attempt = &v + } + } + + return result, nil +} + +// Save serializes LlmStartPayload to map[string]interface{} +func (obj *LlmStartPayload) Save(ctx *SaveContext) map[string]interface{} { + result := make(map[string]interface{}) + if obj.Provider != nil { + result["provider"] = *obj.Provider + } + if obj.ModelId != nil { + result["modelId"] = *obj.ModelId + } + if obj.MessageCount != nil { + result["messageCount"] = *obj.MessageCount + } + if obj.Attempt != nil { + result["attempt"] = *obj.Attempt + } + + return result +} + +// ToJSON serializes LlmStartPayload to JSON string +func (obj *LlmStartPayload) ToJSON() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := json.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// ToYAML serializes LlmStartPayload to YAML string +func (obj *LlmStartPayload) ToYAML() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := yaml.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// FromJSON creates LlmStartPayload from JSON string +func LlmStartPayloadFromJSON(jsonStr string) (LlmStartPayload, error) { + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { + return LlmStartPayload{}, err + } + ctx := NewLoadContext() + return LoadLlmStartPayload(data, ctx) +} + +// FromYAML creates LlmStartPayload from YAML string +func LlmStartPayloadFromYAML(yamlStr string) (LlmStartPayload, error) { + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlStr), &data); err != nil { + return LlmStartPayload{}, err + } + ctx := NewLoadContext() + return LoadLlmStartPayload(data, ctx) +} diff --git a/runtime/go/prompty/model/llm_start_payload_test.go b/runtime/go/prompty/model/llm_start_payload_test.go new file mode 100644 index 00000000..7371ba01 --- /dev/null +++ b/runtime/go/prompty/model/llm_start_payload_test.go @@ -0,0 +1,182 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +package prompty_test + +import ( + "encoding/json" + "testing" + + "gopkg.in/yaml.v3" + + "prompty/model" +) + +// TestLlmStartPayloadLoadJSON tests loading LlmStartPayload from JSON +func TestLlmStartPayloadLoadJSON(t *testing.T) { + jsonData := ` +{ + "provider": "openai", + "modelId": "gpt-4o-mini", + "messageCount": 4, + "attempt": 0 +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadLlmStartPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load LlmStartPayload: %v", err) + } + if instance.Provider == nil || *instance.Provider != "openai" { + t.Errorf(`Expected Provider to be "openai", got %v`, instance.Provider) + } + if instance.ModelId == nil || *instance.ModelId != "gpt-4o-mini" { + t.Errorf(`Expected ModelId to be "gpt-4o-mini", got %v`, instance.ModelId) + } + if instance.MessageCount == nil || *instance.MessageCount != 4 { + t.Errorf(`Expected MessageCount to be 4, got %v`, instance.MessageCount) + } + if instance.Attempt == nil || *instance.Attempt != 0 { + t.Errorf(`Expected Attempt to be 0, got %v`, instance.Attempt) + } +} + +// TestLlmStartPayloadLoadYAML tests loading LlmStartPayload from YAML +func TestLlmStartPayloadLoadYAML(t *testing.T) { + yamlData := ` +provider: openai +modelId: gpt-4o-mini +messageCount: 4 +attempt: 0 + +` + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlData), &data); err != nil { + t.Fatalf("Failed to parse YAML: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadLlmStartPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load LlmStartPayload: %v", err) + } + if instance.Provider == nil || *instance.Provider != "openai" { + t.Errorf(`Expected Provider to be "openai", got %v`, instance.Provider) + } + if instance.ModelId == nil || *instance.ModelId != "gpt-4o-mini" { + t.Errorf(`Expected ModelId to be "gpt-4o-mini", got %v`, instance.ModelId) + } + if instance.MessageCount == nil || *instance.MessageCount != 4 { + t.Errorf(`Expected MessageCount to be 4, got %v`, instance.MessageCount) + } + if instance.Attempt == nil || *instance.Attempt != 0 { + t.Errorf(`Expected Attempt to be 0, got %v`, instance.Attempt) + } +} + +// TestLlmStartPayloadRoundtrip tests load -> save -> load produces equivalent data +func TestLlmStartPayloadRoundtrip(t *testing.T) { + jsonData := ` +{ + "provider": "openai", + "modelId": "gpt-4o-mini", + "messageCount": 4, + "attempt": 0 +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + loadCtx := prompty.NewLoadContext() + instance, err := prompty.LoadLlmStartPayload(data, loadCtx) + if err != nil { + t.Fatalf("Failed to load LlmStartPayload: %v", err) + } + saveCtx := prompty.NewSaveContext() + savedData := instance.Save(saveCtx) + + reloaded, err := prompty.LoadLlmStartPayload(savedData, loadCtx) + if err != nil { + t.Fatalf("Failed to reload LlmStartPayload: %v", err) + } + if reloaded.Provider == nil || *reloaded.Provider != "openai" { + t.Errorf(`Expected Provider to be "openai", got %v`, reloaded.Provider) + } + if reloaded.ModelId == nil || *reloaded.ModelId != "gpt-4o-mini" { + t.Errorf(`Expected ModelId to be "gpt-4o-mini", got %v`, reloaded.ModelId) + } + if reloaded.MessageCount == nil || *reloaded.MessageCount != 4 { + t.Errorf(`Expected MessageCount to be 4, got %v`, reloaded.MessageCount) + } + if reloaded.Attempt == nil || *reloaded.Attempt != 0 { + t.Errorf(`Expected Attempt to be 0, got %v`, reloaded.Attempt) + } +} + +// TestLlmStartPayloadToJSON tests that ToJSON produces valid JSON +func TestLlmStartPayloadToJSON(t *testing.T) { + jsonData := ` +{ + "provider": "openai", + "modelId": "gpt-4o-mini", + "messageCount": 4, + "attempt": 0 +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadLlmStartPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load LlmStartPayload: %v", err) + } + jsonOutput, err := instance.ToJSON() + if err != nil { + t.Fatalf("Failed to convert to JSON: %v", err) + } + + var parsed map[string]interface{} + if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated JSON: %v", err) + } +} + +// TestLlmStartPayloadToYAML tests that ToYAML produces valid YAML +func TestLlmStartPayloadToYAML(t *testing.T) { + jsonData := ` +{ + "provider": "openai", + "modelId": "gpt-4o-mini", + "messageCount": 4, + "attempt": 0 +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadLlmStartPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load LlmStartPayload: %v", err) + } + yamlOutput, err := instance.ToYAML() + if err != nil { + t.Fatalf("Failed to convert to YAML: %v", err) + } + + var parsed map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated YAML: %v", err) + } +} diff --git a/runtime/go/prompty/model/messages_updated_payload.go b/runtime/go/prompty/model/messages_updated_payload.go index 8923f0ab..772b8e04 100644 --- a/runtime/go/prompty/model/messages_updated_payload.go +++ b/runtime/go/prompty/model/messages_updated_payload.go @@ -12,7 +12,10 @@ import ( // MessagesUpdatedPayload represents Payload for "messages_updated" events — the conversation state has changed. type MessagesUpdatedPayload struct { - Messages []Message `json:"messages" yaml:"messages"` + Messages []Message `json:"messages,omitempty" yaml:"messages,omitempty"` + Reason *string `json:"reason,omitempty" yaml:"reason,omitempty"` + Appended []Message `json:"appended,omitempty" yaml:"appended,omitempty"` + Removed *int32 `json:"removed,omitempty" yaml:"removed,omitempty"` } // LoadMessagesUpdatedPayload creates a MessagesUpdatedPayload from a map[string]interface{} @@ -32,6 +35,35 @@ func LoadMessagesUpdatedPayload(data interface{}, ctx *LoadContext) (MessagesUpd } } } + if val, ok := m["reason"]; ok && val != nil { + v := string(val.(string)) + result.Reason = &v + } + if val, ok := m["appended"]; ok && val != nil { + if arr, ok := val.([]interface{}); ok { + result.Appended = make([]Message, len(arr)) + for i, v := range arr { + if item, ok := v.(map[string]interface{}); ok { + loaded, _ := LoadMessage(item, ctx) + result.Appended[i] = loaded + } + } + } + } + if val, ok := m["removed"]; ok && val != nil { // Handle various numeric types from JSON/YAML/roundtrip + var v int32 + switch n := val.(type) { + case int: + v = int32(n) + case int32: + v = int32(n) + case int64: + v = int32(n) + case float64: + v = int32(n) + } + result.Removed = &v + } } return result, nil @@ -47,6 +79,19 @@ func (obj *MessagesUpdatedPayload) Save(ctx *SaveContext) map[string]interface{} } result["messages"] = arr } + if obj.Reason != nil { + result["reason"] = *obj.Reason + } + if obj.Appended != nil { + arr := make([]interface{}, len(obj.Appended)) + for i, item := range obj.Appended { + arr[i] = item.Save(ctx) + } + result["appended"] = arr + } + if obj.Removed != nil { + result["removed"] = *obj.Removed + } return result } diff --git a/runtime/go/prompty/model/messages_updated_payload_test.go b/runtime/go/prompty/model/messages_updated_payload_test.go index 3df1459b..ef142962 100644 --- a/runtime/go/prompty/model/messages_updated_payload_test.go +++ b/runtime/go/prompty/model/messages_updated_payload_test.go @@ -1,3 +1,154 @@ // Code generated by Prompty emitter; DO NOT EDIT. package prompty_test + +import ( + "encoding/json" + "testing" + + "gopkg.in/yaml.v3" + + "prompty/model" +) + +// TestMessagesUpdatedPayloadLoadJSON tests loading MessagesUpdatedPayload from JSON +func TestMessagesUpdatedPayloadLoadJSON(t *testing.T) { + jsonData := ` +{ + "reason": "tool_results", + "removed": 2 +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadMessagesUpdatedPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load MessagesUpdatedPayload: %v", err) + } + if instance.Reason == nil || *instance.Reason != "tool_results" { + t.Errorf(`Expected Reason to be "tool_results", got %v`, instance.Reason) + } + if instance.Removed == nil || *instance.Removed != 2 { + t.Errorf(`Expected Removed to be 2, got %v`, instance.Removed) + } +} + +// TestMessagesUpdatedPayloadLoadYAML tests loading MessagesUpdatedPayload from YAML +func TestMessagesUpdatedPayloadLoadYAML(t *testing.T) { + yamlData := ` +reason: tool_results +removed: 2 + +` + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlData), &data); err != nil { + t.Fatalf("Failed to parse YAML: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadMessagesUpdatedPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load MessagesUpdatedPayload: %v", err) + } + if instance.Reason == nil || *instance.Reason != "tool_results" { + t.Errorf(`Expected Reason to be "tool_results", got %v`, instance.Reason) + } + if instance.Removed == nil || *instance.Removed != 2 { + t.Errorf(`Expected Removed to be 2, got %v`, instance.Removed) + } +} + +// TestMessagesUpdatedPayloadRoundtrip tests load -> save -> load produces equivalent data +func TestMessagesUpdatedPayloadRoundtrip(t *testing.T) { + jsonData := ` +{ + "reason": "tool_results", + "removed": 2 +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + loadCtx := prompty.NewLoadContext() + instance, err := prompty.LoadMessagesUpdatedPayload(data, loadCtx) + if err != nil { + t.Fatalf("Failed to load MessagesUpdatedPayload: %v", err) + } + saveCtx := prompty.NewSaveContext() + savedData := instance.Save(saveCtx) + + reloaded, err := prompty.LoadMessagesUpdatedPayload(savedData, loadCtx) + if err != nil { + t.Fatalf("Failed to reload MessagesUpdatedPayload: %v", err) + } + if reloaded.Reason == nil || *reloaded.Reason != "tool_results" { + t.Errorf(`Expected Reason to be "tool_results", got %v`, reloaded.Reason) + } + if reloaded.Removed == nil || *reloaded.Removed != 2 { + t.Errorf(`Expected Removed to be 2, got %v`, reloaded.Removed) + } +} + +// TestMessagesUpdatedPayloadToJSON tests that ToJSON produces valid JSON +func TestMessagesUpdatedPayloadToJSON(t *testing.T) { + jsonData := ` +{ + "reason": "tool_results", + "removed": 2 +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadMessagesUpdatedPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load MessagesUpdatedPayload: %v", err) + } + jsonOutput, err := instance.ToJSON() + if err != nil { + t.Fatalf("Failed to convert to JSON: %v", err) + } + + var parsed map[string]interface{} + if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated JSON: %v", err) + } +} + +// TestMessagesUpdatedPayloadToYAML tests that ToYAML produces valid YAML +func TestMessagesUpdatedPayloadToYAML(t *testing.T) { + jsonData := ` +{ + "reason": "tool_results", + "removed": 2 +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadMessagesUpdatedPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load MessagesUpdatedPayload: %v", err) + } + yamlOutput, err := instance.ToYAML() + if err != nil { + t.Fatalf("Failed to convert to YAML: %v", err) + } + + var parsed map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated YAML: %v", err) + } +} diff --git a/runtime/go/prompty/model/permission_completed_payload.go b/runtime/go/prompty/model/permission_completed_payload.go new file mode 100644 index 00000000..12d34036 --- /dev/null +++ b/runtime/go/prompty/model/permission_completed_payload.go @@ -0,0 +1,93 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: events + +package prompty + +import ( + "encoding/json" + + "gopkg.in/yaml.v3" +) + +// PermissionCompletedPayload represents Payload for permission completion events — an approval decision was made. + +type PermissionCompletedPayload struct { + Permission string `json:"permission" yaml:"permission"` + Approved bool `json:"approved" yaml:"approved"` + Reason *string `json:"reason,omitempty" yaml:"reason,omitempty"` +} + +// LoadPermissionCompletedPayload creates a PermissionCompletedPayload from a map[string]interface{} +func LoadPermissionCompletedPayload(data interface{}, ctx *LoadContext) (PermissionCompletedPayload, error) { + result := PermissionCompletedPayload{} + + // Load from map + if m, ok := data.(map[string]interface{}); ok { + if val, ok := m["permission"]; ok && val != nil { + result.Permission = string(val.(string)) + } + if val, ok := m["approved"]; ok && val != nil { + result.Approved = val.(bool) + } + if val, ok := m["reason"]; ok && val != nil { + v := string(val.(string)) + result.Reason = &v + } + } + + return result, nil +} + +// Save serializes PermissionCompletedPayload to map[string]interface{} +func (obj *PermissionCompletedPayload) Save(ctx *SaveContext) map[string]interface{} { + result := make(map[string]interface{}) + result["permission"] = obj.Permission + result["approved"] = obj.Approved + if obj.Reason != nil { + result["reason"] = *obj.Reason + } + + return result +} + +// ToJSON serializes PermissionCompletedPayload to JSON string +func (obj *PermissionCompletedPayload) ToJSON() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := json.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// ToYAML serializes PermissionCompletedPayload to YAML string +func (obj *PermissionCompletedPayload) ToYAML() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := yaml.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// FromJSON creates PermissionCompletedPayload from JSON string +func PermissionCompletedPayloadFromJSON(jsonStr string) (PermissionCompletedPayload, error) { + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { + return PermissionCompletedPayload{}, err + } + ctx := NewLoadContext() + return LoadPermissionCompletedPayload(data, ctx) +} + +// FromYAML creates PermissionCompletedPayload from YAML string +func PermissionCompletedPayloadFromYAML(yamlStr string) (PermissionCompletedPayload, error) { + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlStr), &data); err != nil { + return PermissionCompletedPayload{}, err + } + ctx := NewLoadContext() + return LoadPermissionCompletedPayload(data, ctx) +} diff --git a/runtime/go/prompty/model/permission_completed_payload_test.go b/runtime/go/prompty/model/permission_completed_payload_test.go new file mode 100644 index 00000000..631de6d1 --- /dev/null +++ b/runtime/go/prompty/model/permission_completed_payload_test.go @@ -0,0 +1,168 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +package prompty_test + +import ( + "encoding/json" + "testing" + + "gopkg.in/yaml.v3" + + "prompty/model" +) + +// TestPermissionCompletedPayloadLoadJSON tests loading PermissionCompletedPayload from JSON +func TestPermissionCompletedPayloadLoadJSON(t *testing.T) { + jsonData := ` +{ + "permission": "tool.execute", + "approved": true, + "reason": "user_approved" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadPermissionCompletedPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load PermissionCompletedPayload: %v", err) + } + if instance.Permission != "tool.execute" { + t.Errorf(`Expected Permission to be "tool.execute", got %v`, instance.Permission) + } + if instance.Approved != true { + t.Errorf(`Expected Approved to be true, got %v`, instance.Approved) + } + if instance.Reason == nil || *instance.Reason != "user_approved" { + t.Errorf(`Expected Reason to be "user_approved", got %v`, instance.Reason) + } +} + +// TestPermissionCompletedPayloadLoadYAML tests loading PermissionCompletedPayload from YAML +func TestPermissionCompletedPayloadLoadYAML(t *testing.T) { + yamlData := ` +permission: tool.execute +approved: true +reason: user_approved + +` + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlData), &data); err != nil { + t.Fatalf("Failed to parse YAML: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadPermissionCompletedPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load PermissionCompletedPayload: %v", err) + } + if instance.Permission != "tool.execute" { + t.Errorf(`Expected Permission to be "tool.execute", got %v`, instance.Permission) + } + if instance.Approved != true { + t.Errorf(`Expected Approved to be true, got %v`, instance.Approved) + } + if instance.Reason == nil || *instance.Reason != "user_approved" { + t.Errorf(`Expected Reason to be "user_approved", got %v`, instance.Reason) + } +} + +// TestPermissionCompletedPayloadRoundtrip tests load -> save -> load produces equivalent data +func TestPermissionCompletedPayloadRoundtrip(t *testing.T) { + jsonData := ` +{ + "permission": "tool.execute", + "approved": true, + "reason": "user_approved" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + loadCtx := prompty.NewLoadContext() + instance, err := prompty.LoadPermissionCompletedPayload(data, loadCtx) + if err != nil { + t.Fatalf("Failed to load PermissionCompletedPayload: %v", err) + } + saveCtx := prompty.NewSaveContext() + savedData := instance.Save(saveCtx) + + reloaded, err := prompty.LoadPermissionCompletedPayload(savedData, loadCtx) + if err != nil { + t.Fatalf("Failed to reload PermissionCompletedPayload: %v", err) + } + if reloaded.Permission != "tool.execute" { + t.Errorf(`Expected Permission to be "tool.execute", got %v`, reloaded.Permission) + } + if reloaded.Approved != true { + t.Errorf(`Expected Approved to be true, got %v`, reloaded.Approved) + } + if reloaded.Reason == nil || *reloaded.Reason != "user_approved" { + t.Errorf(`Expected Reason to be "user_approved", got %v`, reloaded.Reason) + } +} + +// TestPermissionCompletedPayloadToJSON tests that ToJSON produces valid JSON +func TestPermissionCompletedPayloadToJSON(t *testing.T) { + jsonData := ` +{ + "permission": "tool.execute", + "approved": true, + "reason": "user_approved" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadPermissionCompletedPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load PermissionCompletedPayload: %v", err) + } + jsonOutput, err := instance.ToJSON() + if err != nil { + t.Fatalf("Failed to convert to JSON: %v", err) + } + + var parsed map[string]interface{} + if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated JSON: %v", err) + } +} + +// TestPermissionCompletedPayloadToYAML tests that ToYAML produces valid YAML +func TestPermissionCompletedPayloadToYAML(t *testing.T) { + jsonData := ` +{ + "permission": "tool.execute", + "approved": true, + "reason": "user_approved" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadPermissionCompletedPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load PermissionCompletedPayload: %v", err) + } + yamlOutput, err := instance.ToYAML() + if err != nil { + t.Fatalf("Failed to convert to YAML: %v", err) + } + + var parsed map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated YAML: %v", err) + } +} diff --git a/runtime/go/prompty/model/permission_requested_payload.go b/runtime/go/prompty/model/permission_requested_payload.go new file mode 100644 index 00000000..34c6dbf3 --- /dev/null +++ b/runtime/go/prompty/model/permission_requested_payload.go @@ -0,0 +1,97 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: events + +package prompty + +import ( + "encoding/json" + + "gopkg.in/yaml.v3" +) + +// PermissionRequestedPayload represents Payload for permission request events — a host is asked to approve an action. + +type PermissionRequestedPayload struct { + Permission string `json:"permission" yaml:"permission"` + Target *string `json:"target,omitempty" yaml:"target,omitempty"` + Details map[string]interface{} `json:"details,omitempty" yaml:"details,omitempty"` +} + +// LoadPermissionRequestedPayload creates a PermissionRequestedPayload from a map[string]interface{} +func LoadPermissionRequestedPayload(data interface{}, ctx *LoadContext) (PermissionRequestedPayload, error) { + result := PermissionRequestedPayload{} + + // Load from map + if m, ok := data.(map[string]interface{}); ok { + if val, ok := m["permission"]; ok && val != nil { + result.Permission = string(val.(string)) + } + if val, ok := m["target"]; ok && val != nil { + v := string(val.(string)) + result.Target = &v + } + if val, ok := m["details"]; ok && val != nil { + if m, ok := val.(map[string]interface{}); ok { + result.Details = m + } + } + } + + return result, nil +} + +// Save serializes PermissionRequestedPayload to map[string]interface{} +func (obj *PermissionRequestedPayload) Save(ctx *SaveContext) map[string]interface{} { + result := make(map[string]interface{}) + result["permission"] = obj.Permission + if obj.Target != nil { + result["target"] = *obj.Target + } + if obj.Details != nil { + result["details"] = obj.Details + } + + return result +} + +// ToJSON serializes PermissionRequestedPayload to JSON string +func (obj *PermissionRequestedPayload) ToJSON() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := json.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// ToYAML serializes PermissionRequestedPayload to YAML string +func (obj *PermissionRequestedPayload) ToYAML() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := yaml.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// FromJSON creates PermissionRequestedPayload from JSON string +func PermissionRequestedPayloadFromJSON(jsonStr string) (PermissionRequestedPayload, error) { + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { + return PermissionRequestedPayload{}, err + } + ctx := NewLoadContext() + return LoadPermissionRequestedPayload(data, ctx) +} + +// FromYAML creates PermissionRequestedPayload from YAML string +func PermissionRequestedPayloadFromYAML(yamlStr string) (PermissionRequestedPayload, error) { + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlStr), &data); err != nil { + return PermissionRequestedPayload{}, err + } + ctx := NewLoadContext() + return LoadPermissionRequestedPayload(data, ctx) +} diff --git a/runtime/go/prompty/model/permission_requested_payload_test.go b/runtime/go/prompty/model/permission_requested_payload_test.go new file mode 100644 index 00000000..78be5e99 --- /dev/null +++ b/runtime/go/prompty/model/permission_requested_payload_test.go @@ -0,0 +1,154 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +package prompty_test + +import ( + "encoding/json" + "testing" + + "gopkg.in/yaml.v3" + + "prompty/model" +) + +// TestPermissionRequestedPayloadLoadJSON tests loading PermissionRequestedPayload from JSON +func TestPermissionRequestedPayloadLoadJSON(t *testing.T) { + jsonData := ` +{ + "permission": "tool.execute", + "target": "shell" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadPermissionRequestedPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load PermissionRequestedPayload: %v", err) + } + if instance.Permission != "tool.execute" { + t.Errorf(`Expected Permission to be "tool.execute", got %v`, instance.Permission) + } + if instance.Target == nil || *instance.Target != "shell" { + t.Errorf(`Expected Target to be "shell", got %v`, instance.Target) + } +} + +// TestPermissionRequestedPayloadLoadYAML tests loading PermissionRequestedPayload from YAML +func TestPermissionRequestedPayloadLoadYAML(t *testing.T) { + yamlData := ` +permission: tool.execute +target: shell + +` + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlData), &data); err != nil { + t.Fatalf("Failed to parse YAML: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadPermissionRequestedPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load PermissionRequestedPayload: %v", err) + } + if instance.Permission != "tool.execute" { + t.Errorf(`Expected Permission to be "tool.execute", got %v`, instance.Permission) + } + if instance.Target == nil || *instance.Target != "shell" { + t.Errorf(`Expected Target to be "shell", got %v`, instance.Target) + } +} + +// TestPermissionRequestedPayloadRoundtrip tests load -> save -> load produces equivalent data +func TestPermissionRequestedPayloadRoundtrip(t *testing.T) { + jsonData := ` +{ + "permission": "tool.execute", + "target": "shell" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + loadCtx := prompty.NewLoadContext() + instance, err := prompty.LoadPermissionRequestedPayload(data, loadCtx) + if err != nil { + t.Fatalf("Failed to load PermissionRequestedPayload: %v", err) + } + saveCtx := prompty.NewSaveContext() + savedData := instance.Save(saveCtx) + + reloaded, err := prompty.LoadPermissionRequestedPayload(savedData, loadCtx) + if err != nil { + t.Fatalf("Failed to reload PermissionRequestedPayload: %v", err) + } + if reloaded.Permission != "tool.execute" { + t.Errorf(`Expected Permission to be "tool.execute", got %v`, reloaded.Permission) + } + if reloaded.Target == nil || *reloaded.Target != "shell" { + t.Errorf(`Expected Target to be "shell", got %v`, reloaded.Target) + } +} + +// TestPermissionRequestedPayloadToJSON tests that ToJSON produces valid JSON +func TestPermissionRequestedPayloadToJSON(t *testing.T) { + jsonData := ` +{ + "permission": "tool.execute", + "target": "shell" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadPermissionRequestedPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load PermissionRequestedPayload: %v", err) + } + jsonOutput, err := instance.ToJSON() + if err != nil { + t.Fatalf("Failed to convert to JSON: %v", err) + } + + var parsed map[string]interface{} + if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated JSON: %v", err) + } +} + +// TestPermissionRequestedPayloadToYAML tests that ToYAML produces valid YAML +func TestPermissionRequestedPayloadToYAML(t *testing.T) { + jsonData := ` +{ + "permission": "tool.execute", + "target": "shell" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadPermissionRequestedPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load PermissionRequestedPayload: %v", err) + } + yamlOutput, err := instance.ToYAML() + if err != nil { + t.Fatalf("Failed to convert to YAML: %v", err) + } + + var parsed map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated YAML: %v", err) + } +} diff --git a/runtime/go/prompty/model/prompty.go b/runtime/go/prompty/model/prompty.go index 5ea8484c..767e7666 100644 --- a/runtime/go/prompty/model/prompty.go +++ b/runtime/go/prompty/model/prompty.go @@ -15,6 +15,12 @@ import ( // // This is the single root type for the Prompty schema — there is no abstract base // class or kind discriminator. A .prompty file always produces a Prompty instance. +// +// Runtime loaders may resolve frontmatter references such as `${env:VAR}` and +// `${file:relative/path}`. File references must be treated as a host-controlled +// capability: by default they are scoped to the containing .prompty file's +// directory tree after canonicalization, and any additional allowed roots must +// be supplied by the host application's load options rather than frontmatter. type Prompty struct { Name string `json:"name" yaml:"name"` diff --git a/runtime/go/prompty/model/retry_payload.go b/runtime/go/prompty/model/retry_payload.go new file mode 100644 index 00000000..c0a8bb96 --- /dev/null +++ b/runtime/go/prompty/model/retry_payload.go @@ -0,0 +1,142 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: events + +package prompty + +import ( + "encoding/json" + + "gopkg.in/yaml.v3" +) + +// RetryPayload represents Payload for "retry" events — a transient operation will be retried. + +type RetryPayload struct { + Operation string `json:"operation" yaml:"operation"` + Attempt int32 `json:"attempt" yaml:"attempt"` + MaxAttempts *int32 `json:"maxAttempts,omitempty" yaml:"maxAttempts,omitempty"` + DelayMs *float64 `json:"delayMs,omitempty" yaml:"delayMs,omitempty"` + Reason *string `json:"reason,omitempty" yaml:"reason,omitempty"` +} + +// LoadRetryPayload creates a RetryPayload from a map[string]interface{} +func LoadRetryPayload(data interface{}, ctx *LoadContext) (RetryPayload, error) { + result := RetryPayload{} + + // Load from map + if m, ok := data.(map[string]interface{}); ok { + if val, ok := m["operation"]; ok && val != nil { + result.Operation = string(val.(string)) + } + if val, ok := m["attempt"]; ok && val != nil { // Handle various numeric types from JSON/YAML/roundtrip + var v int32 + switch n := val.(type) { + case int: + v = int32(n) + case int32: + v = int32(n) + case int64: + v = int32(n) + case float64: + v = int32(n) + } + result.Attempt = v + } + if val, ok := m["maxAttempts"]; ok && val != nil { // Handle various numeric types from JSON/YAML/roundtrip + var v int32 + switch n := val.(type) { + case int: + v = int32(n) + case int32: + v = int32(n) + case int64: + v = int32(n) + case float64: + v = int32(n) + } + result.MaxAttempts = &v + } + if val, ok := m["delayMs"]; ok && val != nil { // Handle various numeric types from JSON/YAML/roundtrip + var v float64 + switch n := val.(type) { + case int: + v = float64(n) + case int32: + v = float64(n) + case int64: + v = float64(n) + case float32: + v = float64(n) + case float64: + v = n + } + result.DelayMs = &v + } + if val, ok := m["reason"]; ok && val != nil { + v := string(val.(string)) + result.Reason = &v + } + } + + return result, nil +} + +// Save serializes RetryPayload to map[string]interface{} +func (obj *RetryPayload) Save(ctx *SaveContext) map[string]interface{} { + result := make(map[string]interface{}) + result["operation"] = obj.Operation + result["attempt"] = obj.Attempt + if obj.MaxAttempts != nil { + result["maxAttempts"] = *obj.MaxAttempts + } + if obj.DelayMs != nil { + result["delayMs"] = *obj.DelayMs + } + if obj.Reason != nil { + result["reason"] = *obj.Reason + } + + return result +} + +// ToJSON serializes RetryPayload to JSON string +func (obj *RetryPayload) ToJSON() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := json.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// ToYAML serializes RetryPayload to YAML string +func (obj *RetryPayload) ToYAML() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := yaml.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// FromJSON creates RetryPayload from JSON string +func RetryPayloadFromJSON(jsonStr string) (RetryPayload, error) { + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { + return RetryPayload{}, err + } + ctx := NewLoadContext() + return LoadRetryPayload(data, ctx) +} + +// FromYAML creates RetryPayload from YAML string +func RetryPayloadFromYAML(yamlStr string) (RetryPayload, error) { + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlStr), &data); err != nil { + return RetryPayload{}, err + } + ctx := NewLoadContext() + return LoadRetryPayload(data, ctx) +} diff --git a/runtime/go/prompty/model/retry_payload_test.go b/runtime/go/prompty/model/retry_payload_test.go new file mode 100644 index 00000000..1f106558 --- /dev/null +++ b/runtime/go/prompty/model/retry_payload_test.go @@ -0,0 +1,196 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +package prompty_test + +import ( + "encoding/json" + "testing" + + "gopkg.in/yaml.v3" + + "prompty/model" +) + +// TestRetryPayloadLoadJSON tests loading RetryPayload from JSON +func TestRetryPayloadLoadJSON(t *testing.T) { + jsonData := ` +{ + "operation": "llm", + "attempt": 2, + "maxAttempts": 3, + "delayMs": 1250, + "reason": "rate_limit" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadRetryPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load RetryPayload: %v", err) + } + if instance.Operation != "llm" { + t.Errorf(`Expected Operation to be "llm", got %v`, instance.Operation) + } + if instance.Attempt != 2 { + t.Errorf(`Expected Attempt to be 2, got %v`, instance.Attempt) + } + if instance.MaxAttempts == nil || *instance.MaxAttempts != 3 { + t.Errorf(`Expected MaxAttempts to be 3, got %v`, instance.MaxAttempts) + } + if instance.DelayMs == nil || *instance.DelayMs != 1250 { + t.Errorf(`Expected DelayMs to be 1250, got %v`, instance.DelayMs) + } + if instance.Reason == nil || *instance.Reason != "rate_limit" { + t.Errorf(`Expected Reason to be "rate_limit", got %v`, instance.Reason) + } +} + +// TestRetryPayloadLoadYAML tests loading RetryPayload from YAML +func TestRetryPayloadLoadYAML(t *testing.T) { + yamlData := ` +operation: llm +attempt: 2 +maxAttempts: 3 +delayMs: 1250 +reason: rate_limit + +` + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlData), &data); err != nil { + t.Fatalf("Failed to parse YAML: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadRetryPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load RetryPayload: %v", err) + } + if instance.Operation != "llm" { + t.Errorf(`Expected Operation to be "llm", got %v`, instance.Operation) + } + if instance.Attempt != 2 { + t.Errorf(`Expected Attempt to be 2, got %v`, instance.Attempt) + } + if instance.MaxAttempts == nil || *instance.MaxAttempts != 3 { + t.Errorf(`Expected MaxAttempts to be 3, got %v`, instance.MaxAttempts) + } + if instance.DelayMs == nil || *instance.DelayMs != 1250 { + t.Errorf(`Expected DelayMs to be 1250, got %v`, instance.DelayMs) + } + if instance.Reason == nil || *instance.Reason != "rate_limit" { + t.Errorf(`Expected Reason to be "rate_limit", got %v`, instance.Reason) + } +} + +// TestRetryPayloadRoundtrip tests load -> save -> load produces equivalent data +func TestRetryPayloadRoundtrip(t *testing.T) { + jsonData := ` +{ + "operation": "llm", + "attempt": 2, + "maxAttempts": 3, + "delayMs": 1250, + "reason": "rate_limit" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + loadCtx := prompty.NewLoadContext() + instance, err := prompty.LoadRetryPayload(data, loadCtx) + if err != nil { + t.Fatalf("Failed to load RetryPayload: %v", err) + } + saveCtx := prompty.NewSaveContext() + savedData := instance.Save(saveCtx) + + reloaded, err := prompty.LoadRetryPayload(savedData, loadCtx) + if err != nil { + t.Fatalf("Failed to reload RetryPayload: %v", err) + } + if reloaded.Operation != "llm" { + t.Errorf(`Expected Operation to be "llm", got %v`, reloaded.Operation) + } + if reloaded.Attempt != 2 { + t.Errorf(`Expected Attempt to be 2, got %v`, reloaded.Attempt) + } + if reloaded.MaxAttempts == nil || *reloaded.MaxAttempts != 3 { + t.Errorf(`Expected MaxAttempts to be 3, got %v`, reloaded.MaxAttempts) + } + if reloaded.DelayMs == nil || *reloaded.DelayMs != 1250 { + t.Errorf(`Expected DelayMs to be 1250, got %v`, reloaded.DelayMs) + } + if reloaded.Reason == nil || *reloaded.Reason != "rate_limit" { + t.Errorf(`Expected Reason to be "rate_limit", got %v`, reloaded.Reason) + } +} + +// TestRetryPayloadToJSON tests that ToJSON produces valid JSON +func TestRetryPayloadToJSON(t *testing.T) { + jsonData := ` +{ + "operation": "llm", + "attempt": 2, + "maxAttempts": 3, + "delayMs": 1250, + "reason": "rate_limit" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadRetryPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load RetryPayload: %v", err) + } + jsonOutput, err := instance.ToJSON() + if err != nil { + t.Fatalf("Failed to convert to JSON: %v", err) + } + + var parsed map[string]interface{} + if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated JSON: %v", err) + } +} + +// TestRetryPayloadToYAML tests that ToYAML produces valid YAML +func TestRetryPayloadToYAML(t *testing.T) { + jsonData := ` +{ + "operation": "llm", + "attempt": 2, + "maxAttempts": 3, + "delayMs": 1250, + "reason": "rate_limit" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadRetryPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load RetryPayload: %v", err) + } + yamlOutput, err := instance.ToYAML() + if err != nil { + t.Fatalf("Failed to convert to YAML: %v", err) + } + + var parsed map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated YAML: %v", err) + } +} diff --git a/runtime/go/prompty/model/tool_call_complete_payload.go b/runtime/go/prompty/model/tool_call_complete_payload.go new file mode 100644 index 00000000..b02d3672 --- /dev/null +++ b/runtime/go/prompty/model/tool_call_complete_payload.go @@ -0,0 +1,131 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: events + +package prompty + +import ( + "encoding/json" + + "gopkg.in/yaml.v3" +) + +// ToolCallCompletePayload represents Payload for "tool_call_complete" events — a tool dispatch finished. + +type ToolCallCompletePayload struct { + Id *string `json:"id,omitempty" yaml:"id,omitempty"` + Name string `json:"name" yaml:"name"` + Success bool `json:"success" yaml:"success"` + Result *ToolResult `json:"result,omitempty" yaml:"result,omitempty"` + DurationMs *float64 `json:"durationMs,omitempty" yaml:"durationMs,omitempty"` + ErrorKind *string `json:"errorKind,omitempty" yaml:"errorKind,omitempty"` +} + +// LoadToolCallCompletePayload creates a ToolCallCompletePayload from a map[string]interface{} +func LoadToolCallCompletePayload(data interface{}, ctx *LoadContext) (ToolCallCompletePayload, error) { + result := ToolCallCompletePayload{} + + // Load from map + if m, ok := data.(map[string]interface{}); ok { + if val, ok := m["id"]; ok && val != nil { + v := string(val.(string)) + result.Id = &v + } + if val, ok := m["name"]; ok && val != nil { + result.Name = string(val.(string)) + } + if val, ok := m["success"]; ok && val != nil { + result.Success = val.(bool) + } + if val, ok := m["result"]; ok && val != nil { + if m, ok := val.(map[string]interface{}); ok { + loaded, _ := LoadToolResult(m, ctx) + result.Result = &loaded + } + } + if val, ok := m["durationMs"]; ok && val != nil { // Handle various numeric types from JSON/YAML/roundtrip + var v float64 + switch n := val.(type) { + case int: + v = float64(n) + case int32: + v = float64(n) + case int64: + v = float64(n) + case float32: + v = float64(n) + case float64: + v = n + } + result.DurationMs = &v + } + if val, ok := m["errorKind"]; ok && val != nil { + v := string(val.(string)) + result.ErrorKind = &v + } + } + + return result, nil +} + +// Save serializes ToolCallCompletePayload to map[string]interface{} +func (obj *ToolCallCompletePayload) Save(ctx *SaveContext) map[string]interface{} { + result := make(map[string]interface{}) + if obj.Id != nil { + result["id"] = *obj.Id + } + result["name"] = obj.Name + result["success"] = obj.Success + if obj.Result != nil { + result["result"] = obj.Result.Save(ctx) + } + if obj.DurationMs != nil { + result["durationMs"] = *obj.DurationMs + } + if obj.ErrorKind != nil { + result["errorKind"] = *obj.ErrorKind + } + + return result +} + +// ToJSON serializes ToolCallCompletePayload to JSON string +func (obj *ToolCallCompletePayload) ToJSON() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := json.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// ToYAML serializes ToolCallCompletePayload to YAML string +func (obj *ToolCallCompletePayload) ToYAML() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := yaml.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// FromJSON creates ToolCallCompletePayload from JSON string +func ToolCallCompletePayloadFromJSON(jsonStr string) (ToolCallCompletePayload, error) { + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { + return ToolCallCompletePayload{}, err + } + ctx := NewLoadContext() + return LoadToolCallCompletePayload(data, ctx) +} + +// FromYAML creates ToolCallCompletePayload from YAML string +func ToolCallCompletePayloadFromYAML(yamlStr string) (ToolCallCompletePayload, error) { + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlStr), &data); err != nil { + return ToolCallCompletePayload{}, err + } + ctx := NewLoadContext() + return LoadToolCallCompletePayload(data, ctx) +} diff --git a/runtime/go/prompty/model/tool_call_complete_payload_test.go b/runtime/go/prompty/model/tool_call_complete_payload_test.go new file mode 100644 index 00000000..5f3f5ffe --- /dev/null +++ b/runtime/go/prompty/model/tool_call_complete_payload_test.go @@ -0,0 +1,196 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +package prompty_test + +import ( + "encoding/json" + "testing" + + "gopkg.in/yaml.v3" + + "prompty/model" +) + +// TestToolCallCompletePayloadLoadJSON tests loading ToolCallCompletePayload from JSON +func TestToolCallCompletePayloadLoadJSON(t *testing.T) { + jsonData := ` +{ + "id": "call_abc123", + "name": "get_weather", + "success": true, + "durationMs": 42, + "errorKind": "timeout" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadToolCallCompletePayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load ToolCallCompletePayload: %v", err) + } + if instance.Id == nil || *instance.Id != "call_abc123" { + t.Errorf(`Expected Id to be "call_abc123", got %v`, instance.Id) + } + if instance.Name != "get_weather" { + t.Errorf(`Expected Name to be "get_weather", got %v`, instance.Name) + } + if instance.Success != true { + t.Errorf(`Expected Success to be true, got %v`, instance.Success) + } + if instance.DurationMs == nil || *instance.DurationMs != 42 { + t.Errorf(`Expected DurationMs to be 42, got %v`, instance.DurationMs) + } + if instance.ErrorKind == nil || *instance.ErrorKind != "timeout" { + t.Errorf(`Expected ErrorKind to be "timeout", got %v`, instance.ErrorKind) + } +} + +// TestToolCallCompletePayloadLoadYAML tests loading ToolCallCompletePayload from YAML +func TestToolCallCompletePayloadLoadYAML(t *testing.T) { + yamlData := ` +id: call_abc123 +name: get_weather +success: true +durationMs: 42 +errorKind: timeout + +` + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlData), &data); err != nil { + t.Fatalf("Failed to parse YAML: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadToolCallCompletePayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load ToolCallCompletePayload: %v", err) + } + if instance.Id == nil || *instance.Id != "call_abc123" { + t.Errorf(`Expected Id to be "call_abc123", got %v`, instance.Id) + } + if instance.Name != "get_weather" { + t.Errorf(`Expected Name to be "get_weather", got %v`, instance.Name) + } + if instance.Success != true { + t.Errorf(`Expected Success to be true, got %v`, instance.Success) + } + if instance.DurationMs == nil || *instance.DurationMs != 42 { + t.Errorf(`Expected DurationMs to be 42, got %v`, instance.DurationMs) + } + if instance.ErrorKind == nil || *instance.ErrorKind != "timeout" { + t.Errorf(`Expected ErrorKind to be "timeout", got %v`, instance.ErrorKind) + } +} + +// TestToolCallCompletePayloadRoundtrip tests load -> save -> load produces equivalent data +func TestToolCallCompletePayloadRoundtrip(t *testing.T) { + jsonData := ` +{ + "id": "call_abc123", + "name": "get_weather", + "success": true, + "durationMs": 42, + "errorKind": "timeout" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + loadCtx := prompty.NewLoadContext() + instance, err := prompty.LoadToolCallCompletePayload(data, loadCtx) + if err != nil { + t.Fatalf("Failed to load ToolCallCompletePayload: %v", err) + } + saveCtx := prompty.NewSaveContext() + savedData := instance.Save(saveCtx) + + reloaded, err := prompty.LoadToolCallCompletePayload(savedData, loadCtx) + if err != nil { + t.Fatalf("Failed to reload ToolCallCompletePayload: %v", err) + } + if reloaded.Id == nil || *reloaded.Id != "call_abc123" { + t.Errorf(`Expected Id to be "call_abc123", got %v`, reloaded.Id) + } + if reloaded.Name != "get_weather" { + t.Errorf(`Expected Name to be "get_weather", got %v`, reloaded.Name) + } + if reloaded.Success != true { + t.Errorf(`Expected Success to be true, got %v`, reloaded.Success) + } + if reloaded.DurationMs == nil || *reloaded.DurationMs != 42 { + t.Errorf(`Expected DurationMs to be 42, got %v`, reloaded.DurationMs) + } + if reloaded.ErrorKind == nil || *reloaded.ErrorKind != "timeout" { + t.Errorf(`Expected ErrorKind to be "timeout", got %v`, reloaded.ErrorKind) + } +} + +// TestToolCallCompletePayloadToJSON tests that ToJSON produces valid JSON +func TestToolCallCompletePayloadToJSON(t *testing.T) { + jsonData := ` +{ + "id": "call_abc123", + "name": "get_weather", + "success": true, + "durationMs": 42, + "errorKind": "timeout" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadToolCallCompletePayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load ToolCallCompletePayload: %v", err) + } + jsonOutput, err := instance.ToJSON() + if err != nil { + t.Fatalf("Failed to convert to JSON: %v", err) + } + + var parsed map[string]interface{} + if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated JSON: %v", err) + } +} + +// TestToolCallCompletePayloadToYAML tests that ToYAML produces valid YAML +func TestToolCallCompletePayloadToYAML(t *testing.T) { + jsonData := ` +{ + "id": "call_abc123", + "name": "get_weather", + "success": true, + "durationMs": 42, + "errorKind": "timeout" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadToolCallCompletePayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load ToolCallCompletePayload: %v", err) + } + yamlOutput, err := instance.ToYAML() + if err != nil { + t.Fatalf("Failed to convert to YAML: %v", err) + } + + var parsed map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated YAML: %v", err) + } +} diff --git a/runtime/go/prompty/model/tool_call_start_payload.go b/runtime/go/prompty/model/tool_call_start_payload.go index 378d9516..94db6dfd 100644 --- a/runtime/go/prompty/model/tool_call_start_payload.go +++ b/runtime/go/prompty/model/tool_call_start_payload.go @@ -12,8 +12,9 @@ import ( // ToolCallStartPayload represents Payload for "tool_call_start" events — the LLM has requested a tool call. type ToolCallStartPayload struct { - Name string `json:"name" yaml:"name"` - Arguments string `json:"arguments" yaml:"arguments"` + Id *string `json:"id,omitempty" yaml:"id,omitempty"` + Name string `json:"name" yaml:"name"` + Arguments string `json:"arguments" yaml:"arguments"` } // LoadToolCallStartPayload creates a ToolCallStartPayload from a map[string]interface{} @@ -22,6 +23,10 @@ func LoadToolCallStartPayload(data interface{}, ctx *LoadContext) (ToolCallStart // Load from map if m, ok := data.(map[string]interface{}); ok { + if val, ok := m["id"]; ok && val != nil { + v := string(val.(string)) + result.Id = &v + } if val, ok := m["name"]; ok && val != nil { result.Name = string(val.(string)) } @@ -36,6 +41,9 @@ func LoadToolCallStartPayload(data interface{}, ctx *LoadContext) (ToolCallStart // Save serializes ToolCallStartPayload to map[string]interface{} func (obj *ToolCallStartPayload) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) + if obj.Id != nil { + result["id"] = *obj.Id + } result["name"] = obj.Name result["arguments"] = obj.Arguments diff --git a/runtime/go/prompty/model/tool_call_start_payload_test.go b/runtime/go/prompty/model/tool_call_start_payload_test.go index 3e70a811..1cc86cd8 100644 --- a/runtime/go/prompty/model/tool_call_start_payload_test.go +++ b/runtime/go/prompty/model/tool_call_start_payload_test.go @@ -15,6 +15,7 @@ import ( func TestToolCallStartPayloadLoadJSON(t *testing.T) { jsonData := ` { + "id": "call_abc123", "name": "get_weather", "arguments": "{\"city\": \"Paris\"}" } @@ -29,6 +30,9 @@ func TestToolCallStartPayloadLoadJSON(t *testing.T) { if err != nil { t.Fatalf("Failed to load ToolCallStartPayload: %v", err) } + if instance.Id == nil || *instance.Id != "call_abc123" { + t.Errorf(`Expected Id to be "call_abc123", got %v`, instance.Id) + } if instance.Name != "get_weather" { t.Errorf(`Expected Name to be "get_weather", got %v`, instance.Name) } @@ -40,6 +44,7 @@ func TestToolCallStartPayloadLoadJSON(t *testing.T) { // TestToolCallStartPayloadLoadYAML tests loading ToolCallStartPayload from YAML func TestToolCallStartPayloadLoadYAML(t *testing.T) { yamlData := ` +id: call_abc123 name: get_weather arguments: "{\"city\": \"Paris\"}" @@ -54,6 +59,9 @@ arguments: "{\"city\": \"Paris\"}" if err != nil { t.Fatalf("Failed to load ToolCallStartPayload: %v", err) } + if instance.Id == nil || *instance.Id != "call_abc123" { + t.Errorf(`Expected Id to be "call_abc123", got %v`, instance.Id) + } if instance.Name != "get_weather" { t.Errorf(`Expected Name to be "get_weather", got %v`, instance.Name) } @@ -66,6 +74,7 @@ arguments: "{\"city\": \"Paris\"}" func TestToolCallStartPayloadRoundtrip(t *testing.T) { jsonData := ` { + "id": "call_abc123", "name": "get_weather", "arguments": "{\"city\": \"Paris\"}" } @@ -87,6 +96,9 @@ func TestToolCallStartPayloadRoundtrip(t *testing.T) { if err != nil { t.Fatalf("Failed to reload ToolCallStartPayload: %v", err) } + if reloaded.Id == nil || *reloaded.Id != "call_abc123" { + t.Errorf(`Expected Id to be "call_abc123", got %v`, reloaded.Id) + } if reloaded.Name != "get_weather" { t.Errorf(`Expected Name to be "get_weather", got %v`, reloaded.Name) } @@ -99,6 +111,7 @@ func TestToolCallStartPayloadRoundtrip(t *testing.T) { func TestToolCallStartPayloadToJSON(t *testing.T) { jsonData := ` { + "id": "call_abc123", "name": "get_weather", "arguments": "{\"city\": \"Paris\"}" } @@ -128,6 +141,7 @@ func TestToolCallStartPayloadToJSON(t *testing.T) { func TestToolCallStartPayloadToYAML(t *testing.T) { jsonData := ` { + "id": "call_abc123", "name": "get_weather", "arguments": "{\"city\": \"Paris\"}" } diff --git a/runtime/go/prompty/model/tool_result.go b/runtime/go/prompty/model/tool_result.go index 885c8226..9bfb5bc6 100644 --- a/runtime/go/prompty/model/tool_result.go +++ b/runtime/go/prompty/model/tool_result.go @@ -9,6 +9,16 @@ import ( "gopkg.in/yaml.v3" ) +// ToolResultStatus represents the allowed values for ToolResultStatus. +type ToolResultStatus string + +const ( + ToolResultStatusSuccess ToolResultStatus = "success" + ToolResultStatusError ToolResultStatus = "error" + ToolResultStatusCancelled ToolResultStatus = "cancelled" + ToolResultStatusTimeout ToolResultStatus = "timeout" +) + // ToolResult represents The result of a tool execution. Contains a list of content parts, enabling // rich tool results (text, images, files, audio) rather than just strings. // @@ -16,7 +26,11 @@ import ( // containing a single TextPart for backward compatibility. type ToolResult struct { - Parts []interface{} `json:"parts" yaml:"parts"` + Parts []interface{} `json:"parts" yaml:"parts"` + Status *ToolResultStatus `json:"status,omitempty" yaml:"status,omitempty"` + ErrorKind *string `json:"errorKind,omitempty" yaml:"errorKind,omitempty"` + ErrorMessage *string `json:"errorMessage,omitempty" yaml:"errorMessage,omitempty"` + DurationMs *float64 `json:"durationMs,omitempty" yaml:"durationMs,omitempty"` } // LoadToolResult creates a ToolResult from a map[string]interface{} @@ -37,6 +51,34 @@ func LoadToolResult(data interface{}, ctx *LoadContext) (ToolResult, error) { } } } + if val, ok := m["status"]; ok && val != nil { + v := ToolResultStatus(val.(string)) + result.Status = &v + } + if val, ok := m["errorKind"]; ok && val != nil { + v := string(val.(string)) + result.ErrorKind = &v + } + if val, ok := m["errorMessage"]; ok && val != nil { + v := string(val.(string)) + result.ErrorMessage = &v + } + if val, ok := m["durationMs"]; ok && val != nil { // Handle various numeric types from JSON/YAML/roundtrip + var v float64 + switch n := val.(type) { + case int: + v = float64(n) + case int32: + v = float64(n) + case int64: + v = float64(n) + case float32: + v = float64(n) + case float64: + v = n + } + result.DurationMs = &v + } } return result, nil @@ -60,6 +102,18 @@ func (obj *ToolResult) Save(ctx *SaveContext) map[string]interface{} { } result["parts"] = arr } + if obj.Status != nil { + result["status"] = string(*obj.Status) + } + if obj.ErrorKind != nil { + result["errorKind"] = *obj.ErrorKind + } + if obj.ErrorMessage != nil { + result["errorMessage"] = *obj.ErrorMessage + } + if obj.DurationMs != nil { + result["durationMs"] = *obj.DurationMs + } return result } diff --git a/runtime/go/prompty/model/tool_result_test.go b/runtime/go/prompty/model/tool_result_test.go index 4a623f37..c409d41a 100644 --- a/runtime/go/prompty/model/tool_result_test.go +++ b/runtime/go/prompty/model/tool_result_test.go @@ -20,7 +20,10 @@ func TestToolResultLoadJSON(t *testing.T) { "kind": "text", "value": "72°F and sunny" } - ] + ], + "errorKind": "missing_tool", + "errorMessage": "Tool 'get_weather' is not registered", + "durationMs": 42 } ` var data map[string]interface{} @@ -33,7 +36,15 @@ func TestToolResultLoadJSON(t *testing.T) { if err != nil { t.Fatalf("Failed to load ToolResult: %v", err) } - _ = instance // No scalar properties to validate + if instance.ErrorKind == nil || *instance.ErrorKind != "missing_tool" { + t.Errorf(`Expected ErrorKind to be "missing_tool", got %v`, instance.ErrorKind) + } + if instance.ErrorMessage == nil || *instance.ErrorMessage != "Tool 'get_weather' is not registered" { + t.Errorf(`Expected ErrorMessage to be "Tool 'get_weather' is not registered", got %v`, instance.ErrorMessage) + } + if instance.DurationMs == nil || *instance.DurationMs != 42 { + t.Errorf(`Expected DurationMs to be 42, got %v`, instance.DurationMs) + } } // TestToolResultLoadYAML tests loading ToolResult from YAML @@ -42,6 +53,9 @@ func TestToolResultLoadYAML(t *testing.T) { parts: - kind: text value: 72°F and sunny +errorKind: missing_tool +errorMessage: Tool 'get_weather' is not registered +durationMs: 42 ` var data map[string]interface{} @@ -54,7 +68,15 @@ parts: if err != nil { t.Fatalf("Failed to load ToolResult: %v", err) } - _ = instance // No scalar properties to validate + if instance.ErrorKind == nil || *instance.ErrorKind != "missing_tool" { + t.Errorf(`Expected ErrorKind to be "missing_tool", got %v`, instance.ErrorKind) + } + if instance.ErrorMessage == nil || *instance.ErrorMessage != "Tool 'get_weather' is not registered" { + t.Errorf(`Expected ErrorMessage to be "Tool 'get_weather' is not registered", got %v`, instance.ErrorMessage) + } + if instance.DurationMs == nil || *instance.DurationMs != 42 { + t.Errorf(`Expected DurationMs to be 42, got %v`, instance.DurationMs) + } } // TestToolResultRoundtrip tests load -> save -> load produces equivalent data @@ -66,7 +88,10 @@ func TestToolResultRoundtrip(t *testing.T) { "kind": "text", "value": "72°F and sunny" } - ] + ], + "errorKind": "missing_tool", + "errorMessage": "Tool 'get_weather' is not registered", + "durationMs": 42 } ` var data map[string]interface{} @@ -86,7 +111,15 @@ func TestToolResultRoundtrip(t *testing.T) { if err != nil { t.Fatalf("Failed to reload ToolResult: %v", err) } - _ = reloaded // No scalar properties to validate + if reloaded.ErrorKind == nil || *reloaded.ErrorKind != "missing_tool" { + t.Errorf(`Expected ErrorKind to be "missing_tool", got %v`, reloaded.ErrorKind) + } + if reloaded.ErrorMessage == nil || *reloaded.ErrorMessage != "Tool 'get_weather' is not registered" { + t.Errorf(`Expected ErrorMessage to be "Tool 'get_weather' is not registered", got %v`, reloaded.ErrorMessage) + } + if reloaded.DurationMs == nil || *reloaded.DurationMs != 42 { + t.Errorf(`Expected DurationMs to be 42, got %v`, reloaded.DurationMs) + } } // TestToolResultToJSON tests that ToJSON produces valid JSON @@ -98,7 +131,10 @@ func TestToolResultToJSON(t *testing.T) { "kind": "text", "value": "72°F and sunny" } - ] + ], + "errorKind": "missing_tool", + "errorMessage": "Tool 'get_weather' is not registered", + "durationMs": 42 } ` var data map[string]interface{} @@ -131,7 +167,10 @@ func TestToolResultToYAML(t *testing.T) { "kind": "text", "value": "72°F and sunny" } - ] + ], + "errorKind": "missing_tool", + "errorMessage": "Tool 'get_weather' is not registered", + "durationMs": 42 } ` var data map[string]interface{} diff --git a/runtime/go/prompty/model/turn_end_payload.go b/runtime/go/prompty/model/turn_end_payload.go new file mode 100644 index 00000000..52e5ee14 --- /dev/null +++ b/runtime/go/prompty/model/turn_end_payload.go @@ -0,0 +1,137 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: events + +package prompty + +import ( + "encoding/json" + + "gopkg.in/yaml.v3" +) + +// TurnStatus represents the allowed values for TurnStatus. +type TurnStatus string + +const ( + TurnStatusSuccess TurnStatus = "success" + TurnStatusError TurnStatus = "error" + TurnStatusCancelled TurnStatus = "cancelled" +) + +// TurnEndPayload represents Payload for "turn_end" events — a turn has completed. + +type TurnEndPayload struct { + Iterations *int32 `json:"iterations,omitempty" yaml:"iterations,omitempty"` + Status *TurnStatus `json:"status,omitempty" yaml:"status,omitempty"` + Response *interface{} `json:"response,omitempty" yaml:"response,omitempty"` + DurationMs *float64 `json:"durationMs,omitempty" yaml:"durationMs,omitempty"` +} + +// LoadTurnEndPayload creates a TurnEndPayload from a map[string]interface{} +func LoadTurnEndPayload(data interface{}, ctx *LoadContext) (TurnEndPayload, error) { + result := TurnEndPayload{} + + // Load from map + if m, ok := data.(map[string]interface{}); ok { + if val, ok := m["iterations"]; ok && val != nil { // Handle various numeric types from JSON/YAML/roundtrip + var v int32 + switch n := val.(type) { + case int: + v = int32(n) + case int32: + v = int32(n) + case int64: + v = int32(n) + case float64: + v = int32(n) + } + result.Iterations = &v + } + if val, ok := m["status"]; ok && val != nil { + v := TurnStatus(val.(string)) + result.Status = &v + } + if val, ok := m["response"]; ok && val != nil { + result.Response = &val + } + if val, ok := m["durationMs"]; ok && val != nil { // Handle various numeric types from JSON/YAML/roundtrip + var v float64 + switch n := val.(type) { + case int: + v = float64(n) + case int32: + v = float64(n) + case int64: + v = float64(n) + case float32: + v = float64(n) + case float64: + v = n + } + result.DurationMs = &v + } + } + + return result, nil +} + +// Save serializes TurnEndPayload to map[string]interface{} +func (obj *TurnEndPayload) Save(ctx *SaveContext) map[string]interface{} { + result := make(map[string]interface{}) + if obj.Iterations != nil { + result["iterations"] = *obj.Iterations + } + if obj.Status != nil { + result["status"] = string(*obj.Status) + } + if obj.Response != nil { + result["response"] = *obj.Response + } + if obj.DurationMs != nil { + result["durationMs"] = *obj.DurationMs + } + + return result +} + +// ToJSON serializes TurnEndPayload to JSON string +func (obj *TurnEndPayload) ToJSON() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := json.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// ToYAML serializes TurnEndPayload to YAML string +func (obj *TurnEndPayload) ToYAML() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := yaml.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// FromJSON creates TurnEndPayload from JSON string +func TurnEndPayloadFromJSON(jsonStr string) (TurnEndPayload, error) { + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { + return TurnEndPayload{}, err + } + ctx := NewLoadContext() + return LoadTurnEndPayload(data, ctx) +} + +// FromYAML creates TurnEndPayload from YAML string +func TurnEndPayloadFromYAML(yamlStr string) (TurnEndPayload, error) { + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlStr), &data); err != nil { + return TurnEndPayload{}, err + } + ctx := NewLoadContext() + return LoadTurnEndPayload(data, ctx) +} diff --git a/runtime/go/prompty/model/turn_end_payload_test.go b/runtime/go/prompty/model/turn_end_payload_test.go new file mode 100644 index 00000000..c28ae0fe --- /dev/null +++ b/runtime/go/prompty/model/turn_end_payload_test.go @@ -0,0 +1,154 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +package prompty_test + +import ( + "encoding/json" + "testing" + + "gopkg.in/yaml.v3" + + "prompty/model" +) + +// TestTurnEndPayloadLoadJSON tests loading TurnEndPayload from JSON +func TestTurnEndPayloadLoadJSON(t *testing.T) { + jsonData := ` +{ + "iterations": 2, + "durationMs": 1500 +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadTurnEndPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load TurnEndPayload: %v", err) + } + if instance.Iterations == nil || *instance.Iterations != 2 { + t.Errorf(`Expected Iterations to be 2, got %v`, instance.Iterations) + } + if instance.DurationMs == nil || *instance.DurationMs != 1500 { + t.Errorf(`Expected DurationMs to be 1500, got %v`, instance.DurationMs) + } +} + +// TestTurnEndPayloadLoadYAML tests loading TurnEndPayload from YAML +func TestTurnEndPayloadLoadYAML(t *testing.T) { + yamlData := ` +iterations: 2 +durationMs: 1500 + +` + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlData), &data); err != nil { + t.Fatalf("Failed to parse YAML: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadTurnEndPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load TurnEndPayload: %v", err) + } + if instance.Iterations == nil || *instance.Iterations != 2 { + t.Errorf(`Expected Iterations to be 2, got %v`, instance.Iterations) + } + if instance.DurationMs == nil || *instance.DurationMs != 1500 { + t.Errorf(`Expected DurationMs to be 1500, got %v`, instance.DurationMs) + } +} + +// TestTurnEndPayloadRoundtrip tests load -> save -> load produces equivalent data +func TestTurnEndPayloadRoundtrip(t *testing.T) { + jsonData := ` +{ + "iterations": 2, + "durationMs": 1500 +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + loadCtx := prompty.NewLoadContext() + instance, err := prompty.LoadTurnEndPayload(data, loadCtx) + if err != nil { + t.Fatalf("Failed to load TurnEndPayload: %v", err) + } + saveCtx := prompty.NewSaveContext() + savedData := instance.Save(saveCtx) + + reloaded, err := prompty.LoadTurnEndPayload(savedData, loadCtx) + if err != nil { + t.Fatalf("Failed to reload TurnEndPayload: %v", err) + } + if reloaded.Iterations == nil || *reloaded.Iterations != 2 { + t.Errorf(`Expected Iterations to be 2, got %v`, reloaded.Iterations) + } + if reloaded.DurationMs == nil || *reloaded.DurationMs != 1500 { + t.Errorf(`Expected DurationMs to be 1500, got %v`, reloaded.DurationMs) + } +} + +// TestTurnEndPayloadToJSON tests that ToJSON produces valid JSON +func TestTurnEndPayloadToJSON(t *testing.T) { + jsonData := ` +{ + "iterations": 2, + "durationMs": 1500 +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadTurnEndPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load TurnEndPayload: %v", err) + } + jsonOutput, err := instance.ToJSON() + if err != nil { + t.Fatalf("Failed to convert to JSON: %v", err) + } + + var parsed map[string]interface{} + if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated JSON: %v", err) + } +} + +// TestTurnEndPayloadToYAML tests that ToYAML produces valid YAML +func TestTurnEndPayloadToYAML(t *testing.T) { + jsonData := ` +{ + "iterations": 2, + "durationMs": 1500 +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadTurnEndPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load TurnEndPayload: %v", err) + } + yamlOutput, err := instance.ToYAML() + if err != nil { + t.Fatalf("Failed to convert to YAML: %v", err) + } + + var parsed map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated YAML: %v", err) + } +} diff --git a/runtime/go/prompty/model/turn_event.go b/runtime/go/prompty/model/turn_event.go new file mode 100644 index 00000000..cd85e959 --- /dev/null +++ b/runtime/go/prompty/model/turn_event.go @@ -0,0 +1,167 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: events + +package prompty + +import ( + "encoding/json" + + "gopkg.in/yaml.v3" +) + +// TurnEventType represents the allowed values for TurnEventType. +type TurnEventType string + +const ( + TurnEventTypeTurnStart TurnEventType = "turn_start" + TurnEventTypeTurnEnd TurnEventType = "turn_end" + TurnEventTypeLlmStart TurnEventType = "llm_start" + TurnEventTypeLlmComplete TurnEventType = "llm_complete" + TurnEventTypeRetry TurnEventType = "retry" + TurnEventTypePermissionRequested TurnEventType = "permission_requested" + TurnEventTypePermissionCompleted TurnEventType = "permission_completed" + TurnEventTypeToken TurnEventType = "token" + TurnEventTypeThinking TurnEventType = "thinking" + TurnEventTypeToolCallStart TurnEventType = "tool_call_start" + TurnEventTypeToolCallComplete TurnEventType = "tool_call_complete" + TurnEventTypeToolResult TurnEventType = "tool_result" + TurnEventTypeStatus TurnEventType = "status" + TurnEventTypeMessagesUpdated TurnEventType = "messages_updated" + TurnEventTypeDone TurnEventType = "done" + TurnEventTypeError TurnEventType = "error" + TurnEventTypeCancelled TurnEventType = "cancelled" + TurnEventTypeCompactionStart TurnEventType = "compaction_start" + TurnEventTypeCompactionComplete TurnEventType = "compaction_complete" + TurnEventTypeCompactionFailed TurnEventType = "compaction_failed" +) + +// TurnEvent represents A canonical event envelope emitted by the turn harness. The payload is kept +// JSON-shaped so runtimes can load all events even when newer payload types are +// added; event-specific typed payload models below define the canonical shapes. + +type TurnEvent struct { + Id string `json:"id" yaml:"id"` + Type TurnEventType `json:"type" yaml:"type"` + Timestamp string `json:"timestamp" yaml:"timestamp"` + TurnId *string `json:"turnId,omitempty" yaml:"turnId,omitempty"` + Iteration *int32 `json:"iteration,omitempty" yaml:"iteration,omitempty"` + ParentId *string `json:"parentId,omitempty" yaml:"parentId,omitempty"` + SpanId *string `json:"spanId,omitempty" yaml:"spanId,omitempty"` + Payload map[string]interface{} `json:"payload" yaml:"payload"` +} + +// LoadTurnEvent creates a TurnEvent from a map[string]interface{} +func LoadTurnEvent(data interface{}, ctx *LoadContext) (TurnEvent, error) { + result := TurnEvent{} + + // Load from map + if m, ok := data.(map[string]interface{}); ok { + if val, ok := m["id"]; ok && val != nil { + result.Id = string(val.(string)) + } + if val, ok := m["type"]; ok && val != nil { + result.Type = TurnEventType(val.(string)) + } + if val, ok := m["timestamp"]; ok && val != nil { + result.Timestamp = string(val.(string)) + } + if val, ok := m["turnId"]; ok && val != nil { + v := string(val.(string)) + result.TurnId = &v + } + if val, ok := m["iteration"]; ok && val != nil { // Handle various numeric types from JSON/YAML/roundtrip + var v int32 + switch n := val.(type) { + case int: + v = int32(n) + case int32: + v = int32(n) + case int64: + v = int32(n) + case float64: + v = int32(n) + } + result.Iteration = &v + } + if val, ok := m["parentId"]; ok && val != nil { + v := string(val.(string)) + result.ParentId = &v + } + if val, ok := m["spanId"]; ok && val != nil { + v := string(val.(string)) + result.SpanId = &v + } + if val, ok := m["payload"]; ok && val != nil { + if m, ok := val.(map[string]interface{}); ok { + result.Payload = m + } + } + } + + return result, nil +} + +// Save serializes TurnEvent to map[string]interface{} +func (obj *TurnEvent) Save(ctx *SaveContext) map[string]interface{} { + result := make(map[string]interface{}) + result["id"] = obj.Id + result["type"] = string(obj.Type) + result["timestamp"] = obj.Timestamp + if obj.TurnId != nil { + result["turnId"] = *obj.TurnId + } + if obj.Iteration != nil { + result["iteration"] = *obj.Iteration + } + if obj.ParentId != nil { + result["parentId"] = *obj.ParentId + } + if obj.SpanId != nil { + result["spanId"] = *obj.SpanId + } + result["payload"] = obj.Payload + + return result +} + +// ToJSON serializes TurnEvent to JSON string +func (obj *TurnEvent) ToJSON() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := json.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// ToYAML serializes TurnEvent to YAML string +func (obj *TurnEvent) ToYAML() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := yaml.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// FromJSON creates TurnEvent from JSON string +func TurnEventFromJSON(jsonStr string) (TurnEvent, error) { + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { + return TurnEvent{}, err + } + ctx := NewLoadContext() + return LoadTurnEvent(data, ctx) +} + +// FromYAML creates TurnEvent from YAML string +func TurnEventFromYAML(yamlStr string) (TurnEvent, error) { + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlStr), &data); err != nil { + return TurnEvent{}, err + } + ctx := NewLoadContext() + return LoadTurnEvent(data, ctx) +} diff --git a/runtime/go/prompty/model/turn_event_test.go b/runtime/go/prompty/model/turn_event_test.go new file mode 100644 index 00000000..b1fc2dcb --- /dev/null +++ b/runtime/go/prompty/model/turn_event_test.go @@ -0,0 +1,210 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +package prompty_test + +import ( + "encoding/json" + "testing" + + "gopkg.in/yaml.v3" + + "prompty/model" +) + +// TestTurnEventLoadJSON tests loading TurnEvent from JSON +func TestTurnEventLoadJSON(t *testing.T) { + jsonData := ` +{ + "id": "evt_abc123", + "timestamp": "2026-06-09T20:00:00Z", + "turnId": "turn_001", + "iteration": 0, + "parentId": "evt_parent", + "spanId": "span_tool_001" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadTurnEvent(data, ctx) + if err != nil { + t.Fatalf("Failed to load TurnEvent: %v", err) + } + if instance.Id != "evt_abc123" { + t.Errorf(`Expected Id to be "evt_abc123", got %v`, instance.Id) + } + if instance.Timestamp != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected Timestamp to be "2026-06-09T20:00:00Z", got %v`, instance.Timestamp) + } + if instance.TurnId == nil || *instance.TurnId != "turn_001" { + t.Errorf(`Expected TurnId to be "turn_001", got %v`, instance.TurnId) + } + if instance.Iteration == nil || *instance.Iteration != 0 { + t.Errorf(`Expected Iteration to be 0, got %v`, instance.Iteration) + } + if instance.ParentId == nil || *instance.ParentId != "evt_parent" { + t.Errorf(`Expected ParentId to be "evt_parent", got %v`, instance.ParentId) + } + if instance.SpanId == nil || *instance.SpanId != "span_tool_001" { + t.Errorf(`Expected SpanId to be "span_tool_001", got %v`, instance.SpanId) + } +} + +// TestTurnEventLoadYAML tests loading TurnEvent from YAML +func TestTurnEventLoadYAML(t *testing.T) { + yamlData := ` +id: evt_abc123 +timestamp: "2026-06-09T20:00:00Z" +turnId: turn_001 +iteration: 0 +parentId: evt_parent +spanId: span_tool_001 + +` + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlData), &data); err != nil { + t.Fatalf("Failed to parse YAML: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadTurnEvent(data, ctx) + if err != nil { + t.Fatalf("Failed to load TurnEvent: %v", err) + } + if instance.Id != "evt_abc123" { + t.Errorf(`Expected Id to be "evt_abc123", got %v`, instance.Id) + } + if instance.Timestamp != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected Timestamp to be "2026-06-09T20:00:00Z", got %v`, instance.Timestamp) + } + if instance.TurnId == nil || *instance.TurnId != "turn_001" { + t.Errorf(`Expected TurnId to be "turn_001", got %v`, instance.TurnId) + } + if instance.Iteration == nil || *instance.Iteration != 0 { + t.Errorf(`Expected Iteration to be 0, got %v`, instance.Iteration) + } + if instance.ParentId == nil || *instance.ParentId != "evt_parent" { + t.Errorf(`Expected ParentId to be "evt_parent", got %v`, instance.ParentId) + } + if instance.SpanId == nil || *instance.SpanId != "span_tool_001" { + t.Errorf(`Expected SpanId to be "span_tool_001", got %v`, instance.SpanId) + } +} + +// TestTurnEventRoundtrip tests load -> save -> load produces equivalent data +func TestTurnEventRoundtrip(t *testing.T) { + jsonData := ` +{ + "id": "evt_abc123", + "timestamp": "2026-06-09T20:00:00Z", + "turnId": "turn_001", + "iteration": 0, + "parentId": "evt_parent", + "spanId": "span_tool_001" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + loadCtx := prompty.NewLoadContext() + instance, err := prompty.LoadTurnEvent(data, loadCtx) + if err != nil { + t.Fatalf("Failed to load TurnEvent: %v", err) + } + saveCtx := prompty.NewSaveContext() + savedData := instance.Save(saveCtx) + + reloaded, err := prompty.LoadTurnEvent(savedData, loadCtx) + if err != nil { + t.Fatalf("Failed to reload TurnEvent: %v", err) + } + if reloaded.Id != "evt_abc123" { + t.Errorf(`Expected Id to be "evt_abc123", got %v`, reloaded.Id) + } + if reloaded.Timestamp != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected Timestamp to be "2026-06-09T20:00:00Z", got %v`, reloaded.Timestamp) + } + if reloaded.TurnId == nil || *reloaded.TurnId != "turn_001" { + t.Errorf(`Expected TurnId to be "turn_001", got %v`, reloaded.TurnId) + } + if reloaded.Iteration == nil || *reloaded.Iteration != 0 { + t.Errorf(`Expected Iteration to be 0, got %v`, reloaded.Iteration) + } + if reloaded.ParentId == nil || *reloaded.ParentId != "evt_parent" { + t.Errorf(`Expected ParentId to be "evt_parent", got %v`, reloaded.ParentId) + } + if reloaded.SpanId == nil || *reloaded.SpanId != "span_tool_001" { + t.Errorf(`Expected SpanId to be "span_tool_001", got %v`, reloaded.SpanId) + } +} + +// TestTurnEventToJSON tests that ToJSON produces valid JSON +func TestTurnEventToJSON(t *testing.T) { + jsonData := ` +{ + "id": "evt_abc123", + "timestamp": "2026-06-09T20:00:00Z", + "turnId": "turn_001", + "iteration": 0, + "parentId": "evt_parent", + "spanId": "span_tool_001" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadTurnEvent(data, ctx) + if err != nil { + t.Fatalf("Failed to load TurnEvent: %v", err) + } + jsonOutput, err := instance.ToJSON() + if err != nil { + t.Fatalf("Failed to convert to JSON: %v", err) + } + + var parsed map[string]interface{} + if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated JSON: %v", err) + } +} + +// TestTurnEventToYAML tests that ToYAML produces valid YAML +func TestTurnEventToYAML(t *testing.T) { + jsonData := ` +{ + "id": "evt_abc123", + "timestamp": "2026-06-09T20:00:00Z", + "turnId": "turn_001", + "iteration": 0, + "parentId": "evt_parent", + "spanId": "span_tool_001" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadTurnEvent(data, ctx) + if err != nil { + t.Fatalf("Failed to load TurnEvent: %v", err) + } + yamlOutput, err := instance.ToYAML() + if err != nil { + t.Fatalf("Failed to convert to YAML: %v", err) + } + + var parsed map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated YAML: %v", err) + } +} diff --git a/runtime/go/prompty/model/turn_start_payload.go b/runtime/go/prompty/model/turn_start_payload.go new file mode 100644 index 00000000..c127fa7a --- /dev/null +++ b/runtime/go/prompty/model/turn_start_payload.go @@ -0,0 +1,110 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: events + +package prompty + +import ( + "encoding/json" + + "gopkg.in/yaml.v3" +) + +// TurnStartPayload represents Payload for "turn_start" events — a turn is beginning. + +type TurnStartPayload struct { + Agent *string `json:"agent,omitempty" yaml:"agent,omitempty"` + Inputs map[string]interface{} `json:"inputs,omitempty" yaml:"inputs,omitempty"` + MaxIterations *int32 `json:"maxIterations,omitempty" yaml:"maxIterations,omitempty"` +} + +// LoadTurnStartPayload creates a TurnStartPayload from a map[string]interface{} +func LoadTurnStartPayload(data interface{}, ctx *LoadContext) (TurnStartPayload, error) { + result := TurnStartPayload{} + + // Load from map + if m, ok := data.(map[string]interface{}); ok { + if val, ok := m["agent"]; ok && val != nil { + v := string(val.(string)) + result.Agent = &v + } + if val, ok := m["inputs"]; ok && val != nil { + if m, ok := val.(map[string]interface{}); ok { + result.Inputs = m + } + } + if val, ok := m["maxIterations"]; ok && val != nil { // Handle various numeric types from JSON/YAML/roundtrip + var v int32 + switch n := val.(type) { + case int: + v = int32(n) + case int32: + v = int32(n) + case int64: + v = int32(n) + case float64: + v = int32(n) + } + result.MaxIterations = &v + } + } + + return result, nil +} + +// Save serializes TurnStartPayload to map[string]interface{} +func (obj *TurnStartPayload) Save(ctx *SaveContext) map[string]interface{} { + result := make(map[string]interface{}) + if obj.Agent != nil { + result["agent"] = *obj.Agent + } + if obj.Inputs != nil { + result["inputs"] = obj.Inputs + } + if obj.MaxIterations != nil { + result["maxIterations"] = *obj.MaxIterations + } + + return result +} + +// ToJSON serializes TurnStartPayload to JSON string +func (obj *TurnStartPayload) ToJSON() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := json.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// ToYAML serializes TurnStartPayload to YAML string +func (obj *TurnStartPayload) ToYAML() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := yaml.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// FromJSON creates TurnStartPayload from JSON string +func TurnStartPayloadFromJSON(jsonStr string) (TurnStartPayload, error) { + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { + return TurnStartPayload{}, err + } + ctx := NewLoadContext() + return LoadTurnStartPayload(data, ctx) +} + +// FromYAML creates TurnStartPayload from YAML string +func TurnStartPayloadFromYAML(yamlStr string) (TurnStartPayload, error) { + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlStr), &data); err != nil { + return TurnStartPayload{}, err + } + ctx := NewLoadContext() + return LoadTurnStartPayload(data, ctx) +} diff --git a/runtime/go/prompty/model/turn_start_payload_test.go b/runtime/go/prompty/model/turn_start_payload_test.go new file mode 100644 index 00000000..d9af183b --- /dev/null +++ b/runtime/go/prompty/model/turn_start_payload_test.go @@ -0,0 +1,154 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +package prompty_test + +import ( + "encoding/json" + "testing" + + "gopkg.in/yaml.v3" + + "prompty/model" +) + +// TestTurnStartPayloadLoadJSON tests loading TurnStartPayload from JSON +func TestTurnStartPayloadLoadJSON(t *testing.T) { + jsonData := ` +{ + "agent": "weather-agent", + "maxIterations": 10 +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadTurnStartPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load TurnStartPayload: %v", err) + } + if instance.Agent == nil || *instance.Agent != "weather-agent" { + t.Errorf(`Expected Agent to be "weather-agent", got %v`, instance.Agent) + } + if instance.MaxIterations == nil || *instance.MaxIterations != 10 { + t.Errorf(`Expected MaxIterations to be 10, got %v`, instance.MaxIterations) + } +} + +// TestTurnStartPayloadLoadYAML tests loading TurnStartPayload from YAML +func TestTurnStartPayloadLoadYAML(t *testing.T) { + yamlData := ` +agent: weather-agent +maxIterations: 10 + +` + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlData), &data); err != nil { + t.Fatalf("Failed to parse YAML: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadTurnStartPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load TurnStartPayload: %v", err) + } + if instance.Agent == nil || *instance.Agent != "weather-agent" { + t.Errorf(`Expected Agent to be "weather-agent", got %v`, instance.Agent) + } + if instance.MaxIterations == nil || *instance.MaxIterations != 10 { + t.Errorf(`Expected MaxIterations to be 10, got %v`, instance.MaxIterations) + } +} + +// TestTurnStartPayloadRoundtrip tests load -> save -> load produces equivalent data +func TestTurnStartPayloadRoundtrip(t *testing.T) { + jsonData := ` +{ + "agent": "weather-agent", + "maxIterations": 10 +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + loadCtx := prompty.NewLoadContext() + instance, err := prompty.LoadTurnStartPayload(data, loadCtx) + if err != nil { + t.Fatalf("Failed to load TurnStartPayload: %v", err) + } + saveCtx := prompty.NewSaveContext() + savedData := instance.Save(saveCtx) + + reloaded, err := prompty.LoadTurnStartPayload(savedData, loadCtx) + if err != nil { + t.Fatalf("Failed to reload TurnStartPayload: %v", err) + } + if reloaded.Agent == nil || *reloaded.Agent != "weather-agent" { + t.Errorf(`Expected Agent to be "weather-agent", got %v`, reloaded.Agent) + } + if reloaded.MaxIterations == nil || *reloaded.MaxIterations != 10 { + t.Errorf(`Expected MaxIterations to be 10, got %v`, reloaded.MaxIterations) + } +} + +// TestTurnStartPayloadToJSON tests that ToJSON produces valid JSON +func TestTurnStartPayloadToJSON(t *testing.T) { + jsonData := ` +{ + "agent": "weather-agent", + "maxIterations": 10 +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadTurnStartPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load TurnStartPayload: %v", err) + } + jsonOutput, err := instance.ToJSON() + if err != nil { + t.Fatalf("Failed to convert to JSON: %v", err) + } + + var parsed map[string]interface{} + if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated JSON: %v", err) + } +} + +// TestTurnStartPayloadToYAML tests that ToYAML produces valid YAML +func TestTurnStartPayloadToYAML(t *testing.T) { + jsonData := ` +{ + "agent": "weather-agent", + "maxIterations": 10 +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadTurnStartPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load TurnStartPayload: %v", err) + } + yamlOutput, err := instance.ToYAML() + if err != nil { + t.Fatalf("Failed to convert to YAML: %v", err) + } + + var parsed map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated YAML: %v", err) + } +} diff --git a/runtime/go/prompty/model/turn_summary.go b/runtime/go/prompty/model/turn_summary.go new file mode 100644 index 00000000..56be90fe --- /dev/null +++ b/runtime/go/prompty/model/turn_summary.go @@ -0,0 +1,185 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: events + +package prompty + +import ( + "encoding/json" + + "gopkg.in/yaml.v3" +) + +// TurnSummary represents Summary statistics for a completed turn trace. + +type TurnSummary struct { + TurnId string `json:"turnId" yaml:"turnId"` + Status string `json:"status" yaml:"status"` + Iterations int32 `json:"iterations" yaml:"iterations"` + LlmCalls *int32 `json:"llmCalls,omitempty" yaml:"llmCalls,omitempty"` + ToolCalls *int32 `json:"toolCalls,omitempty" yaml:"toolCalls,omitempty"` + Retries *int32 `json:"retries,omitempty" yaml:"retries,omitempty"` + Usage *TokenUsage `json:"usage,omitempty" yaml:"usage,omitempty"` + DurationMs *float64 `json:"durationMs,omitempty" yaml:"durationMs,omitempty"` +} + +// LoadTurnSummary creates a TurnSummary from a map[string]interface{} +func LoadTurnSummary(data interface{}, ctx *LoadContext) (TurnSummary, error) { + result := TurnSummary{} + + // Load from map + if m, ok := data.(map[string]interface{}); ok { + if val, ok := m["turnId"]; ok && val != nil { + result.TurnId = string(val.(string)) + } + if val, ok := m["status"]; ok && val != nil { + result.Status = string(val.(string)) + } + if val, ok := m["iterations"]; ok && val != nil { // Handle various numeric types from JSON/YAML/roundtrip + var v int32 + switch n := val.(type) { + case int: + v = int32(n) + case int32: + v = int32(n) + case int64: + v = int32(n) + case float64: + v = int32(n) + } + result.Iterations = v + } + if val, ok := m["llmCalls"]; ok && val != nil { // Handle various numeric types from JSON/YAML/roundtrip + var v int32 + switch n := val.(type) { + case int: + v = int32(n) + case int32: + v = int32(n) + case int64: + v = int32(n) + case float64: + v = int32(n) + } + result.LlmCalls = &v + } + if val, ok := m["toolCalls"]; ok && val != nil { // Handle various numeric types from JSON/YAML/roundtrip + var v int32 + switch n := val.(type) { + case int: + v = int32(n) + case int32: + v = int32(n) + case int64: + v = int32(n) + case float64: + v = int32(n) + } + result.ToolCalls = &v + } + if val, ok := m["retries"]; ok && val != nil { // Handle various numeric types from JSON/YAML/roundtrip + var v int32 + switch n := val.(type) { + case int: + v = int32(n) + case int32: + v = int32(n) + case int64: + v = int32(n) + case float64: + v = int32(n) + } + result.Retries = &v + } + if val, ok := m["usage"]; ok && val != nil { + if m, ok := val.(map[string]interface{}); ok { + loaded, _ := LoadTokenUsage(m, ctx) + result.Usage = &loaded + } + } + if val, ok := m["durationMs"]; ok && val != nil { // Handle various numeric types from JSON/YAML/roundtrip + var v float64 + switch n := val.(type) { + case int: + v = float64(n) + case int32: + v = float64(n) + case int64: + v = float64(n) + case float32: + v = float64(n) + case float64: + v = n + } + result.DurationMs = &v + } + } + + return result, nil +} + +// Save serializes TurnSummary to map[string]interface{} +func (obj *TurnSummary) Save(ctx *SaveContext) map[string]interface{} { + result := make(map[string]interface{}) + result["turnId"] = obj.TurnId + result["status"] = obj.Status + result["iterations"] = obj.Iterations + if obj.LlmCalls != nil { + result["llmCalls"] = *obj.LlmCalls + } + if obj.ToolCalls != nil { + result["toolCalls"] = *obj.ToolCalls + } + if obj.Retries != nil { + result["retries"] = *obj.Retries + } + if obj.Usage != nil { + result["usage"] = obj.Usage.Save(ctx) + } + if obj.DurationMs != nil { + result["durationMs"] = *obj.DurationMs + } + + return result +} + +// ToJSON serializes TurnSummary to JSON string +func (obj *TurnSummary) ToJSON() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := json.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// ToYAML serializes TurnSummary to YAML string +func (obj *TurnSummary) ToYAML() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := yaml.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// FromJSON creates TurnSummary from JSON string +func TurnSummaryFromJSON(jsonStr string) (TurnSummary, error) { + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { + return TurnSummary{}, err + } + ctx := NewLoadContext() + return LoadTurnSummary(data, ctx) +} + +// FromYAML creates TurnSummary from YAML string +func TurnSummaryFromYAML(yamlStr string) (TurnSummary, error) { + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlStr), &data); err != nil { + return TurnSummary{}, err + } + ctx := NewLoadContext() + return LoadTurnSummary(data, ctx) +} diff --git a/runtime/go/prompty/model/turn_summary_test.go b/runtime/go/prompty/model/turn_summary_test.go new file mode 100644 index 00000000..feb7c04c --- /dev/null +++ b/runtime/go/prompty/model/turn_summary_test.go @@ -0,0 +1,224 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +package prompty_test + +import ( + "encoding/json" + "testing" + + "gopkg.in/yaml.v3" + + "prompty/model" +) + +// TestTurnSummaryLoadJSON tests loading TurnSummary from JSON +func TestTurnSummaryLoadJSON(t *testing.T) { + jsonData := ` +{ + "turnId": "turn_001", + "status": "success", + "iterations": 2, + "llmCalls": 3, + "toolCalls": 2, + "retries": 1, + "durationMs": 2500 +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadTurnSummary(data, ctx) + if err != nil { + t.Fatalf("Failed to load TurnSummary: %v", err) + } + if instance.TurnId != "turn_001" { + t.Errorf(`Expected TurnId to be "turn_001", got %v`, instance.TurnId) + } + if instance.Status != "success" { + t.Errorf(`Expected Status to be "success", got %v`, instance.Status) + } + if instance.Iterations != 2 { + t.Errorf(`Expected Iterations to be 2, got %v`, instance.Iterations) + } + if instance.LlmCalls == nil || *instance.LlmCalls != 3 { + t.Errorf(`Expected LlmCalls to be 3, got %v`, instance.LlmCalls) + } + if instance.ToolCalls == nil || *instance.ToolCalls != 2 { + t.Errorf(`Expected ToolCalls to be 2, got %v`, instance.ToolCalls) + } + if instance.Retries == nil || *instance.Retries != 1 { + t.Errorf(`Expected Retries to be 1, got %v`, instance.Retries) + } + if instance.DurationMs == nil || *instance.DurationMs != 2500 { + t.Errorf(`Expected DurationMs to be 2500, got %v`, instance.DurationMs) + } +} + +// TestTurnSummaryLoadYAML tests loading TurnSummary from YAML +func TestTurnSummaryLoadYAML(t *testing.T) { + yamlData := ` +turnId: turn_001 +status: success +iterations: 2 +llmCalls: 3 +toolCalls: 2 +retries: 1 +durationMs: 2500 + +` + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlData), &data); err != nil { + t.Fatalf("Failed to parse YAML: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadTurnSummary(data, ctx) + if err != nil { + t.Fatalf("Failed to load TurnSummary: %v", err) + } + if instance.TurnId != "turn_001" { + t.Errorf(`Expected TurnId to be "turn_001", got %v`, instance.TurnId) + } + if instance.Status != "success" { + t.Errorf(`Expected Status to be "success", got %v`, instance.Status) + } + if instance.Iterations != 2 { + t.Errorf(`Expected Iterations to be 2, got %v`, instance.Iterations) + } + if instance.LlmCalls == nil || *instance.LlmCalls != 3 { + t.Errorf(`Expected LlmCalls to be 3, got %v`, instance.LlmCalls) + } + if instance.ToolCalls == nil || *instance.ToolCalls != 2 { + t.Errorf(`Expected ToolCalls to be 2, got %v`, instance.ToolCalls) + } + if instance.Retries == nil || *instance.Retries != 1 { + t.Errorf(`Expected Retries to be 1, got %v`, instance.Retries) + } + if instance.DurationMs == nil || *instance.DurationMs != 2500 { + t.Errorf(`Expected DurationMs to be 2500, got %v`, instance.DurationMs) + } +} + +// TestTurnSummaryRoundtrip tests load -> save -> load produces equivalent data +func TestTurnSummaryRoundtrip(t *testing.T) { + jsonData := ` +{ + "turnId": "turn_001", + "status": "success", + "iterations": 2, + "llmCalls": 3, + "toolCalls": 2, + "retries": 1, + "durationMs": 2500 +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + loadCtx := prompty.NewLoadContext() + instance, err := prompty.LoadTurnSummary(data, loadCtx) + if err != nil { + t.Fatalf("Failed to load TurnSummary: %v", err) + } + saveCtx := prompty.NewSaveContext() + savedData := instance.Save(saveCtx) + + reloaded, err := prompty.LoadTurnSummary(savedData, loadCtx) + if err != nil { + t.Fatalf("Failed to reload TurnSummary: %v", err) + } + if reloaded.TurnId != "turn_001" { + t.Errorf(`Expected TurnId to be "turn_001", got %v`, reloaded.TurnId) + } + if reloaded.Status != "success" { + t.Errorf(`Expected Status to be "success", got %v`, reloaded.Status) + } + if reloaded.Iterations != 2 { + t.Errorf(`Expected Iterations to be 2, got %v`, reloaded.Iterations) + } + if reloaded.LlmCalls == nil || *reloaded.LlmCalls != 3 { + t.Errorf(`Expected LlmCalls to be 3, got %v`, reloaded.LlmCalls) + } + if reloaded.ToolCalls == nil || *reloaded.ToolCalls != 2 { + t.Errorf(`Expected ToolCalls to be 2, got %v`, reloaded.ToolCalls) + } + if reloaded.Retries == nil || *reloaded.Retries != 1 { + t.Errorf(`Expected Retries to be 1, got %v`, reloaded.Retries) + } + if reloaded.DurationMs == nil || *reloaded.DurationMs != 2500 { + t.Errorf(`Expected DurationMs to be 2500, got %v`, reloaded.DurationMs) + } +} + +// TestTurnSummaryToJSON tests that ToJSON produces valid JSON +func TestTurnSummaryToJSON(t *testing.T) { + jsonData := ` +{ + "turnId": "turn_001", + "status": "success", + "iterations": 2, + "llmCalls": 3, + "toolCalls": 2, + "retries": 1, + "durationMs": 2500 +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadTurnSummary(data, ctx) + if err != nil { + t.Fatalf("Failed to load TurnSummary: %v", err) + } + jsonOutput, err := instance.ToJSON() + if err != nil { + t.Fatalf("Failed to convert to JSON: %v", err) + } + + var parsed map[string]interface{} + if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated JSON: %v", err) + } +} + +// TestTurnSummaryToYAML tests that ToYAML produces valid YAML +func TestTurnSummaryToYAML(t *testing.T) { + jsonData := ` +{ + "turnId": "turn_001", + "status": "success", + "iterations": 2, + "llmCalls": 3, + "toolCalls": 2, + "retries": 1, + "durationMs": 2500 +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadTurnSummary(data, ctx) + if err != nil { + t.Fatalf("Failed to load TurnSummary: %v", err) + } + yamlOutput, err := instance.ToYAML() + if err != nil { + t.Fatalf("Failed to convert to YAML: %v", err) + } + + var parsed map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated YAML: %v", err) + } +} diff --git a/runtime/go/prompty/model/turn_trace.go b/runtime/go/prompty/model/turn_trace.go new file mode 100644 index 00000000..92693f33 --- /dev/null +++ b/runtime/go/prompty/model/turn_trace.go @@ -0,0 +1,125 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: events + +package prompty + +import ( + "encoding/json" + + "gopkg.in/yaml.v3" +) + +// TurnTrace represents Portable JSONL/replay container for a recorded turn harness run. + +type TurnTrace struct { + Version string `json:"version" yaml:"version"` + Runtime *string `json:"runtime,omitempty" yaml:"runtime,omitempty"` + PromptyVersion *string `json:"promptyVersion,omitempty" yaml:"promptyVersion,omitempty"` + Events []TurnEvent `json:"events" yaml:"events"` + Summary *TurnSummary `json:"summary,omitempty" yaml:"summary,omitempty"` +} + +// LoadTurnTrace creates a TurnTrace from a map[string]interface{} +func LoadTurnTrace(data interface{}, ctx *LoadContext) (TurnTrace, error) { + result := TurnTrace{} + + // Load from map + if m, ok := data.(map[string]interface{}); ok { + if val, ok := m["version"]; ok && val != nil { + result.Version = string(val.(string)) + } + if val, ok := m["runtime"]; ok && val != nil { + v := string(val.(string)) + result.Runtime = &v + } + if val, ok := m["promptyVersion"]; ok && val != nil { + v := string(val.(string)) + result.PromptyVersion = &v + } + if val, ok := m["events"]; ok && val != nil { + if arr, ok := val.([]interface{}); ok { + result.Events = make([]TurnEvent, len(arr)) + for i, v := range arr { + if item, ok := v.(map[string]interface{}); ok { + loaded, _ := LoadTurnEvent(item, ctx) + result.Events[i] = loaded + } + } + } + } + if val, ok := m["summary"]; ok && val != nil { + if m, ok := val.(map[string]interface{}); ok { + loaded, _ := LoadTurnSummary(m, ctx) + result.Summary = &loaded + } + } + } + + return result, nil +} + +// Save serializes TurnTrace to map[string]interface{} +func (obj *TurnTrace) Save(ctx *SaveContext) map[string]interface{} { + result := make(map[string]interface{}) + result["version"] = obj.Version + if obj.Runtime != nil { + result["runtime"] = *obj.Runtime + } + if obj.PromptyVersion != nil { + result["promptyVersion"] = *obj.PromptyVersion + } + if obj.Events != nil { + arr := make([]interface{}, len(obj.Events)) + for i, item := range obj.Events { + arr[i] = item.Save(ctx) + } + result["events"] = arr + } + if obj.Summary != nil { + result["summary"] = obj.Summary.Save(ctx) + } + + return result +} + +// ToJSON serializes TurnTrace to JSON string +func (obj *TurnTrace) ToJSON() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := json.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// ToYAML serializes TurnTrace to YAML string +func (obj *TurnTrace) ToYAML() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := yaml.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// FromJSON creates TurnTrace from JSON string +func TurnTraceFromJSON(jsonStr string) (TurnTrace, error) { + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { + return TurnTrace{}, err + } + ctx := NewLoadContext() + return LoadTurnTrace(data, ctx) +} + +// FromYAML creates TurnTrace from YAML string +func TurnTraceFromYAML(yamlStr string) (TurnTrace, error) { + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlStr), &data); err != nil { + return TurnTrace{}, err + } + ctx := NewLoadContext() + return LoadTurnTrace(data, ctx) +} diff --git a/runtime/go/prompty/model/turn_trace_test.go b/runtime/go/prompty/model/turn_trace_test.go new file mode 100644 index 00000000..2de9b5ac --- /dev/null +++ b/runtime/go/prompty/model/turn_trace_test.go @@ -0,0 +1,168 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +package prompty_test + +import ( + "encoding/json" + "testing" + + "gopkg.in/yaml.v3" + + "prompty/model" +) + +// TestTurnTraceLoadJSON tests loading TurnTrace from JSON +func TestTurnTraceLoadJSON(t *testing.T) { + jsonData := ` +{ + "version": "1", + "runtime": "typescript", + "promptyVersion": "2.0.0" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadTurnTrace(data, ctx) + if err != nil { + t.Fatalf("Failed to load TurnTrace: %v", err) + } + if instance.Version != "1" { + t.Errorf(`Expected Version to be "1", got %v`, instance.Version) + } + if instance.Runtime == nil || *instance.Runtime != "typescript" { + t.Errorf(`Expected Runtime to be "typescript", got %v`, instance.Runtime) + } + if instance.PromptyVersion == nil || *instance.PromptyVersion != "2.0.0" { + t.Errorf(`Expected PromptyVersion to be "2.0.0", got %v`, instance.PromptyVersion) + } +} + +// TestTurnTraceLoadYAML tests loading TurnTrace from YAML +func TestTurnTraceLoadYAML(t *testing.T) { + yamlData := ` +version: "1" +runtime: typescript +promptyVersion: 2.0.0 + +` + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlData), &data); err != nil { + t.Fatalf("Failed to parse YAML: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadTurnTrace(data, ctx) + if err != nil { + t.Fatalf("Failed to load TurnTrace: %v", err) + } + if instance.Version != "1" { + t.Errorf(`Expected Version to be "1", got %v`, instance.Version) + } + if instance.Runtime == nil || *instance.Runtime != "typescript" { + t.Errorf(`Expected Runtime to be "typescript", got %v`, instance.Runtime) + } + if instance.PromptyVersion == nil || *instance.PromptyVersion != "2.0.0" { + t.Errorf(`Expected PromptyVersion to be "2.0.0", got %v`, instance.PromptyVersion) + } +} + +// TestTurnTraceRoundtrip tests load -> save -> load produces equivalent data +func TestTurnTraceRoundtrip(t *testing.T) { + jsonData := ` +{ + "version": "1", + "runtime": "typescript", + "promptyVersion": "2.0.0" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + loadCtx := prompty.NewLoadContext() + instance, err := prompty.LoadTurnTrace(data, loadCtx) + if err != nil { + t.Fatalf("Failed to load TurnTrace: %v", err) + } + saveCtx := prompty.NewSaveContext() + savedData := instance.Save(saveCtx) + + reloaded, err := prompty.LoadTurnTrace(savedData, loadCtx) + if err != nil { + t.Fatalf("Failed to reload TurnTrace: %v", err) + } + if reloaded.Version != "1" { + t.Errorf(`Expected Version to be "1", got %v`, reloaded.Version) + } + if reloaded.Runtime == nil || *reloaded.Runtime != "typescript" { + t.Errorf(`Expected Runtime to be "typescript", got %v`, reloaded.Runtime) + } + if reloaded.PromptyVersion == nil || *reloaded.PromptyVersion != "2.0.0" { + t.Errorf(`Expected PromptyVersion to be "2.0.0", got %v`, reloaded.PromptyVersion) + } +} + +// TestTurnTraceToJSON tests that ToJSON produces valid JSON +func TestTurnTraceToJSON(t *testing.T) { + jsonData := ` +{ + "version": "1", + "runtime": "typescript", + "promptyVersion": "2.0.0" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadTurnTrace(data, ctx) + if err != nil { + t.Fatalf("Failed to load TurnTrace: %v", err) + } + jsonOutput, err := instance.ToJSON() + if err != nil { + t.Fatalf("Failed to convert to JSON: %v", err) + } + + var parsed map[string]interface{} + if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated JSON: %v", err) + } +} + +// TestTurnTraceToYAML tests that ToYAML produces valid YAML +func TestTurnTraceToYAML(t *testing.T) { + jsonData := ` +{ + "version": "1", + "runtime": "typescript", + "promptyVersion": "2.0.0" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadTurnTrace(data, ctx) + if err != nil { + t.Fatalf("Failed to load TurnTrace: %v", err) + } + yamlOutput, err := instance.ToYAML() + if err != nil { + t.Fatalf("Failed to convert to YAML: %v", err) + } + + var parsed map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated YAML: %v", err) + } +} diff --git a/runtime/python/prompty/prompty/core/agent_events.py b/runtime/python/prompty/prompty/core/agent_events.py index de344751..41643daa 100644 --- a/runtime/python/prompty/prompty/core/agent_events.py +++ b/runtime/python/prompty/prompty/core/agent_events.py @@ -8,7 +8,9 @@ from collections.abc import Callable from dataclasses import dataclass +from datetime import UTC, datetime from typing import Any +from uuid import uuid4 __all__ = [ "AgentEvent", @@ -52,7 +54,19 @@ def emit_event( if callback is None: return try: - callback(event_type, data or {}) + payload = data or {} + event_data = dict(payload) + event_data.setdefault( + "turnEvent", + { + "id": f"evt_{uuid4().hex}", + "type": event_type, + "timestamp": datetime.now(UTC).isoformat().replace("+00:00", "Z"), + "iteration": payload.get("iteration") if isinstance(payload.get("iteration"), int) else None, + "payload": payload, + }, + ) + callback(event_type, event_data) except Exception as exc: # noqa: BLE001 — spec says log and continue import logging diff --git a/runtime/python/prompty/prompty/core/pipeline.py b/runtime/python/prompty/prompty/core/pipeline.py index c3f61ede..ba508ff6 100644 --- a/runtime/python/prompty/prompty/core/pipeline.py +++ b/runtime/python/prompty/prompty/core/pipeline.py @@ -654,6 +654,16 @@ def _invoke_with_retry( "status", {"message": f"LLM call failed, retrying (attempt {attempts + 1}/{max_retries})..."}, ) + emit_event( + on_event, + "retry", + { + "operation": "llm", + "attempt": attempts + 1, + "maxAttempts": max_retries, + "reason": str(e), + }, + ) # Exponential backoff with jitter, capped at 60s backoff = min(2**attempts + random.random(), 60) # Check cancellation during backoff @@ -686,6 +696,16 @@ async def _invoke_with_retry_async( "status", {"message": f"LLM call failed, retrying (attempt {attempts + 1}/{max_retries})..."}, ) + emit_event( + on_event, + "retry", + { + "operation": "llm", + "attempt": attempts + 1, + "maxAttempts": max_retries, + "reason": str(e), + }, + ) backoff = min(2**attempts + random.random(), 60) if cancel is not None and cancel.is_cancelled: raise @@ -868,6 +888,20 @@ async def invoke_async( _DEFAULT_MAX_LLM_RETRIES = 3 +def _emit_failed_turn_end( + on_event: EventCallback | None, + exc: BaseException, + *, + iterations: int, + response: Any = None, +) -> None: + status = "cancelled" if isinstance(exc, CancelledError) else "error" + payload: dict[str, Any] = {"iterations": iterations, "status": status} + if response is not None: + payload["response"] = response + emit_event(on_event, "turn_end", payload) + + @trace def turn( prompt: str | Prompty, @@ -955,6 +989,15 @@ def turn( tools = tools or {} parent_inputs = inputs or {} messages = prepare(agent, inputs) + emit_event( + on_event, + "turn_start", + { + "agent": getattr(agent, "name", None), + "inputs": inputs or {}, + "maxIterations": max_iterations, + }, + ) # Fast path: no tools and no loop extensions — single executor + process call (not via run) _has_extensions = ( @@ -965,10 +1008,26 @@ def turn( or steering is not None ) if not tools and not _has_extensions: - response = _invoke_executor(agent, messages) + emit_event( + on_event, + "llm_start", + {"provider": agent.model.provider, "modelId": agent.model.id, "messageCount": len(messages), "attempt": 0}, + ) + try: + response = _invoke_executor(agent, messages) + except Exception as exc: + _emit_failed_turn_end(on_event, exc, iterations=0) + raise + emit_event(on_event, "llm_complete", {}) if raw: + emit_event(on_event, "turn_end", {"iterations": 0, "status": "success", "response": response}) return response - result = process(agent, response) + try: + result = process(agent, response) + except Exception as exc: + _emit_failed_turn_end(on_event, exc, iterations=0, response=response) + raise + emit_event(on_event, "turn_end", {"iterations": 0, "status": "success", "response": result}) if target_type is not None: return cast(result, target_type) return result @@ -984,6 +1043,7 @@ def turn( while True: if cancel is not None and cancel.is_cancelled: emit_event(on_event, "cancelled", {}) + _emit_failed_turn_end(on_event, CancelledError(), iterations=iteration) raise CancelledError() if steering is not None: @@ -1005,6 +1065,9 @@ def turn( gr_input = guardrails.check_input(messages) if not gr_input.allowed: emit_event(on_event, "error", {"message": f"Input guardrail denied: {gr_input.reason}"}) + _emit_failed_turn_end( + on_event, GuardrailError(gr_input.reason or "Input guardrail denied"), iterations=iteration + ) raise GuardrailError(gr_input.reason or "Input guardrail denied") if gr_input.rewrite is not None: messages = gr_input.rewrite @@ -1012,14 +1075,35 @@ def turn( if cancel is not None and cancel.is_cancelled: emit_event(on_event, "cancelled", {}) + _emit_failed_turn_end(on_event, CancelledError(), iterations=iteration) raise CancelledError() # Call LLM (with retry per §9.10 in agent loop) - response = _invoke_with_retry(agent, messages, max_llm_retries, on_event, cancel) + emit_event( + on_event, + "llm_start", + { + "provider": agent.model.provider, + "modelId": agent.model.id, + "messageCount": len(messages), + "attempt": 0, + "iteration": iteration, + }, + ) + try: + response = _invoke_with_retry(agent, messages, max_llm_retries, on_event, cancel) + except Exception as exc: + _emit_failed_turn_end(on_event, exc, iterations=iteration) + raise + emit_event(on_event, "llm_complete", {"iteration": iteration}) # Streaming: consume through processor, extract tool calls if _is_stream(response): - streamed_tool_calls, content = _consume_stream(agent, response, on_event) + try: + streamed_tool_calls, content = _consume_stream(agent, response, on_event) + except Exception as exc: + _emit_failed_turn_end(on_event, exc, iterations=iteration, response=response) + raise if not streamed_tool_calls: if guardrails is not None and content: @@ -1027,12 +1111,21 @@ def turn( gr = guardrails.check_output(assistant_msg) if not gr.allowed: emit_event(on_event, "error", {"message": f"Output guardrail denied: {gr.reason}"}) + _emit_failed_turn_end( + on_event, + GuardrailError(gr.reason or "Output guardrail denied"), + iterations=iteration, + response=content, + ) raise GuardrailError(gr.reason or "Output guardrail denied") if gr.rewrite is not None: content = gr.rewrite t("iterations", iteration) t("result", content) emit_event(on_event, "done", {"response": content, "messages": messages}) + emit_event( + on_event, "turn_end", {"iterations": iteration, "status": "success", "response": content} + ) return content if guardrails is not None and content: @@ -1040,28 +1133,41 @@ def turn( gr = guardrails.check_output(assistant_msg) if not gr.allowed: emit_event(on_event, "error", {"message": f"Output guardrail denied: {gr.reason}"}) + _emit_failed_turn_end( + on_event, + GuardrailError(gr.reason or "Output guardrail denied"), + iterations=iteration, + response=content, + ) raise GuardrailError(gr.reason or "Output guardrail denied") if gr.rewrite is not None: content = gr.rewrite iteration += 1 if iteration > max_iterations: + _emit_failed_turn_end( + on_event, ValueError("Agent loop exceeded max_iterations"), iterations=iteration + ) raise ValueError( f"Agent loop exceeded max_iterations ({max_iterations}). " f"The model kept requesting tool calls. Increase max_iterations or check your tools." ) - tool_messages = _build_tool_messages_from_calls_with_extensions( - streamed_tool_calls, - content, - tools, - agent, - parent_inputs, - on_event=on_event, - cancel=cancel, - guardrails=guardrails, - parallel=parallel_tool_calls, - ) + try: + tool_messages = _build_tool_messages_from_calls_with_extensions( + streamed_tool_calls, + content, + tools, + agent, + parent_inputs, + on_event=on_event, + cancel=cancel, + guardrails=guardrails, + parallel=parallel_tool_calls, + ) + except Exception as exc: + _emit_failed_turn_end(on_event, exc, iterations=iteration, response=content) + raise messages.extend(tool_messages) emit_event(on_event, "messages_updated", {"messages": messages}) continue @@ -1077,27 +1183,38 @@ def turn( gr = guardrails.check_output(assistant_msg) if not gr.allowed: emit_event(on_event, "error", {"message": f"Output guardrail denied: {gr.reason}"}) + _emit_failed_turn_end( + on_event, + GuardrailError(gr.reason or "Output guardrail denied"), + iterations=iteration, + response=text_content, + ) raise GuardrailError(gr.reason or "Output guardrail denied") if gr.rewrite is not None: text_content = gr.rewrite iteration += 1 if iteration > max_iterations: + _emit_failed_turn_end(on_event, ValueError("Agent loop exceeded max_iterations"), iterations=iteration) raise ValueError( f"Agent loop exceeded max_iterations ({max_iterations}). " f"The model kept requesting tool calls. Increase max_iterations or check your tools." ) - tool_messages, _ = _build_tool_result_messages_with_extensions( - response, - tools, - agent, - parent_inputs, - on_event=on_event, - cancel=cancel, - guardrails=guardrails, - parallel=parallel_tool_calls, - ) + try: + tool_messages, _ = _build_tool_result_messages_with_extensions( + response, + tools, + agent, + parent_inputs, + on_event=on_event, + cancel=cancel, + guardrails=guardrails, + parallel=parallel_tool_calls, + ) + except Exception as exc: + _emit_failed_turn_end(on_event, exc, iterations=iteration, response=response) + raise messages.extend(tool_messages) emit_event(on_event, "messages_updated", {"messages": messages}) @@ -1107,17 +1224,29 @@ def turn( # Process final response (directly, not via run) if raw: emit_event(on_event, "done", {"response": response, "messages": messages}) + emit_event(on_event, "turn_end", {"iterations": iteration, "status": "success", "response": response}) return response - processed_result = process(agent, response) + try: + processed_result = process(agent, response) + except Exception as exc: + _emit_failed_turn_end(on_event, exc, iterations=iteration, response=response) + raise if guardrails is not None and isinstance(processed_result, str): assistant_msg = Message(role="assistant", parts=[TextPart(value=processed_result)]) gr = guardrails.check_output(assistant_msg) if not gr.allowed: emit_event(on_event, "error", {"message": f"Output guardrail denied: {gr.reason}"}) + _emit_failed_turn_end( + on_event, + GuardrailError(gr.reason or "Output guardrail denied"), + iterations=iteration, + response=processed_result, + ) raise GuardrailError(gr.reason or "Output guardrail denied") if gr.rewrite is not None: processed_result = gr.rewrite emit_event(on_event, "done", {"response": processed_result, "messages": messages}) + emit_event(on_event, "turn_end", {"iterations": iteration, "status": "success", "response": processed_result}) if target_type is not None: return cast(processed_result, target_type) return processed_result @@ -1152,6 +1281,15 @@ async def turn_async( tools = tools or {} parent_inputs = inputs or {} messages = await prepare_async(agent, inputs) + emit_event( + on_event, + "turn_start", + { + "agent": getattr(agent, "name", None), + "inputs": inputs or {}, + "maxIterations": max_iterations, + }, + ) # Fast path: no tools and no loop extensions — single executor + process call (not via run) _has_extensions = ( @@ -1162,10 +1300,26 @@ async def turn_async( or steering is not None ) if not tools and not _has_extensions: - response = await _invoke_executor_async(agent, messages) + emit_event( + on_event, + "llm_start", + {"provider": agent.model.provider, "modelId": agent.model.id, "messageCount": len(messages), "attempt": 0}, + ) + try: + response = await _invoke_executor_async(agent, messages) + except Exception as exc: + _emit_failed_turn_end(on_event, exc, iterations=0) + raise + emit_event(on_event, "llm_complete", {}) if raw: + emit_event(on_event, "turn_end", {"iterations": 0, "status": "success", "response": response}) return response - result = await process_async(agent, response) + try: + result = await process_async(agent, response) + except Exception as exc: + _emit_failed_turn_end(on_event, exc, iterations=0, response=response) + raise + emit_event(on_event, "turn_end", {"iterations": 0, "status": "success", "response": result}) if target_type is not None: return cast(result, target_type) return result @@ -1181,6 +1335,7 @@ async def turn_async( while True: if cancel is not None and cancel.is_cancelled: emit_event(on_event, "cancelled", {}) + _emit_failed_turn_end(on_event, CancelledError(), iterations=iteration) raise CancelledError() if steering is not None: @@ -1202,6 +1357,9 @@ async def turn_async( gr_input = guardrails.check_input(messages) if not gr_input.allowed: emit_event(on_event, "error", {"message": f"Input guardrail denied: {gr_input.reason}"}) + _emit_failed_turn_end( + on_event, GuardrailError(gr_input.reason or "Input guardrail denied"), iterations=iteration + ) raise GuardrailError(gr_input.reason or "Input guardrail denied") if gr_input.rewrite is not None: messages = gr_input.rewrite @@ -1209,14 +1367,35 @@ async def turn_async( if cancel is not None and cancel.is_cancelled: emit_event(on_event, "cancelled", {}) + _emit_failed_turn_end(on_event, CancelledError(), iterations=iteration) raise CancelledError() # Call LLM (with retry per §9.10 in agent loop) - response = await _invoke_with_retry_async(agent, messages, max_llm_retries, on_event, cancel) + emit_event( + on_event, + "llm_start", + { + "provider": agent.model.provider, + "modelId": agent.model.id, + "messageCount": len(messages), + "attempt": 0, + "iteration": iteration, + }, + ) + try: + response = await _invoke_with_retry_async(agent, messages, max_llm_retries, on_event, cancel) + except Exception as exc: + _emit_failed_turn_end(on_event, exc, iterations=iteration) + raise + emit_event(on_event, "llm_complete", {"iteration": iteration}) # Streaming: consume through processor, extract tool calls if _is_stream(response): - streamed_tool_calls, content = await _consume_stream_async(agent, response, on_event) + try: + streamed_tool_calls, content = await _consume_stream_async(agent, response, on_event) + except Exception as exc: + _emit_failed_turn_end(on_event, exc, iterations=iteration, response=response) + raise if not streamed_tool_calls: if guardrails is not None and content: @@ -1224,12 +1403,21 @@ async def turn_async( gr = guardrails.check_output(assistant_msg) if not gr.allowed: emit_event(on_event, "error", {"message": f"Output guardrail denied: {gr.reason}"}) + _emit_failed_turn_end( + on_event, + GuardrailError(gr.reason or "Output guardrail denied"), + iterations=iteration, + response=content, + ) raise GuardrailError(gr.reason or "Output guardrail denied") if gr.rewrite is not None: content = gr.rewrite t("iterations", iteration) t("result", content) emit_event(on_event, "done", {"response": content, "messages": messages}) + emit_event( + on_event, "turn_end", {"iterations": iteration, "status": "success", "response": content} + ) return content if guardrails is not None and content: @@ -1237,28 +1425,41 @@ async def turn_async( gr = guardrails.check_output(assistant_msg) if not gr.allowed: emit_event(on_event, "error", {"message": f"Output guardrail denied: {gr.reason}"}) + _emit_failed_turn_end( + on_event, + GuardrailError(gr.reason or "Output guardrail denied"), + iterations=iteration, + response=content, + ) raise GuardrailError(gr.reason or "Output guardrail denied") if gr.rewrite is not None: content = gr.rewrite iteration += 1 if iteration > max_iterations: + _emit_failed_turn_end( + on_event, ValueError("Agent loop exceeded max_iterations"), iterations=iteration + ) raise ValueError( f"Agent loop exceeded max_iterations ({max_iterations}). " f"The model kept requesting tool calls. Increase max_iterations or check your tools." ) - tool_messages = await _build_tool_messages_from_calls_with_extensions_async( - streamed_tool_calls, - content, - tools, - agent, - parent_inputs, - on_event=on_event, - cancel=cancel, - guardrails=guardrails, - parallel=parallel_tool_calls, - ) + try: + tool_messages = await _build_tool_messages_from_calls_with_extensions_async( + streamed_tool_calls, + content, + tools, + agent, + parent_inputs, + on_event=on_event, + cancel=cancel, + guardrails=guardrails, + parallel=parallel_tool_calls, + ) + except Exception as exc: + _emit_failed_turn_end(on_event, exc, iterations=iteration, response=content) + raise messages.extend(tool_messages) emit_event(on_event, "messages_updated", {"messages": messages}) continue @@ -1274,27 +1475,38 @@ async def turn_async( gr = guardrails.check_output(assistant_msg) if not gr.allowed: emit_event(on_event, "error", {"message": f"Output guardrail denied: {gr.reason}"}) + _emit_failed_turn_end( + on_event, + GuardrailError(gr.reason or "Output guardrail denied"), + iterations=iteration, + response=text_content, + ) raise GuardrailError(gr.reason or "Output guardrail denied") if gr.rewrite is not None: text_content = gr.rewrite iteration += 1 if iteration > max_iterations: + _emit_failed_turn_end(on_event, ValueError("Agent loop exceeded max_iterations"), iterations=iteration) raise ValueError( f"Agent loop exceeded max_iterations ({max_iterations}). " f"The model kept requesting tool calls. Increase max_iterations or check your tools." ) - tool_messages = await _build_tool_result_messages_with_extensions_async( - response, - tools, - agent, - parent_inputs, - on_event=on_event, - cancel=cancel, - guardrails=guardrails, - parallel=parallel_tool_calls, - ) + try: + tool_messages = await _build_tool_result_messages_with_extensions_async( + response, + tools, + agent, + parent_inputs, + on_event=on_event, + cancel=cancel, + guardrails=guardrails, + parallel=parallel_tool_calls, + ) + except Exception as exc: + _emit_failed_turn_end(on_event, exc, iterations=iteration, response=response) + raise messages.extend(tool_messages) emit_event(on_event, "messages_updated", {"messages": messages}) @@ -1304,17 +1516,29 @@ async def turn_async( # Process final response (directly, not via run) if raw: emit_event(on_event, "done", {"response": response, "messages": messages}) + emit_event(on_event, "turn_end", {"iterations": iteration, "status": "success", "response": response}) return response - processed_result = await process_async(agent, response) + try: + processed_result = await process_async(agent, response) + except Exception as exc: + _emit_failed_turn_end(on_event, exc, iterations=iteration, response=response) + raise if guardrails is not None and isinstance(processed_result, str): assistant_msg = Message(role="assistant", parts=[TextPart(value=processed_result)]) gr = guardrails.check_output(assistant_msg) if not gr.allowed: emit_event(on_event, "error", {"message": f"Output guardrail denied: {gr.reason}"}) + _emit_failed_turn_end( + on_event, + GuardrailError(gr.reason or "Output guardrail denied"), + iterations=iteration, + response=processed_result, + ) raise GuardrailError(gr.reason or "Output guardrail denied") if gr.rewrite is not None: processed_result = gr.rewrite emit_event(on_event, "done", {"response": processed_result, "messages": messages}) + emit_event(on_event, "turn_end", {"iterations": iteration, "status": "success", "response": processed_result}) if target_type is not None: return cast(processed_result, target_type) return processed_result @@ -1872,6 +2096,7 @@ def _dispatch_one(tc: Any) -> str: # §13.1 — Emit tool_call_start emit_event(on_event, "tool_call_start", {"name": name, "arguments": arguments}) + started = time.perf_counter() # §13.4 — Tool guardrail if guardrails is not None: @@ -1880,6 +2105,17 @@ def _dispatch_one(tc: Any) -> str: if not gr.allowed: denied_msg = f"Tool denied by guardrail: {gr.reason}" emit_event(on_event, "tool_result", {"name": name, "result": denied_msg}) + emit_event( + on_event, + "tool_call_complete", + { + "name": name, + "success": False, + "result": denied_msg, + "durationMs": (time.perf_counter() - started) * 1000, + "errorKind": "guardrail_denied", + }, + ) return denied_msg if gr.rewrite is not None: arguments = json.dumps(gr.rewrite) if isinstance(gr.rewrite, dict) else gr.rewrite @@ -1890,9 +2126,22 @@ def _dispatch_one(tc: Any) -> str: except Exception as e: result = f"Error: Tool '{name}' failed: {type(e).__name__}: {e}" emit_event(on_event, "error", {"tool": name, "error": str(e)}) + success = not result.startswith("Error:") + error_kind = None if success else "tool_error" # §13.1 — Emit tool_result emit_event(on_event, "tool_result", {"name": name, "result": result}) + emit_event( + on_event, + "tool_call_complete", + { + "name": name, + "success": success, + "result": result, + "durationMs": (time.perf_counter() - started) * 1000, + "errorKind": error_kind, + }, + ) return result # §13.6 — Parallel tool execution @@ -1928,6 +2177,7 @@ async def _dispatch_one(tc: Any) -> str: # §13.1 — Emit tool_call_start emit_event(on_event, "tool_call_start", {"name": name, "arguments": arguments}) + started = time.perf_counter() # §13.4 — Tool guardrail if guardrails is not None: @@ -1936,6 +2186,17 @@ async def _dispatch_one(tc: Any) -> str: if not gr.allowed: denied_msg = f"Tool denied by guardrail: {gr.reason}" emit_event(on_event, "tool_result", {"name": name, "result": denied_msg}) + emit_event( + on_event, + "tool_call_complete", + { + "name": name, + "success": False, + "result": denied_msg, + "durationMs": (time.perf_counter() - started) * 1000, + "errorKind": "guardrail_denied", + }, + ) return denied_msg if gr.rewrite is not None: arguments = json.dumps(gr.rewrite) if isinstance(gr.rewrite, dict) else gr.rewrite @@ -1946,9 +2207,22 @@ async def _dispatch_one(tc: Any) -> str: except Exception as e: result = f"Error: Tool '{name}' failed: {type(e).__name__}: {e}" emit_event(on_event, "error", {"tool": name, "error": str(e)}) + success = not result.startswith("Error:") + error_kind = None if success else "tool_error" # §13.1 — Emit tool_result emit_event(on_event, "tool_result", {"name": name, "result": result}) + emit_event( + on_event, + "tool_call_complete", + { + "name": name, + "success": success, + "result": result, + "durationMs": (time.perf_counter() - started) * 1000, + "errorKind": error_kind, + }, + ) return result # §13.6 — Parallel tool execution diff --git a/runtime/python/prompty/prompty/model/__init__.py b/runtime/python/prompty/prompty/model/__init__.py index c207597f..b98b42e7 100644 --- a/runtime/python/prompty/prompty/model/__init__.py +++ b/runtime/python/prompty/prompty/model/__init__.py @@ -42,19 +42,31 @@ from .events import ( CompactionCompletePayload, CompactionFailedPayload, + CompactionStartPayload, DoneEventPayload, ErrorChunk, ErrorEventPayload, + LlmCompletePayload, + LlmStartPayload, MessagesUpdatedPayload, + PermissionCompletedPayload, + PermissionRequestedPayload, + RetryPayload, StatusEventPayload, StreamChunk, TextChunk, ThinkingChunk, ThinkingEventPayload, TokenEventPayload, + ToolCallCompletePayload, ToolCallStartPayload, ToolChunk, ToolResultPayload, + TurnEndPayload, + TurnEvent, + TurnStartPayload, + TurnSummary, + TurnTrace, ) from .model import ( Model, @@ -161,16 +173,28 @@ "Parser", "Executor", "Processor", + "TurnEvent", + "TurnStartPayload", + "TurnEndPayload", + "LlmStartPayload", + "LlmCompletePayload", + "RetryPayload", + "PermissionRequestedPayload", + "PermissionCompletedPayload", "TokenEventPayload", "ThinkingEventPayload", "ToolCallStartPayload", + "ToolCallCompletePayload", "ToolResultPayload", "StatusEventPayload", "MessagesUpdatedPayload", "DoneEventPayload", "ErrorEventPayload", + "CompactionStartPayload", "CompactionCompletePayload", "CompactionFailedPayload", + "TurnSummary", + "TurnTrace", "StreamChunk", "TextChunk", "ThinkingChunk", diff --git a/runtime/python/prompty/prompty/model/agent/_Prompty.py b/runtime/python/prompty/prompty/model/agent/_Prompty.py index 517e7bdc..9bdfbeee 100644 --- a/runtime/python/prompty/prompty/model/agent/_Prompty.py +++ b/runtime/python/prompty/prompty/model/agent/_Prompty.py @@ -23,6 +23,12 @@ class Prompty: This is the single root type for the Prompty schema — there is no abstract base class or kind discriminator. A .prompty file always produces a Prompty instance. + Runtime loaders may resolve frontmatter references such as `${env:VAR}` and + `${file:relative/path}`. File references must be treated as a host-controlled + capability: by default they are scoped to the containing .prompty file's + directory tree after canonicalization, and any additional allowed roots must + be supplied by the host application's load options rather than frontmatter. + Attributes ---------- name : str diff --git a/runtime/python/prompty/prompty/model/conversation/_ToolResult.py b/runtime/python/prompty/prompty/model/conversation/_ToolResult.py index 48cf022c..c5192e01 100644 --- a/runtime/python/prompty/prompty/model/conversation/_ToolResult.py +++ b/runtime/python/prompty/prompty/model/conversation/_ToolResult.py @@ -5,11 +5,13 @@ ########################################## from dataclasses import dataclass, field -from typing import Any, ClassVar, Protocol, runtime_checkable +from typing import Any, ClassVar, Literal, Protocol, runtime_checkable from .._context import LoadContext, SaveContext from ._ContentPart import ContentPart, TextPart +ToolResultStatus = Literal["success", "error", "cancelled", "timeout"] + @dataclass class ToolResult: @@ -23,11 +25,23 @@ class ToolResult: ---------- parts : list[ContentPart] The content parts of the tool result + status : Optional[str] + Semantic execution status for the tool result + error_kind : Optional[str] + Stable machine-readable error category when status is not success + error_message : Optional[str] + Human-readable error message when status is not success + duration_ms : Optional[float] + Tool execution duration in milliseconds """ _shorthand_property: ClassVar[str | None] = None parts: list[ContentPart] = field(default_factory=list) + status: ToolResultStatus | None = None + error_kind: str | None = None + error_message: str | None = None + duration_ms: float | None = None @staticmethod def load(data: Any, context: LoadContext | None = None) -> "ToolResult": @@ -51,6 +65,14 @@ def load(data: Any, context: LoadContext | None = None) -> "ToolResult": if data is not None and "parts" in data: instance.parts = ToolResult.load_parts(data["parts"], context) + if data is not None and "status" in data: + instance.status = data["status"] + if data is not None and "errorKind" in data: + instance.error_kind = data["errorKind"] + if data is not None and "errorMessage" in data: + instance.error_message = data["errorMessage"] + if data is not None and "durationMs" in data: + instance.duration_ms = data["durationMs"] if context is not None: instance = context.process_output(instance) return instance @@ -94,6 +116,14 @@ def save(self, context: SaveContext | None = None) -> dict[str, Any]: if obj.parts is not None: result["parts"] = ToolResult.save_parts(obj.parts, context) + if obj.status is not None: + result["status"] = obj.status + if obj.error_kind is not None: + result["errorKind"] = obj.error_kind + if obj.error_message is not None: + result["errorMessage"] = obj.error_message + if obj.duration_ms is not None: + result["durationMs"] = obj.duration_ms if context is not None: result = context.process_dict(result) diff --git a/runtime/python/prompty/prompty/model/events/_CompactionCompletePayload.py b/runtime/python/prompty/prompty/model/events/_CompactionCompletePayload.py index 0ac1385b..45c8486e 100644 --- a/runtime/python/prompty/prompty/model/events/_CompactionCompletePayload.py +++ b/runtime/python/prompty/prompty/model/events/_CompactionCompletePayload.py @@ -20,12 +20,15 @@ class CompactionCompletePayload: Number of messages removed during compaction remaining : int Number of messages remaining after compaction + summary_length : Optional[int] + Length of the generated summary, when a summarization strategy is used """ _shorthand_property: ClassVar[str | None] = None removed: int = field(default=0) remaining: int = field(default=0) + summary_length: int | None = None @staticmethod def load(data: Any, context: LoadContext | None = None) -> "CompactionCompletePayload": @@ -51,6 +54,8 @@ def load(data: Any, context: LoadContext | None = None) -> "CompactionCompletePa instance.removed = data["removed"] if data is not None and "remaining" in data: instance.remaining = data["remaining"] + if data is not None and "summaryLength" in data: + instance.summary_length = data["summaryLength"] if context is not None: instance = context.process_output(instance) return instance @@ -73,6 +78,8 @@ def save(self, context: SaveContext | None = None) -> dict[str, Any]: result["removed"] = obj.removed if obj.remaining is not None: result["remaining"] = obj.remaining + if obj.summary_length is not None: + result["summaryLength"] = obj.summary_length if context is not None: result = context.process_dict(result) diff --git a/runtime/python/prompty/prompty/model/events/_CompactionStartPayload.py b/runtime/python/prompty/prompty/model/events/_CompactionStartPayload.py new file mode 100644 index 00000000..6a1e90a2 --- /dev/null +++ b/runtime/python/prompty/prompty/model/events/_CompactionStartPayload.py @@ -0,0 +1,97 @@ +########################################## +# WARNING: This is an auto-generated file. +# DO NOT EDIT THIS FILE DIRECTLY +# ANY EDITS WILL BE LOST +########################################## + +from dataclasses import dataclass, field +from typing import Any, ClassVar + +from .._context import LoadContext, SaveContext + + +@dataclass +class CompactionStartPayload: + """Payload for "compaction_start" events — context compaction is beginning. + + Attributes + ---------- + dropped_count : int + Number of messages selected for compaction + """ + + _shorthand_property: ClassVar[str | None] = None + + dropped_count: int = field(default=0) + + @staticmethod + def load(data: Any, context: LoadContext | None = None) -> "CompactionStartPayload": + """Load a CompactionStartPayload instance. + Args: + data (Any): The data to load the instance from. + context (Optional[LoadContext]): Optional context with pre/post processing callbacks. + Returns: + CompactionStartPayload: The loaded CompactionStartPayload instance. + + """ + + if context is not None: + data = context.process_input(data) + + if not isinstance(data, dict): + raise ValueError(f"Invalid data for CompactionStartPayload: {data}") + + # create new instance + instance = CompactionStartPayload() + + if data is not None and "droppedCount" in data: + instance.dropped_count = data["droppedCount"] + if context is not None: + instance = context.process_output(instance) + return instance + + def save(self, context: SaveContext | None = None) -> dict[str, Any]: + """Save the CompactionStartPayload instance to a dictionary. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + dict[str, Any]: The dictionary representation of this instance. + + """ + obj = self + if context is not None: + obj = context.process_object(obj) + + result: dict[str, Any] = {} + + if obj.dropped_count is not None: + result["droppedCount"] = obj.dropped_count + + if context is not None: + result = context.process_dict(result) + return result + + def to_yaml(self, context: SaveContext | None = None) -> str: + """Convert the CompactionStartPayload instance to a YAML string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + str: The YAML string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_yaml(self.save(context)) + + def to_json(self, context: SaveContext | None = None, indent: int = 2) -> str: + """Convert the CompactionStartPayload instance to a JSON string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + indent (int): Number of spaces for indentation. Defaults to 2. + Returns: + str: The JSON string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_json(self.save(context), indent) diff --git a/runtime/python/prompty/prompty/model/events/_DoneEventPayload.py b/runtime/python/prompty/prompty/model/events/_DoneEventPayload.py index 4465a498..9478b5eb 100644 --- a/runtime/python/prompty/prompty/model/events/_DoneEventPayload.py +++ b/runtime/python/prompty/prompty/model/events/_DoneEventPayload.py @@ -17,15 +17,15 @@ class DoneEventPayload: Attributes ---------- - response : str - The final text response from the LLM + response : Any + The final response from the LLM after processing messages : list[Message] The final conversation state including all messages """ _shorthand_property: ClassVar[str | None] = None - response: str = field(default="") + response: Any = field(default=None) messages: list[Message] = field(default_factory=list) @staticmethod diff --git a/runtime/python/prompty/prompty/model/events/_ErrorEventPayload.py b/runtime/python/prompty/prompty/model/events/_ErrorEventPayload.py index 88c5bab5..b27d74f7 100644 --- a/runtime/python/prompty/prompty/model/events/_ErrorEventPayload.py +++ b/runtime/python/prompty/prompty/model/events/_ErrorEventPayload.py @@ -18,11 +18,17 @@ class ErrorEventPayload: ---------- message : str Human-readable error description + error_kind : Optional[str] + Stable machine-readable error category + phase : Optional[str] + Operation or phase where the error occurred """ _shorthand_property: ClassVar[str | None] = None message: str = field(default="") + error_kind: str | None = None + phase: str | None = None @staticmethod def load(data: Any, context: LoadContext | None = None) -> "ErrorEventPayload": @@ -46,6 +52,10 @@ def load(data: Any, context: LoadContext | None = None) -> "ErrorEventPayload": if data is not None and "message" in data: instance.message = data["message"] + if data is not None and "errorKind" in data: + instance.error_kind = data["errorKind"] + if data is not None and "phase" in data: + instance.phase = data["phase"] if context is not None: instance = context.process_output(instance) return instance @@ -66,6 +76,10 @@ def save(self, context: SaveContext | None = None) -> dict[str, Any]: if obj.message is not None: result["message"] = obj.message + if obj.error_kind is not None: + result["errorKind"] = obj.error_kind + if obj.phase is not None: + result["phase"] = obj.phase if context is not None: result = context.process_dict(result) diff --git a/runtime/python/prompty/prompty/model/events/_LlmCompletePayload.py b/runtime/python/prompty/prompty/model/events/_LlmCompletePayload.py new file mode 100644 index 00000000..274da046 --- /dev/null +++ b/runtime/python/prompty/prompty/model/events/_LlmCompletePayload.py @@ -0,0 +1,119 @@ +########################################## +# WARNING: This is an auto-generated file. +# DO NOT EDIT THIS FILE DIRECTLY +# ANY EDITS WILL BE LOST +########################################## + +from dataclasses import dataclass +from typing import Any, ClassVar + +from .._context import LoadContext, SaveContext +from ..model._TokenUsage import TokenUsage + + +@dataclass +class LlmCompletePayload: + """Payload for "llm_complete" events — an LLM request completed. + + Attributes + ---------- + request_id : Optional[str] + Provider request identifier, when supplied by the SDK/API + service_request_id : Optional[str] + Service request identifier, when supplied by the SDK/API + usage : Optional[TokenUsage] + Token usage reported by the provider + duration_ms : Optional[float] + LLM call duration in milliseconds + """ + + _shorthand_property: ClassVar[str | None] = None + + request_id: str | None = None + service_request_id: str | None = None + usage: TokenUsage | None = None + duration_ms: float | None = None + + @staticmethod + def load(data: Any, context: LoadContext | None = None) -> "LlmCompletePayload": + """Load a LlmCompletePayload instance. + Args: + data (Any): The data to load the instance from. + context (Optional[LoadContext]): Optional context with pre/post processing callbacks. + Returns: + LlmCompletePayload: The loaded LlmCompletePayload instance. + + """ + + if context is not None: + data = context.process_input(data) + + if not isinstance(data, dict): + raise ValueError(f"Invalid data for LlmCompletePayload: {data}") + + # create new instance + instance = LlmCompletePayload() + + if data is not None and "requestId" in data: + instance.request_id = data["requestId"] + if data is not None and "serviceRequestId" in data: + instance.service_request_id = data["serviceRequestId"] + if data is not None and "usage" in data: + instance.usage = TokenUsage.load(data["usage"], context) + if data is not None and "durationMs" in data: + instance.duration_ms = data["durationMs"] + if context is not None: + instance = context.process_output(instance) + return instance + + def save(self, context: SaveContext | None = None) -> dict[str, Any]: + """Save the LlmCompletePayload instance to a dictionary. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + dict[str, Any]: The dictionary representation of this instance. + + """ + obj = self + if context is not None: + obj = context.process_object(obj) + + result: dict[str, Any] = {} + + if obj.request_id is not None: + result["requestId"] = obj.request_id + if obj.service_request_id is not None: + result["serviceRequestId"] = obj.service_request_id + if obj.usage is not None: + result["usage"] = obj.usage.save(context) + if obj.duration_ms is not None: + result["durationMs"] = obj.duration_ms + + if context is not None: + result = context.process_dict(result) + return result + + def to_yaml(self, context: SaveContext | None = None) -> str: + """Convert the LlmCompletePayload instance to a YAML string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + str: The YAML string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_yaml(self.save(context)) + + def to_json(self, context: SaveContext | None = None, indent: int = 2) -> str: + """Convert the LlmCompletePayload instance to a JSON string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + indent (int): Number of spaces for indentation. Defaults to 2. + Returns: + str: The JSON string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_json(self.save(context), indent) diff --git a/runtime/python/prompty/prompty/model/events/_LlmStartPayload.py b/runtime/python/prompty/prompty/model/events/_LlmStartPayload.py new file mode 100644 index 00000000..8e5edd3c --- /dev/null +++ b/runtime/python/prompty/prompty/model/events/_LlmStartPayload.py @@ -0,0 +1,118 @@ +########################################## +# WARNING: This is an auto-generated file. +# DO NOT EDIT THIS FILE DIRECTLY +# ANY EDITS WILL BE LOST +########################################## + +from dataclasses import dataclass +from typing import Any, ClassVar + +from .._context import LoadContext, SaveContext + + +@dataclass +class LlmStartPayload: + """Payload for "llm_start" events — an LLM request is about to be sent. + + Attributes + ---------- + provider : Optional[str] + Provider identifier used for the request + model_id : Optional[str] + Model or deployment identifier used for the request + message_count : Optional[int] + Number of messages sent to the provider + attempt : Optional[int] + Retry attempt number, zero for the initial attempt + """ + + _shorthand_property: ClassVar[str | None] = None + + provider: str | None = None + model_id: str | None = None + message_count: int | None = None + attempt: int | None = None + + @staticmethod + def load(data: Any, context: LoadContext | None = None) -> "LlmStartPayload": + """Load a LlmStartPayload instance. + Args: + data (Any): The data to load the instance from. + context (Optional[LoadContext]): Optional context with pre/post processing callbacks. + Returns: + LlmStartPayload: The loaded LlmStartPayload instance. + + """ + + if context is not None: + data = context.process_input(data) + + if not isinstance(data, dict): + raise ValueError(f"Invalid data for LlmStartPayload: {data}") + + # create new instance + instance = LlmStartPayload() + + if data is not None and "provider" in data: + instance.provider = data["provider"] + if data is not None and "modelId" in data: + instance.model_id = data["modelId"] + if data is not None and "messageCount" in data: + instance.message_count = data["messageCount"] + if data is not None and "attempt" in data: + instance.attempt = data["attempt"] + if context is not None: + instance = context.process_output(instance) + return instance + + def save(self, context: SaveContext | None = None) -> dict[str, Any]: + """Save the LlmStartPayload instance to a dictionary. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + dict[str, Any]: The dictionary representation of this instance. + + """ + obj = self + if context is not None: + obj = context.process_object(obj) + + result: dict[str, Any] = {} + + if obj.provider is not None: + result["provider"] = obj.provider + if obj.model_id is not None: + result["modelId"] = obj.model_id + if obj.message_count is not None: + result["messageCount"] = obj.message_count + if obj.attempt is not None: + result["attempt"] = obj.attempt + + if context is not None: + result = context.process_dict(result) + return result + + def to_yaml(self, context: SaveContext | None = None) -> str: + """Convert the LlmStartPayload instance to a YAML string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + str: The YAML string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_yaml(self.save(context)) + + def to_json(self, context: SaveContext | None = None, indent: int = 2) -> str: + """Convert the LlmStartPayload instance to a JSON string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + indent (int): Number of spaces for indentation. Defaults to 2. + Returns: + str: The JSON string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_json(self.save(context), indent) diff --git a/runtime/python/prompty/prompty/model/events/_MessagesUpdatedPayload.py b/runtime/python/prompty/prompty/model/events/_MessagesUpdatedPayload.py index f3de4c6e..1e71aa26 100644 --- a/runtime/python/prompty/prompty/model/events/_MessagesUpdatedPayload.py +++ b/runtime/python/prompty/prompty/model/events/_MessagesUpdatedPayload.py @@ -17,13 +17,22 @@ class MessagesUpdatedPayload: Attributes ---------- - messages : list[Message] + messages : Optional[list[Message]] The current full message list after the update + reason : Optional[str] + Why the message list changed + appended : Optional[list[Message]] + Messages appended by this update, when available + removed : Optional[int] + Number of messages removed by this update, when available """ _shorthand_property: ClassVar[str | None] = None messages: list[Message] = field(default_factory=list) + reason: str | None = None + appended: list[Message] = field(default_factory=list) + removed: int | None = None @staticmethod def load(data: Any, context: LoadContext | None = None) -> "MessagesUpdatedPayload": @@ -47,6 +56,12 @@ def load(data: Any, context: LoadContext | None = None) -> "MessagesUpdatedPaylo if data is not None and "messages" in data: instance.messages = MessagesUpdatedPayload.load_messages(data["messages"], context) + if data is not None and "reason" in data: + instance.reason = data["reason"] + if data is not None and "appended" in data: + instance.appended = MessagesUpdatedPayload.load_appended(data["appended"], context) + if data is not None and "removed" in data: + instance.removed = data["removed"] if context is not None: instance = context.process_output(instance) return instance @@ -74,6 +89,29 @@ def save_messages(items: list[Message], context: SaveContext | None) -> dict[str # This type doesn't have a 'name' property, so always use array format return [item.save(context) for item in items] + @staticmethod + def load_appended(data: dict | list, context: LoadContext | None) -> list[Message]: + if isinstance(data, dict): + # convert simple named appended to list of Message + result = [] + for k, v in data.items(): + if isinstance(v, dict): + # value is an object, spread its properties + result.append({"name": k, **v}) + else: + # value is a scalar, use it as the primary property + result.append({"name": k, "role": v}) + data = result + return [Message.load(item, context) for item in data] + + @staticmethod + def save_appended(items: list[Message], context: SaveContext | None) -> dict[str, Any] | list[dict[str, Any]]: + if context is None: + context = SaveContext() + + # This type doesn't have a 'name' property, so always use array format + return [item.save(context) for item in items] + def save(self, context: SaveContext | None = None) -> dict[str, Any]: """Save the MessagesUpdatedPayload instance to a dictionary. Args: @@ -90,6 +128,12 @@ def save(self, context: SaveContext | None = None) -> dict[str, Any]: if obj.messages is not None: result["messages"] = MessagesUpdatedPayload.save_messages(obj.messages, context) + if obj.reason is not None: + result["reason"] = obj.reason + if obj.appended is not None: + result["appended"] = MessagesUpdatedPayload.save_appended(obj.appended, context) + if obj.removed is not None: + result["removed"] = obj.removed if context is not None: result = context.process_dict(result) diff --git a/runtime/python/prompty/prompty/model/events/_PermissionCompletedPayload.py b/runtime/python/prompty/prompty/model/events/_PermissionCompletedPayload.py new file mode 100644 index 00000000..eedf9a93 --- /dev/null +++ b/runtime/python/prompty/prompty/model/events/_PermissionCompletedPayload.py @@ -0,0 +1,111 @@ +########################################## +# WARNING: This is an auto-generated file. +# DO NOT EDIT THIS FILE DIRECTLY +# ANY EDITS WILL BE LOST +########################################## + +from dataclasses import dataclass, field +from typing import Any, ClassVar + +from .._context import LoadContext, SaveContext + + +@dataclass +class PermissionCompletedPayload: + """Payload for permission completion events — an approval decision was made. + + Attributes + ---------- + permission : str + Permission/action name that was decided + approved : bool + Whether the requested permission was approved + reason : Optional[str] + Decision reason, if available + """ + + _shorthand_property: ClassVar[str | None] = None + + permission: str = field(default="") + approved: bool = field(default=False) + reason: str | None = None + + @staticmethod + def load(data: Any, context: LoadContext | None = None) -> "PermissionCompletedPayload": + """Load a PermissionCompletedPayload instance. + Args: + data (Any): The data to load the instance from. + context (Optional[LoadContext]): Optional context with pre/post processing callbacks. + Returns: + PermissionCompletedPayload: The loaded PermissionCompletedPayload instance. + + """ + + if context is not None: + data = context.process_input(data) + + if not isinstance(data, dict): + raise ValueError(f"Invalid data for PermissionCompletedPayload: {data}") + + # create new instance + instance = PermissionCompletedPayload() + + if data is not None and "permission" in data: + instance.permission = data["permission"] + if data is not None and "approved" in data: + instance.approved = data["approved"] + if data is not None and "reason" in data: + instance.reason = data["reason"] + if context is not None: + instance = context.process_output(instance) + return instance + + def save(self, context: SaveContext | None = None) -> dict[str, Any]: + """Save the PermissionCompletedPayload instance to a dictionary. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + dict[str, Any]: The dictionary representation of this instance. + + """ + obj = self + if context is not None: + obj = context.process_object(obj) + + result: dict[str, Any] = {} + + if obj.permission is not None: + result["permission"] = obj.permission + if obj.approved is not None: + result["approved"] = obj.approved + if obj.reason is not None: + result["reason"] = obj.reason + + if context is not None: + result = context.process_dict(result) + return result + + def to_yaml(self, context: SaveContext | None = None) -> str: + """Convert the PermissionCompletedPayload instance to a YAML string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + str: The YAML string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_yaml(self.save(context)) + + def to_json(self, context: SaveContext | None = None, indent: int = 2) -> str: + """Convert the PermissionCompletedPayload instance to a JSON string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + indent (int): Number of spaces for indentation. Defaults to 2. + Returns: + str: The JSON string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_json(self.save(context), indent) diff --git a/runtime/python/prompty/prompty/model/events/_PermissionRequestedPayload.py b/runtime/python/prompty/prompty/model/events/_PermissionRequestedPayload.py new file mode 100644 index 00000000..eb2fc9b2 --- /dev/null +++ b/runtime/python/prompty/prompty/model/events/_PermissionRequestedPayload.py @@ -0,0 +1,111 @@ +########################################## +# WARNING: This is an auto-generated file. +# DO NOT EDIT THIS FILE DIRECTLY +# ANY EDITS WILL BE LOST +########################################## + +from dataclasses import dataclass, field +from typing import Any, ClassVar + +from .._context import LoadContext, SaveContext + + +@dataclass +class PermissionRequestedPayload: + """Payload for permission request events — a host is asked to approve an action. + + Attributes + ---------- + permission : str + Permission/action name being requested + target : Optional[str] + Resource or tool the permission applies to + details : Optional[dict[str, Any]] + Additional host-specific permission details + """ + + _shorthand_property: ClassVar[str | None] = None + + permission: str = field(default="") + target: str | None = None + details: dict[str, Any] | None = None + + @staticmethod + def load(data: Any, context: LoadContext | None = None) -> "PermissionRequestedPayload": + """Load a PermissionRequestedPayload instance. + Args: + data (Any): The data to load the instance from. + context (Optional[LoadContext]): Optional context with pre/post processing callbacks. + Returns: + PermissionRequestedPayload: The loaded PermissionRequestedPayload instance. + + """ + + if context is not None: + data = context.process_input(data) + + if not isinstance(data, dict): + raise ValueError(f"Invalid data for PermissionRequestedPayload: {data}") + + # create new instance + instance = PermissionRequestedPayload() + + if data is not None and "permission" in data: + instance.permission = data["permission"] + if data is not None and "target" in data: + instance.target = data["target"] + if data is not None and "details" in data: + instance.details = data["details"] + if context is not None: + instance = context.process_output(instance) + return instance + + def save(self, context: SaveContext | None = None) -> dict[str, Any]: + """Save the PermissionRequestedPayload instance to a dictionary. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + dict[str, Any]: The dictionary representation of this instance. + + """ + obj = self + if context is not None: + obj = context.process_object(obj) + + result: dict[str, Any] = {} + + if obj.permission is not None: + result["permission"] = obj.permission + if obj.target is not None: + result["target"] = obj.target + if obj.details is not None: + result["details"] = obj.details + + if context is not None: + result = context.process_dict(result) + return result + + def to_yaml(self, context: SaveContext | None = None) -> str: + """Convert the PermissionRequestedPayload instance to a YAML string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + str: The YAML string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_yaml(self.save(context)) + + def to_json(self, context: SaveContext | None = None, indent: int = 2) -> str: + """Convert the PermissionRequestedPayload instance to a JSON string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + indent (int): Number of spaces for indentation. Defaults to 2. + Returns: + str: The JSON string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_json(self.save(context), indent) diff --git a/runtime/python/prompty/prompty/model/events/_RetryPayload.py b/runtime/python/prompty/prompty/model/events/_RetryPayload.py new file mode 100644 index 00000000..a9c58f34 --- /dev/null +++ b/runtime/python/prompty/prompty/model/events/_RetryPayload.py @@ -0,0 +1,125 @@ +########################################## +# WARNING: This is an auto-generated file. +# DO NOT EDIT THIS FILE DIRECTLY +# ANY EDITS WILL BE LOST +########################################## + +from dataclasses import dataclass, field +from typing import Any, ClassVar + +from .._context import LoadContext, SaveContext + + +@dataclass +class RetryPayload: + """Payload for "retry" events — a transient operation will be retried. + + Attributes + ---------- + operation : str + Operation being retried + attempt : int + Attempt number about to run + max_attempts : Optional[int] + Maximum configured attempts + delay_ms : Optional[float] + Backoff delay before the next attempt in milliseconds + reason : Optional[str] + Reason for the retry + """ + + _shorthand_property: ClassVar[str | None] = None + + operation: str = field(default="") + attempt: int = field(default=0) + max_attempts: int | None = None + delay_ms: float | None = None + reason: str | None = None + + @staticmethod + def load(data: Any, context: LoadContext | None = None) -> "RetryPayload": + """Load a RetryPayload instance. + Args: + data (Any): The data to load the instance from. + context (Optional[LoadContext]): Optional context with pre/post processing callbacks. + Returns: + RetryPayload: The loaded RetryPayload instance. + + """ + + if context is not None: + data = context.process_input(data) + + if not isinstance(data, dict): + raise ValueError(f"Invalid data for RetryPayload: {data}") + + # create new instance + instance = RetryPayload() + + if data is not None and "operation" in data: + instance.operation = data["operation"] + if data is not None and "attempt" in data: + instance.attempt = data["attempt"] + if data is not None and "maxAttempts" in data: + instance.max_attempts = data["maxAttempts"] + if data is not None and "delayMs" in data: + instance.delay_ms = data["delayMs"] + if data is not None and "reason" in data: + instance.reason = data["reason"] + if context is not None: + instance = context.process_output(instance) + return instance + + def save(self, context: SaveContext | None = None) -> dict[str, Any]: + """Save the RetryPayload instance to a dictionary. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + dict[str, Any]: The dictionary representation of this instance. + + """ + obj = self + if context is not None: + obj = context.process_object(obj) + + result: dict[str, Any] = {} + + if obj.operation is not None: + result["operation"] = obj.operation + if obj.attempt is not None: + result["attempt"] = obj.attempt + if obj.max_attempts is not None: + result["maxAttempts"] = obj.max_attempts + if obj.delay_ms is not None: + result["delayMs"] = obj.delay_ms + if obj.reason is not None: + result["reason"] = obj.reason + + if context is not None: + result = context.process_dict(result) + return result + + def to_yaml(self, context: SaveContext | None = None) -> str: + """Convert the RetryPayload instance to a YAML string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + str: The YAML string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_yaml(self.save(context)) + + def to_json(self, context: SaveContext | None = None, indent: int = 2) -> str: + """Convert the RetryPayload instance to a JSON string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + indent (int): Number of spaces for indentation. Defaults to 2. + Returns: + str: The JSON string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_json(self.save(context), indent) diff --git a/runtime/python/prompty/prompty/model/events/_ToolCallCompletePayload.py b/runtime/python/prompty/prompty/model/events/_ToolCallCompletePayload.py new file mode 100644 index 00000000..2f85b721 --- /dev/null +++ b/runtime/python/prompty/prompty/model/events/_ToolCallCompletePayload.py @@ -0,0 +1,133 @@ +########################################## +# WARNING: This is an auto-generated file. +# DO NOT EDIT THIS FILE DIRECTLY +# ANY EDITS WILL BE LOST +########################################## + +from dataclasses import dataclass, field +from typing import Any, ClassVar + +from .._context import LoadContext, SaveContext +from ..conversation._ToolResult import ToolResult + + +@dataclass +class ToolCallCompletePayload: + """Payload for "tool_call_complete" events — a tool dispatch finished. + + Attributes + ---------- + id : Optional[str] + The unique identifier of the tool call + name : str + The name of the tool that completed + success : bool + Whether the tool dispatch succeeded semantically + result : Optional[ToolResult] + Normalized tool result + duration_ms : Optional[float] + Tool execution duration in milliseconds + error_kind : Optional[str] + Machine-readable error category when success is false + """ + + _shorthand_property: ClassVar[str | None] = None + + id: str | None = None + name: str = field(default="") + success: bool = field(default=False) + result: ToolResult | None = None + duration_ms: float | None = None + error_kind: str | None = None + + @staticmethod + def load(data: Any, context: LoadContext | None = None) -> "ToolCallCompletePayload": + """Load a ToolCallCompletePayload instance. + Args: + data (Any): The data to load the instance from. + context (Optional[LoadContext]): Optional context with pre/post processing callbacks. + Returns: + ToolCallCompletePayload: The loaded ToolCallCompletePayload instance. + + """ + + if context is not None: + data = context.process_input(data) + + if not isinstance(data, dict): + raise ValueError(f"Invalid data for ToolCallCompletePayload: {data}") + + # create new instance + instance = ToolCallCompletePayload() + + if data is not None and "id" in data: + instance.id = data["id"] + if data is not None and "name" in data: + instance.name = data["name"] + if data is not None and "success" in data: + instance.success = data["success"] + if data is not None and "result" in data: + instance.result = ToolResult.load(data["result"], context) + if data is not None and "durationMs" in data: + instance.duration_ms = data["durationMs"] + if data is not None and "errorKind" in data: + instance.error_kind = data["errorKind"] + if context is not None: + instance = context.process_output(instance) + return instance + + def save(self, context: SaveContext | None = None) -> dict[str, Any]: + """Save the ToolCallCompletePayload instance to a dictionary. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + dict[str, Any]: The dictionary representation of this instance. + + """ + obj = self + if context is not None: + obj = context.process_object(obj) + + result: dict[str, Any] = {} + + if obj.id is not None: + result["id"] = obj.id + if obj.name is not None: + result["name"] = obj.name + if obj.success is not None: + result["success"] = obj.success + if obj.result is not None: + result["result"] = obj.result.save(context) + if obj.duration_ms is not None: + result["durationMs"] = obj.duration_ms + if obj.error_kind is not None: + result["errorKind"] = obj.error_kind + + if context is not None: + result = context.process_dict(result) + return result + + def to_yaml(self, context: SaveContext | None = None) -> str: + """Convert the ToolCallCompletePayload instance to a YAML string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + str: The YAML string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_yaml(self.save(context)) + + def to_json(self, context: SaveContext | None = None, indent: int = 2) -> str: + """Convert the ToolCallCompletePayload instance to a JSON string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + indent (int): Number of spaces for indentation. Defaults to 2. + Returns: + str: The JSON string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_json(self.save(context), indent) diff --git a/runtime/python/prompty/prompty/model/events/_ToolCallStartPayload.py b/runtime/python/prompty/prompty/model/events/_ToolCallStartPayload.py index a4489731..b836732f 100644 --- a/runtime/python/prompty/prompty/model/events/_ToolCallStartPayload.py +++ b/runtime/python/prompty/prompty/model/events/_ToolCallStartPayload.py @@ -16,6 +16,8 @@ class ToolCallStartPayload: Attributes ---------- + id : Optional[str] + The unique identifier of the tool call name : str The name of the tool being called arguments : str @@ -24,6 +26,7 @@ class ToolCallStartPayload: _shorthand_property: ClassVar[str | None] = None + id: str | None = None name: str = field(default="") arguments: str = field(default="") @@ -47,6 +50,8 @@ def load(data: Any, context: LoadContext | None = None) -> "ToolCallStartPayload # create new instance instance = ToolCallStartPayload() + if data is not None and "id" in data: + instance.id = data["id"] if data is not None and "name" in data: instance.name = data["name"] if data is not None and "arguments" in data: @@ -69,6 +74,8 @@ def save(self, context: SaveContext | None = None) -> dict[str, Any]: result: dict[str, Any] = {} + if obj.id is not None: + result["id"] = obj.id if obj.name is not None: result["name"] = obj.name if obj.arguments is not None: diff --git a/runtime/python/prompty/prompty/model/events/_TurnEndPayload.py b/runtime/python/prompty/prompty/model/events/_TurnEndPayload.py new file mode 100644 index 00000000..d4d532a0 --- /dev/null +++ b/runtime/python/prompty/prompty/model/events/_TurnEndPayload.py @@ -0,0 +1,120 @@ +########################################## +# WARNING: This is an auto-generated file. +# DO NOT EDIT THIS FILE DIRECTLY +# ANY EDITS WILL BE LOST +########################################## + +from dataclasses import dataclass +from typing import Any, ClassVar, Literal + +from .._context import LoadContext, SaveContext + +TurnStatus = Literal["success", "error", "cancelled"] + + +@dataclass +class TurnEndPayload: + """Payload for "turn_end" events — a turn has completed. + + Attributes + ---------- + iterations : Optional[int] + Number of tool-call iterations performed + status : Optional[str] + Final semantic status of the turn + response : Optional[Any] + Final response after processing, if available + duration_ms : Optional[float] + Total elapsed turn duration in milliseconds + """ + + _shorthand_property: ClassVar[str | None] = None + + iterations: int | None = None + status: TurnStatus | None = None + response: Any | None = None + duration_ms: float | None = None + + @staticmethod + def load(data: Any, context: LoadContext | None = None) -> "TurnEndPayload": + """Load a TurnEndPayload instance. + Args: + data (Any): The data to load the instance from. + context (Optional[LoadContext]): Optional context with pre/post processing callbacks. + Returns: + TurnEndPayload: The loaded TurnEndPayload instance. + + """ + + if context is not None: + data = context.process_input(data) + + if not isinstance(data, dict): + raise ValueError(f"Invalid data for TurnEndPayload: {data}") + + # create new instance + instance = TurnEndPayload() + + if data is not None and "iterations" in data: + instance.iterations = data["iterations"] + if data is not None and "status" in data: + instance.status = data["status"] + if data is not None and "response" in data: + instance.response = data["response"] + if data is not None and "durationMs" in data: + instance.duration_ms = data["durationMs"] + if context is not None: + instance = context.process_output(instance) + return instance + + def save(self, context: SaveContext | None = None) -> dict[str, Any]: + """Save the TurnEndPayload instance to a dictionary. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + dict[str, Any]: The dictionary representation of this instance. + + """ + obj = self + if context is not None: + obj = context.process_object(obj) + + result: dict[str, Any] = {} + + if obj.iterations is not None: + result["iterations"] = obj.iterations + if obj.status is not None: + result["status"] = obj.status + if obj.response is not None: + result["response"] = obj.response + if obj.duration_ms is not None: + result["durationMs"] = obj.duration_ms + + if context is not None: + result = context.process_dict(result) + return result + + def to_yaml(self, context: SaveContext | None = None) -> str: + """Convert the TurnEndPayload instance to a YAML string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + str: The YAML string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_yaml(self.save(context)) + + def to_json(self, context: SaveContext | None = None, indent: int = 2) -> str: + """Convert the TurnEndPayload instance to a JSON string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + indent (int): Number of spaces for indentation. Defaults to 2. + Returns: + str: The JSON string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_json(self.save(context), indent) diff --git a/runtime/python/prompty/prompty/model/events/_TurnEvent.py b/runtime/python/prompty/prompty/model/events/_TurnEvent.py new file mode 100644 index 00000000..5aca2f34 --- /dev/null +++ b/runtime/python/prompty/prompty/model/events/_TurnEvent.py @@ -0,0 +1,171 @@ +########################################## +# WARNING: This is an auto-generated file. +# DO NOT EDIT THIS FILE DIRECTLY +# ANY EDITS WILL BE LOST +########################################## + +from dataclasses import dataclass, field +from typing import Any, ClassVar, Literal + +from .._context import LoadContext, SaveContext + +TurnEventType = Literal[ + "turn_start", + "turn_end", + "llm_start", + "llm_complete", + "retry", + "permission_requested", + "permission_completed", + "token", + "thinking", + "tool_call_start", + "tool_call_complete", + "tool_result", + "status", + "messages_updated", + "done", + "error", + "cancelled", + "compaction_start", + "compaction_complete", + "compaction_failed", +] + + +@dataclass +class TurnEvent: + """A canonical event envelope emitted by the turn harness. The payload is kept + JSON-shaped so runtimes can load all events even when newer payload types are + added; event-specific typed payload models below define the canonical shapes. + + Attributes + ---------- + id : str + Unique identifier for this event + type : str + Event type discriminator + timestamp : str + ISO 8601 UTC timestamp when the event was emitted + turn_id : Optional[str] + Stable identifier for the outer turn + iteration : Optional[int] + Zero-based agent-loop iteration associated with the event + parent_id : Optional[str] + Parent event or span identifier for reconstructing event hierarchy + span_id : Optional[str] + Trace span identifier associated with this event + payload : dict[str, Any] + Event-specific payload. Use the typed payload model matching 'type'. + """ + + _shorthand_property: ClassVar[str | None] = None + + id: str = field(default="") + type: TurnEventType = field(default="turn_start") + timestamp: str = field(default="") + turn_id: str | None = None + iteration: int | None = None + parent_id: str | None = None + span_id: str | None = None + payload: dict[str, Any] = field(default_factory=dict) + + @staticmethod + def load(data: Any, context: LoadContext | None = None) -> "TurnEvent": + """Load a TurnEvent instance. + Args: + data (Any): The data to load the instance from. + context (Optional[LoadContext]): Optional context with pre/post processing callbacks. + Returns: + TurnEvent: The loaded TurnEvent instance. + + """ + + if context is not None: + data = context.process_input(data) + + if not isinstance(data, dict): + raise ValueError(f"Invalid data for TurnEvent: {data}") + + # create new instance + instance = TurnEvent() + + if data is not None and "id" in data: + instance.id = data["id"] + if data is not None and "type" in data: + instance.type = data["type"] + if data is not None and "timestamp" in data: + instance.timestamp = data["timestamp"] + if data is not None and "turnId" in data: + instance.turn_id = data["turnId"] + if data is not None and "iteration" in data: + instance.iteration = data["iteration"] + if data is not None and "parentId" in data: + instance.parent_id = data["parentId"] + if data is not None and "spanId" in data: + instance.span_id = data["spanId"] + if data is not None and "payload" in data: + instance.payload = data["payload"] + if context is not None: + instance = context.process_output(instance) + return instance + + def save(self, context: SaveContext | None = None) -> dict[str, Any]: + """Save the TurnEvent instance to a dictionary. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + dict[str, Any]: The dictionary representation of this instance. + + """ + obj = self + if context is not None: + obj = context.process_object(obj) + + result: dict[str, Any] = {} + + if obj.id is not None: + result["id"] = obj.id + if obj.type is not None: + result["type"] = obj.type + if obj.timestamp is not None: + result["timestamp"] = obj.timestamp + if obj.turn_id is not None: + result["turnId"] = obj.turn_id + if obj.iteration is not None: + result["iteration"] = obj.iteration + if obj.parent_id is not None: + result["parentId"] = obj.parent_id + if obj.span_id is not None: + result["spanId"] = obj.span_id + if obj.payload is not None: + result["payload"] = obj.payload + + if context is not None: + result = context.process_dict(result) + return result + + def to_yaml(self, context: SaveContext | None = None) -> str: + """Convert the TurnEvent instance to a YAML string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + str: The YAML string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_yaml(self.save(context)) + + def to_json(self, context: SaveContext | None = None, indent: int = 2) -> str: + """Convert the TurnEvent instance to a JSON string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + indent (int): Number of spaces for indentation. Defaults to 2. + Returns: + str: The JSON string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_json(self.save(context), indent) diff --git a/runtime/python/prompty/prompty/model/events/_TurnStartPayload.py b/runtime/python/prompty/prompty/model/events/_TurnStartPayload.py new file mode 100644 index 00000000..3584eddd --- /dev/null +++ b/runtime/python/prompty/prompty/model/events/_TurnStartPayload.py @@ -0,0 +1,111 @@ +########################################## +# WARNING: This is an auto-generated file. +# DO NOT EDIT THIS FILE DIRECTLY +# ANY EDITS WILL BE LOST +########################################## + +from dataclasses import dataclass +from typing import Any, ClassVar + +from .._context import LoadContext, SaveContext + + +@dataclass +class TurnStartPayload: + """Payload for "turn_start" events — a turn is beginning. + + Attributes + ---------- + agent : Optional[str] + Name of the loaded prompt/agent, when available + inputs : Optional[dict[str, Any]] + Input values supplied to the turn after host-side sanitization + max_iterations : Optional[int] + Configured maximum tool-call iterations + """ + + _shorthand_property: ClassVar[str | None] = None + + agent: str | None = None + inputs: dict[str, Any] | None = None + max_iterations: int | None = None + + @staticmethod + def load(data: Any, context: LoadContext | None = None) -> "TurnStartPayload": + """Load a TurnStartPayload instance. + Args: + data (Any): The data to load the instance from. + context (Optional[LoadContext]): Optional context with pre/post processing callbacks. + Returns: + TurnStartPayload: The loaded TurnStartPayload instance. + + """ + + if context is not None: + data = context.process_input(data) + + if not isinstance(data, dict): + raise ValueError(f"Invalid data for TurnStartPayload: {data}") + + # create new instance + instance = TurnStartPayload() + + if data is not None and "agent" in data: + instance.agent = data["agent"] + if data is not None and "inputs" in data: + instance.inputs = data["inputs"] + if data is not None and "maxIterations" in data: + instance.max_iterations = data["maxIterations"] + if context is not None: + instance = context.process_output(instance) + return instance + + def save(self, context: SaveContext | None = None) -> dict[str, Any]: + """Save the TurnStartPayload instance to a dictionary. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + dict[str, Any]: The dictionary representation of this instance. + + """ + obj = self + if context is not None: + obj = context.process_object(obj) + + result: dict[str, Any] = {} + + if obj.agent is not None: + result["agent"] = obj.agent + if obj.inputs is not None: + result["inputs"] = obj.inputs + if obj.max_iterations is not None: + result["maxIterations"] = obj.max_iterations + + if context is not None: + result = context.process_dict(result) + return result + + def to_yaml(self, context: SaveContext | None = None) -> str: + """Convert the TurnStartPayload instance to a YAML string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + str: The YAML string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_yaml(self.save(context)) + + def to_json(self, context: SaveContext | None = None, indent: int = 2) -> str: + """Convert the TurnStartPayload instance to a JSON string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + indent (int): Number of spaces for indentation. Defaults to 2. + Returns: + str: The JSON string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_json(self.save(context), indent) diff --git a/runtime/python/prompty/prompty/model/events/_TurnSummary.py b/runtime/python/prompty/prompty/model/events/_TurnSummary.py new file mode 100644 index 00000000..79d1c254 --- /dev/null +++ b/runtime/python/prompty/prompty/model/events/_TurnSummary.py @@ -0,0 +1,147 @@ +########################################## +# WARNING: This is an auto-generated file. +# DO NOT EDIT THIS FILE DIRECTLY +# ANY EDITS WILL BE LOST +########################################## + +from dataclasses import dataclass, field +from typing import Any, ClassVar + +from .._context import LoadContext, SaveContext +from ..model._TokenUsage import TokenUsage + + +@dataclass +class TurnSummary: + """Summary statistics for a completed turn trace. + + Attributes + ---------- + turn_id : str + Stable identifier for the outer turn + status : str + Final turn status: 'success', 'error', or 'cancelled' + iterations : int + Number of agent-loop iterations + llm_calls : Optional[int] + Number of LLM calls made during the turn + tool_calls : Optional[int] + Number of tool calls dispatched during the turn + retries : Optional[int] + Number of retry events during the turn + usage : Optional[TokenUsage] + Aggregated token usage for the turn + duration_ms : Optional[float] + Total elapsed turn duration in milliseconds + """ + + _shorthand_property: ClassVar[str | None] = None + + turn_id: str = field(default="") + status: str = field(default="") + iterations: int = field(default=0) + llm_calls: int | None = None + tool_calls: int | None = None + retries: int | None = None + usage: TokenUsage | None = None + duration_ms: float | None = None + + @staticmethod + def load(data: Any, context: LoadContext | None = None) -> "TurnSummary": + """Load a TurnSummary instance. + Args: + data (Any): The data to load the instance from. + context (Optional[LoadContext]): Optional context with pre/post processing callbacks. + Returns: + TurnSummary: The loaded TurnSummary instance. + + """ + + if context is not None: + data = context.process_input(data) + + if not isinstance(data, dict): + raise ValueError(f"Invalid data for TurnSummary: {data}") + + # create new instance + instance = TurnSummary() + + if data is not None and "turnId" in data: + instance.turn_id = data["turnId"] + if data is not None and "status" in data: + instance.status = data["status"] + if data is not None and "iterations" in data: + instance.iterations = data["iterations"] + if data is not None and "llmCalls" in data: + instance.llm_calls = data["llmCalls"] + if data is not None and "toolCalls" in data: + instance.tool_calls = data["toolCalls"] + if data is not None and "retries" in data: + instance.retries = data["retries"] + if data is not None and "usage" in data: + instance.usage = TokenUsage.load(data["usage"], context) + if data is not None and "durationMs" in data: + instance.duration_ms = data["durationMs"] + if context is not None: + instance = context.process_output(instance) + return instance + + def save(self, context: SaveContext | None = None) -> dict[str, Any]: + """Save the TurnSummary instance to a dictionary. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + dict[str, Any]: The dictionary representation of this instance. + + """ + obj = self + if context is not None: + obj = context.process_object(obj) + + result: dict[str, Any] = {} + + if obj.turn_id is not None: + result["turnId"] = obj.turn_id + if obj.status is not None: + result["status"] = obj.status + if obj.iterations is not None: + result["iterations"] = obj.iterations + if obj.llm_calls is not None: + result["llmCalls"] = obj.llm_calls + if obj.tool_calls is not None: + result["toolCalls"] = obj.tool_calls + if obj.retries is not None: + result["retries"] = obj.retries + if obj.usage is not None: + result["usage"] = obj.usage.save(context) + if obj.duration_ms is not None: + result["durationMs"] = obj.duration_ms + + if context is not None: + result = context.process_dict(result) + return result + + def to_yaml(self, context: SaveContext | None = None) -> str: + """Convert the TurnSummary instance to a YAML string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + str: The YAML string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_yaml(self.save(context)) + + def to_json(self, context: SaveContext | None = None, indent: int = 2) -> str: + """Convert the TurnSummary instance to a JSON string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + indent (int): Number of spaces for indentation. Defaults to 2. + Returns: + str: The JSON string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_json(self.save(context), indent) diff --git a/runtime/python/prompty/prompty/model/events/_TurnTrace.py b/runtime/python/prompty/prompty/model/events/_TurnTrace.py new file mode 100644 index 00000000..7dbcd956 --- /dev/null +++ b/runtime/python/prompty/prompty/model/events/_TurnTrace.py @@ -0,0 +1,150 @@ +########################################## +# WARNING: This is an auto-generated file. +# DO NOT EDIT THIS FILE DIRECTLY +# ANY EDITS WILL BE LOST +########################################## + +from dataclasses import dataclass, field +from typing import Any, ClassVar + +from .._context import LoadContext, SaveContext +from ._TurnEvent import TurnEvent +from ._TurnSummary import TurnSummary + + +@dataclass +class TurnTrace: + """Portable JSONL/replay container for a recorded turn harness run. + + Attributes + ---------- + version : str + Trace schema version + runtime : Optional[str] + Runtime name that produced the trace + prompty_version : Optional[str] + Prompty library version that produced the trace + events : list[TurnEvent] + Recorded turn events in emission order + summary : Optional[TurnSummary] + Optional summary computed from the event stream + """ + + _shorthand_property: ClassVar[str | None] = None + + version: str = field(default="1") + runtime: str | None = None + prompty_version: str | None = None + events: list[TurnEvent] = field(default_factory=list) + summary: TurnSummary | None = None + + @staticmethod + def load(data: Any, context: LoadContext | None = None) -> "TurnTrace": + """Load a TurnTrace instance. + Args: + data (Any): The data to load the instance from. + context (Optional[LoadContext]): Optional context with pre/post processing callbacks. + Returns: + TurnTrace: The loaded TurnTrace instance. + + """ + + if context is not None: + data = context.process_input(data) + + if not isinstance(data, dict): + raise ValueError(f"Invalid data for TurnTrace: {data}") + + # create new instance + instance = TurnTrace() + + if data is not None and "version" in data: + instance.version = data["version"] + if data is not None and "runtime" in data: + instance.runtime = data["runtime"] + if data is not None and "promptyVersion" in data: + instance.prompty_version = data["promptyVersion"] + if data is not None and "events" in data: + instance.events = TurnTrace.load_events(data["events"], context) + if data is not None and "summary" in data: + instance.summary = TurnSummary.load(data["summary"], context) + if context is not None: + instance = context.process_output(instance) + return instance + + @staticmethod + def load_events(data: dict | list, context: LoadContext | None) -> list[TurnEvent]: + if isinstance(data, dict): + # convert simple named events to list of TurnEvent + result = [] + for k, v in data.items(): + if isinstance(v, dict): + # value is an object, spread its properties + result.append({"name": k, **v}) + else: + # value is a scalar, use it as the primary property + result.append({"name": k, "id": v}) + data = result + return [TurnEvent.load(item, context) for item in data] + + @staticmethod + def save_events(items: list[TurnEvent], context: SaveContext | None) -> dict[str, Any] | list[dict[str, Any]]: + if context is None: + context = SaveContext() + + # This type doesn't have a 'name' property, so always use array format + return [item.save(context) for item in items] + + def save(self, context: SaveContext | None = None) -> dict[str, Any]: + """Save the TurnTrace instance to a dictionary. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + dict[str, Any]: The dictionary representation of this instance. + + """ + obj = self + if context is not None: + obj = context.process_object(obj) + + result: dict[str, Any] = {} + + if obj.version is not None: + result["version"] = obj.version + if obj.runtime is not None: + result["runtime"] = obj.runtime + if obj.prompty_version is not None: + result["promptyVersion"] = obj.prompty_version + if obj.events is not None: + result["events"] = TurnTrace.save_events(obj.events, context) + if obj.summary is not None: + result["summary"] = obj.summary.save(context) + + if context is not None: + result = context.process_dict(result) + return result + + def to_yaml(self, context: SaveContext | None = None) -> str: + """Convert the TurnTrace instance to a YAML string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + str: The YAML string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_yaml(self.save(context)) + + def to_json(self, context: SaveContext | None = None, indent: int = 2) -> str: + """Convert the TurnTrace instance to a JSON string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + indent (int): Number of spaces for indentation. Defaults to 2. + Returns: + str: The JSON string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_json(self.save(context), indent) diff --git a/runtime/python/prompty/prompty/model/events/__init__.py b/runtime/python/prompty/prompty/model/events/__init__.py index a2404644..8eb17ce3 100644 --- a/runtime/python/prompty/prompty/model/events/__init__.py +++ b/runtime/python/prompty/prompty/model/events/__init__.py @@ -5,9 +5,15 @@ ########################################## from ._CompactionCompletePayload import CompactionCompletePayload from ._CompactionFailedPayload import CompactionFailedPayload +from ._CompactionStartPayload import CompactionStartPayload from ._DoneEventPayload import DoneEventPayload from ._ErrorEventPayload import ErrorEventPayload +from ._LlmCompletePayload import LlmCompletePayload +from ._LlmStartPayload import LlmStartPayload from ._MessagesUpdatedPayload import MessagesUpdatedPayload +from ._PermissionCompletedPayload import PermissionCompletedPayload +from ._PermissionRequestedPayload import PermissionRequestedPayload +from ._RetryPayload import RetryPayload from ._StatusEventPayload import StatusEventPayload from ._StreamChunk import ( ErrorChunk, @@ -18,20 +24,38 @@ ) from ._ThinkingEventPayload import ThinkingEventPayload from ._TokenEventPayload import TokenEventPayload +from ._ToolCallCompletePayload import ToolCallCompletePayload from ._ToolCallStartPayload import ToolCallStartPayload from ._ToolResultPayload import ToolResultPayload +from ._TurnEndPayload import TurnEndPayload +from ._TurnEvent import TurnEvent +from ._TurnStartPayload import TurnStartPayload +from ._TurnSummary import TurnSummary +from ._TurnTrace import TurnTrace __all__ = [ + "TurnEvent", + "TurnStartPayload", + "TurnEndPayload", + "LlmStartPayload", + "LlmCompletePayload", + "RetryPayload", + "PermissionRequestedPayload", + "PermissionCompletedPayload", "TokenEventPayload", "ThinkingEventPayload", "ToolCallStartPayload", + "ToolCallCompletePayload", "ToolResultPayload", "StatusEventPayload", "MessagesUpdatedPayload", "DoneEventPayload", "ErrorEventPayload", + "CompactionStartPayload", "CompactionCompletePayload", "CompactionFailedPayload", + "TurnSummary", + "TurnTrace", "StreamChunk", "TextChunk", "ThinkingChunk", diff --git a/runtime/python/prompty/tests/model/agent/test_guardrail_result.py b/runtime/python/prompty/tests/model/agent/test_guardrail_result.py index c0ae828d..598110a6 100644 --- a/runtime/python/prompty/tests/model/agent/test_guardrail_result.py +++ b/runtime/python/prompty/tests/model/agent/test_guardrail_result.py @@ -23,7 +23,7 @@ def test_load_yaml_guardrailresult(): yaml_data = r""" allowed: true reason: Content is safe - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = GuardrailResult.load(data) diff --git a/runtime/python/prompty/tests/model/agent/test_prompty.py b/runtime/python/prompty/tests/model/agent/test_prompty.py index 997af6e1..5717ed59 100644 --- a/runtime/python/prompty/tests/model/agent/test_prompty.py +++ b/runtime/python/prompty/tests/model/agent/test_prompty.py @@ -142,26 +142,26 @@ def test_load_yaml_prompty(): format: mustache parser: prompty instructions: "system: - + You are an AI assistant who helps people find information. - + As the assistant, you answer questions briefly, succinctly, - + and in a personable manner using markdown and even add some\ - + personal flair with appropriate emojis. - - + + # Customer - + You are helping {{firstName}} {{lastName}} to find answers to\ - + their questions. Use their name to address them in your responses. - + user: - + {{question}}" - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = Prompty.load(data) @@ -568,26 +568,26 @@ def test_load_yaml_prompty_1(): format: mustache parser: prompty instructions: "system: - + You are an AI assistant who helps people find information. - + As the assistant, you answer questions briefly, succinctly, - + and in a personable manner using markdown and even add some\ - + personal flair with appropriate emojis. - - + + # Customer - + You are helping {{firstName}} {{lastName}} to find answers to\ - + their questions. Use their name to address them in your responses. - + user: - + {{question}}" - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = Prompty.load(data) @@ -993,26 +993,26 @@ def test_load_yaml_prompty_2(): format: mustache parser: prompty instructions: "system: - + You are an AI assistant who helps people find information. - + As the assistant, you answer questions briefly, succinctly, - + and in a personable manner using markdown and even add some\ - + personal flair with appropriate emojis. - - + + # Customer - + You are helping {{firstName}} {{lastName}} to find answers to\ - + their questions. Use their name to address them in your responses. - + user: - + {{question}}" - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = Prompty.load(data) @@ -1423,26 +1423,26 @@ def test_load_yaml_prompty_3(): format: mustache parser: prompty instructions: "system: - + You are an AI assistant who helps people find information. - + As the assistant, you answer questions briefly, succinctly, - + and in a personable manner using markdown and even add some\ - + personal flair with appropriate emojis. - - + + # Customer - + You are helping {{firstName}} {{lastName}} to find answers to\ - + their questions. Use their name to address them in your responses. - + user: - + {{question}}" - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = Prompty.load(data) @@ -1853,26 +1853,26 @@ def test_load_yaml_prompty_4(): format: mustache parser: prompty instructions: "system: - + You are an AI assistant who helps people find information. - + As the assistant, you answer questions briefly, succinctly, - + and in a personable manner using markdown and even add some\ - + personal flair with appropriate emojis. - - + + # Customer - + You are helping {{firstName}} {{lastName}} to find answers to\ - + their questions. Use their name to address them in your responses. - + user: - + {{question}}" - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = Prompty.load(data) @@ -2291,26 +2291,26 @@ def test_load_yaml_prompty_5(): format: mustache parser: prompty instructions: "system: - + You are an AI assistant who helps people find information. - + As the assistant, you answer questions briefly, succinctly, - + and in a personable manner using markdown and even add some\ - + personal flair with appropriate emojis. - - + + # Customer - + You are helping {{firstName}} {{lastName}} to find answers to\ - + their questions. Use their name to address them in your responses. - + user: - + {{question}}" - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = Prompty.load(data) @@ -2728,26 +2728,26 @@ def test_load_yaml_prompty_6(): format: mustache parser: prompty instructions: "system: - + You are an AI assistant who helps people find information. - + As the assistant, you answer questions briefly, succinctly, - + and in a personable manner using markdown and even add some\ - + personal flair with appropriate emojis. - - + + # Customer - + You are helping {{firstName}} {{lastName}} to find answers to\ - + their questions. Use their name to address them in your responses. - + user: - + {{question}}" - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = Prompty.load(data) @@ -3170,26 +3170,26 @@ def test_load_yaml_prompty_7(): format: mustache parser: prompty instructions: "system: - + You are an AI assistant who helps people find information. - + As the assistant, you answer questions briefly, succinctly, - + and in a personable manner using markdown and even add some\ - + personal flair with appropriate emojis. - - + + # Customer - + You are helping {{firstName}} {{lastName}} to find answers to\ - + their questions. Use their name to address them in your responses. - + user: - + {{question}}" - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = Prompty.load(data) diff --git a/runtime/python/prompty/tests/model/connection/test_anonymous_connection.py b/runtime/python/prompty/tests/model/connection/test_anonymous_connection.py index 9dbc7afe..95ff3290 100644 --- a/runtime/python/prompty/tests/model/connection/test_anonymous_connection.py +++ b/runtime/python/prompty/tests/model/connection/test_anonymous_connection.py @@ -23,7 +23,7 @@ def test_load_yaml_anonymousconnection(): yaml_data = r""" kind: anonymous endpoint: "https://{your-custom-endpoint}.openai.azure.com/" - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = AnonymousConnection.load(data) diff --git a/runtime/python/prompty/tests/model/connection/test_api_key_connection.py b/runtime/python/prompty/tests/model/connection/test_api_key_connection.py index 79616486..c063a7d4 100644 --- a/runtime/python/prompty/tests/model/connection/test_api_key_connection.py +++ b/runtime/python/prompty/tests/model/connection/test_api_key_connection.py @@ -26,7 +26,7 @@ def test_load_yaml_apikeyconnection(): kind: key endpoint: "https://{your-custom-endpoint}.openai.azure.com/" apiKey: your-api-key - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = ApiKeyConnection.load(data) diff --git a/runtime/python/prompty/tests/model/connection/test_connection.py b/runtime/python/prompty/tests/model/connection/test_connection.py index 872a0998..4019463d 100644 --- a/runtime/python/prompty/tests/model/connection/test_connection.py +++ b/runtime/python/prompty/tests/model/connection/test_connection.py @@ -26,7 +26,7 @@ def test_load_yaml_connection(): kind: reference authenticationMode: system usageDescription: This will allow the agent to respond to an email on your behalf - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = Connection.load(data) diff --git a/runtime/python/prompty/tests/model/connection/test_foundry_connection.py b/runtime/python/prompty/tests/model/connection/test_foundry_connection.py index 8cb16477..c7cecba9 100644 --- a/runtime/python/prompty/tests/model/connection/test_foundry_connection.py +++ b/runtime/python/prompty/tests/model/connection/test_foundry_connection.py @@ -29,7 +29,7 @@ def test_load_yaml_foundryconnection(): endpoint: "https://myresource.services.ai.azure.com/api/projects/myproject" name: my-openai-connection connectionType: model - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = FoundryConnection.load(data) diff --git a/runtime/python/prompty/tests/model/connection/test_o_auth_connection.py b/runtime/python/prompty/tests/model/connection/test_o_auth_connection.py index d00be0da..79e5f353 100644 --- a/runtime/python/prompty/tests/model/connection/test_o_auth_connection.py +++ b/runtime/python/prompty/tests/model/connection/test_o_auth_connection.py @@ -37,7 +37,7 @@ def test_load_yaml_oauthconnection(): tokenUrl: "https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token" scopes: - "https://cognitiveservices.azure.com/.default" - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = OAuthConnection.load(data) diff --git a/runtime/python/prompty/tests/model/connection/test_reference_connection.py b/runtime/python/prompty/tests/model/connection/test_reference_connection.py index e1413c3a..e3aa655b 100644 --- a/runtime/python/prompty/tests/model/connection/test_reference_connection.py +++ b/runtime/python/prompty/tests/model/connection/test_reference_connection.py @@ -26,7 +26,7 @@ def test_load_yaml_referenceconnection(): kind: reference name: my-reference-connection target: my-target-resource - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = ReferenceConnection.load(data) diff --git a/runtime/python/prompty/tests/model/connection/test_remote_connection.py b/runtime/python/prompty/tests/model/connection/test_remote_connection.py index c5799c41..345edaaa 100644 --- a/runtime/python/prompty/tests/model/connection/test_remote_connection.py +++ b/runtime/python/prompty/tests/model/connection/test_remote_connection.py @@ -26,7 +26,7 @@ def test_load_yaml_remoteconnection(): kind: remote name: my-reference-connection endpoint: "https://{your-custom-endpoint}.openai.azure.com/" - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = RemoteConnection.load(data) diff --git a/runtime/python/prompty/tests/model/conversation/test_audio_part.py b/runtime/python/prompty/tests/model/conversation/test_audio_part.py index aa6fb24a..7d65c3c2 100644 --- a/runtime/python/prompty/tests/model/conversation/test_audio_part.py +++ b/runtime/python/prompty/tests/model/conversation/test_audio_part.py @@ -23,7 +23,7 @@ def test_load_yaml_audiopart(): yaml_data = r""" source: "https://example.com/audio.wav" mediaType: audio/wav - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = AudioPart.load(data) diff --git a/runtime/python/prompty/tests/model/conversation/test_file_part.py b/runtime/python/prompty/tests/model/conversation/test_file_part.py index f47505b4..22967d53 100644 --- a/runtime/python/prompty/tests/model/conversation/test_file_part.py +++ b/runtime/python/prompty/tests/model/conversation/test_file_part.py @@ -23,7 +23,7 @@ def test_load_yaml_filepart(): yaml_data = r""" source: "https://example.com/document.pdf" mediaType: application/pdf - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = FilePart.load(data) diff --git a/runtime/python/prompty/tests/model/conversation/test_image_part.py b/runtime/python/prompty/tests/model/conversation/test_image_part.py index 97e53a92..f7fa3f59 100644 --- a/runtime/python/prompty/tests/model/conversation/test_image_part.py +++ b/runtime/python/prompty/tests/model/conversation/test_image_part.py @@ -26,7 +26,7 @@ def test_load_yaml_imagepart(): source: "https://example.com/image.png" detail: auto mediaType: image/png - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = ImagePart.load(data) diff --git a/runtime/python/prompty/tests/model/conversation/test_message.py b/runtime/python/prompty/tests/model/conversation/test_message.py index ac52230a..8bb1119a 100644 --- a/runtime/python/prompty/tests/model/conversation/test_message.py +++ b/runtime/python/prompty/tests/model/conversation/test_message.py @@ -34,7 +34,7 @@ def test_load_yaml_message(): value: Hello! metadata: source: user-input - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = Message.load(data) diff --git a/runtime/python/prompty/tests/model/conversation/test_text_part.py b/runtime/python/prompty/tests/model/conversation/test_text_part.py index b8d22986..66f759f5 100644 --- a/runtime/python/prompty/tests/model/conversation/test_text_part.py +++ b/runtime/python/prompty/tests/model/conversation/test_text_part.py @@ -20,7 +20,7 @@ def test_load_json_textpart(): def test_load_yaml_textpart(): yaml_data = r""" value: Hello, world! - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = TextPart.load(data) diff --git a/runtime/python/prompty/tests/model/conversation/test_thread_marker.py b/runtime/python/prompty/tests/model/conversation/test_thread_marker.py index b9a9b20a..58f7ee53 100644 --- a/runtime/python/prompty/tests/model/conversation/test_thread_marker.py +++ b/runtime/python/prompty/tests/model/conversation/test_thread_marker.py @@ -23,7 +23,7 @@ def test_load_yaml_threadmarker(): yaml_data = r""" name: thread kind: thread - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = ThreadMarker.load(data) diff --git a/runtime/python/prompty/tests/model/conversation/test_tool_call.py b/runtime/python/prompty/tests/model/conversation/test_tool_call.py index a7248f51..7d3ab534 100644 --- a/runtime/python/prompty/tests/model/conversation/test_tool_call.py +++ b/runtime/python/prompty/tests/model/conversation/test_tool_call.py @@ -26,7 +26,7 @@ def test_load_yaml_toolcall(): id: call_abc123 name: get_weather arguments: "{\"city\": \"Paris\"}" - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = ToolCall.load(data) diff --git a/runtime/python/prompty/tests/model/conversation/test_tool_result.py b/runtime/python/prompty/tests/model/conversation/test_tool_result.py index 1717e47d..f8bb462b 100644 --- a/runtime/python/prompty/tests/model/conversation/test_tool_result.py +++ b/runtime/python/prompty/tests/model/conversation/test_tool_result.py @@ -13,12 +13,18 @@ def test_load_json_toolresult(): "kind": "text", "value": "72°F and sunny" } - ] + ], + "errorKind": "missing_tool", + "errorMessage": "Tool 'get_weather' is not registered", + "durationMs": 42 } """ data = json.loads(json_data, strict=False) instance = ToolResult.load(data) assert instance is not None + assert instance.error_kind == "missing_tool" + assert instance.error_message == "Tool 'get_weather' is not registered" + assert instance.duration_ms == 42 def test_load_yaml_toolresult(): @@ -26,11 +32,17 @@ def test_load_yaml_toolresult(): parts: - kind: text value: 72°F and sunny - + errorKind: missing_tool + errorMessage: Tool 'get_weather' is not registered + durationMs: 42 + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = ToolResult.load(data) assert instance is not None + assert instance.error_kind == "missing_tool" + assert instance.error_message == "Tool 'get_weather' is not registered" + assert instance.duration_ms == 42 def test_roundtrip_json_toolresult(): @@ -42,7 +54,10 @@ def test_roundtrip_json_toolresult(): "kind": "text", "value": "72°F and sunny" } - ] + ], + "errorKind": "missing_tool", + "errorMessage": "Tool 'get_weather' is not registered", + "durationMs": 42 } """ original_data = json.loads(json_data, strict=False) @@ -50,6 +65,9 @@ def test_roundtrip_json_toolresult(): saved_data = instance.save() reloaded = ToolResult.load(saved_data) assert reloaded is not None + assert reloaded.error_kind == "missing_tool" + assert reloaded.error_message == "Tool 'get_weather' is not registered" + assert reloaded.duration_ms == 42 def test_to_json_toolresult(): @@ -61,7 +79,10 @@ def test_to_json_toolresult(): "kind": "text", "value": "72°F and sunny" } - ] + ], + "errorKind": "missing_tool", + "errorMessage": "Tool 'get_weather' is not registered", + "durationMs": 42 } """ data = json.loads(json_data, strict=False) @@ -81,7 +102,10 @@ def test_to_yaml_toolresult(): "kind": "text", "value": "72°F and sunny" } - ] + ], + "errorKind": "missing_tool", + "errorMessage": "Tool 'get_weather' is not registered", + "durationMs": 42 } """ data = json.loads(json_data, strict=False) diff --git a/runtime/python/prompty/tests/model/core/test_array_property.py b/runtime/python/prompty/tests/model/core/test_array_property.py index 3f63517a..71c4ce25 100644 --- a/runtime/python/prompty/tests/model/core/test_array_property.py +++ b/runtime/python/prompty/tests/model/core/test_array_property.py @@ -22,7 +22,7 @@ def test_load_yaml_arrayproperty(): yaml_data = r""" items: kind: string - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = ArrayProperty.load(data) diff --git a/runtime/python/prompty/tests/model/core/test_file_not_found_error.py b/runtime/python/prompty/tests/model/core/test_file_not_found_error.py index 4151e7c4..ae4a39ac 100644 --- a/runtime/python/prompty/tests/model/core/test_file_not_found_error.py +++ b/runtime/python/prompty/tests/model/core/test_file_not_found_error.py @@ -23,7 +23,7 @@ def test_load_yaml_filenotfounderror(): yaml_data = r""" message: "Prompty file not found: ./chat.prompty" path: ./chat.prompty - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = FileNotFoundError.load(data) diff --git a/runtime/python/prompty/tests/model/core/test_invoker_error.py b/runtime/python/prompty/tests/model/core/test_invoker_error.py index f179e211..640a3b0b 100644 --- a/runtime/python/prompty/tests/model/core/test_invoker_error.py +++ b/runtime/python/prompty/tests/model/core/test_invoker_error.py @@ -26,7 +26,7 @@ def test_load_yaml_invokererror(): message: "No renderer registered for key: jinja2" component: renderer key: jinja2 - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = InvokerError.load(data) diff --git a/runtime/python/prompty/tests/model/core/test_object_property.py b/runtime/python/prompty/tests/model/core/test_object_property.py index 8956d1c0..13209441 100644 --- a/runtime/python/prompty/tests/model/core/test_object_property.py +++ b/runtime/python/prompty/tests/model/core/test_object_property.py @@ -30,7 +30,7 @@ def test_load_yaml_objectproperty(): kind: string property2: kind: number - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = ObjectProperty.load(data) diff --git a/runtime/python/prompty/tests/model/core/test_property.py b/runtime/python/prompty/tests/model/core/test_property.py index 52a0e219..2552c8be 100644 --- a/runtime/python/prompty/tests/model/core/test_property.py +++ b/runtime/python/prompty/tests/model/core/test_property.py @@ -44,7 +44,7 @@ def test_load_yaml_property(): - value1 - value2 - value3 - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = Property.load(data) diff --git a/runtime/python/prompty/tests/model/core/test_validation_error.py b/runtime/python/prompty/tests/model/core/test_validation_error.py index 4c7191b8..31627a60 100644 --- a/runtime/python/prompty/tests/model/core/test_validation_error.py +++ b/runtime/python/prompty/tests/model/core/test_validation_error.py @@ -26,7 +26,7 @@ def test_load_yaml_validationerror(): message: "Missing required input: firstName" property: firstName constraint: required - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = ValidationError.load(data) diff --git a/runtime/python/prompty/tests/model/core/test_validation_result.py b/runtime/python/prompty/tests/model/core/test_validation_result.py index dbd693f9..2c64ec8d 100644 --- a/runtime/python/prompty/tests/model/core/test_validation_result.py +++ b/runtime/python/prompty/tests/model/core/test_validation_result.py @@ -22,7 +22,7 @@ def test_load_yaml_validationresult(): yaml_data = r""" valid: true errors: [] - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = ValidationResult.load(data) diff --git a/runtime/python/prompty/tests/model/events/test_compaction_complete_payload.py b/runtime/python/prompty/tests/model/events/test_compaction_complete_payload.py index e235eb85..85a5a934 100644 --- a/runtime/python/prompty/tests/model/events/test_compaction_complete_payload.py +++ b/runtime/python/prompty/tests/model/events/test_compaction_complete_payload.py @@ -9,7 +9,8 @@ def test_load_json_compactioncompletepayload(): json_data = r""" { "removed": 5, - "remaining": 3 + "remaining": 3, + "summaryLength": 1200 } """ data = json.loads(json_data, strict=False) @@ -17,19 +18,22 @@ def test_load_json_compactioncompletepayload(): assert instance is not None assert instance.removed == 5 assert instance.remaining == 3 + assert instance.summary_length == 1200 def test_load_yaml_compactioncompletepayload(): yaml_data = r""" removed: 5 remaining: 3 - + summaryLength: 1200 + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = CompactionCompletePayload.load(data) assert instance is not None assert instance.removed == 5 assert instance.remaining == 3 + assert instance.summary_length == 1200 def test_roundtrip_json_compactioncompletepayload(): @@ -37,7 +41,8 @@ def test_roundtrip_json_compactioncompletepayload(): json_data = r""" { "removed": 5, - "remaining": 3 + "remaining": 3, + "summaryLength": 1200 } """ original_data = json.loads(json_data, strict=False) @@ -47,6 +52,7 @@ def test_roundtrip_json_compactioncompletepayload(): assert reloaded is not None assert reloaded.removed == 5 assert reloaded.remaining == 3 + assert reloaded.summary_length == 1200 def test_to_json_compactioncompletepayload(): @@ -54,7 +60,8 @@ def test_to_json_compactioncompletepayload(): json_data = r""" { "removed": 5, - "remaining": 3 + "remaining": 3, + "summaryLength": 1200 } """ data = json.loads(json_data, strict=False) @@ -70,7 +77,8 @@ def test_to_yaml_compactioncompletepayload(): json_data = r""" { "removed": 5, - "remaining": 3 + "remaining": 3, + "summaryLength": 1200 } """ data = json.loads(json_data, strict=False) diff --git a/runtime/python/prompty/tests/model/events/test_compaction_failed_payload.py b/runtime/python/prompty/tests/model/events/test_compaction_failed_payload.py index d7ef0d06..6b2f2314 100644 --- a/runtime/python/prompty/tests/model/events/test_compaction_failed_payload.py +++ b/runtime/python/prompty/tests/model/events/test_compaction_failed_payload.py @@ -20,7 +20,7 @@ def test_load_json_compactionfailedpayload(): def test_load_yaml_compactionfailedpayload(): yaml_data = r""" message: Summarization prompt exceeded context window - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = CompactionFailedPayload.load(data) diff --git a/runtime/python/prompty/tests/model/events/test_compaction_start_payload.py b/runtime/python/prompty/tests/model/events/test_compaction_start_payload.py new file mode 100644 index 00000000..803790ae --- /dev/null +++ b/runtime/python/prompty/tests/model/events/test_compaction_start_payload.py @@ -0,0 +1,73 @@ +import json + +import yaml + +from prompty.model import CompactionStartPayload + + +def test_load_json_compactionstartpayload(): + json_data = r""" + { + "droppedCount": 5 + } + """ + data = json.loads(json_data, strict=False) + instance = CompactionStartPayload.load(data) + assert instance is not None + assert instance.dropped_count == 5 + + +def test_load_yaml_compactionstartpayload(): + yaml_data = r""" + droppedCount: 5 + + """ + data = yaml.load(yaml_data, Loader=yaml.FullLoader) + instance = CompactionStartPayload.load(data) + assert instance is not None + assert instance.dropped_count == 5 + + +def test_roundtrip_json_compactionstartpayload(): + """Test that load -> save -> load produces equivalent data.""" + json_data = r""" + { + "droppedCount": 5 + } + """ + original_data = json.loads(json_data, strict=False) + instance = CompactionStartPayload.load(original_data) + saved_data = instance.save() + reloaded = CompactionStartPayload.load(saved_data) + assert reloaded is not None + assert reloaded.dropped_count == 5 + + +def test_to_json_compactionstartpayload(): + """Test that to_json produces valid JSON.""" + json_data = r""" + { + "droppedCount": 5 + } + """ + data = json.loads(json_data, strict=False) + instance = CompactionStartPayload.load(data) + json_output = instance.to_json() + assert json_output is not None + parsed = json.loads(json_output) + assert isinstance(parsed, dict) + + +def test_to_yaml_compactionstartpayload(): + """Test that to_yaml produces valid YAML.""" + json_data = r""" + { + "droppedCount": 5 + } + """ + data = json.loads(json_data, strict=False) + instance = CompactionStartPayload.load(data) + yaml_output = instance.to_yaml() + assert yaml_output is not None + parsed = yaml.safe_load(yaml_output) + assert isinstance(parsed, dict) diff --git a/runtime/python/prompty/tests/model/events/test_done_event_payload.py b/runtime/python/prompty/tests/model/events/test_done_event_payload.py index fbc99566..8b137891 100644 --- a/runtime/python/prompty/tests/model/events/test_done_event_payload.py +++ b/runtime/python/prompty/tests/model/events/test_done_event_payload.py @@ -1,73 +1 @@ -import json -import yaml - -from prompty.model import DoneEventPayload - - -def test_load_json_doneeventpayload(): - json_data = r""" - { - "response": "The weather in Paris is 72°F and sunny." - } - """ - data = json.loads(json_data, strict=False) - instance = DoneEventPayload.load(data) - assert instance is not None - assert instance.response == "The weather in Paris is 72°F and sunny." - - -def test_load_yaml_doneeventpayload(): - yaml_data = r""" - response: The weather in Paris is 72°F and sunny. - - """ - data = yaml.load(yaml_data, Loader=yaml.FullLoader) - instance = DoneEventPayload.load(data) - assert instance is not None - assert instance.response == "The weather in Paris is 72°F and sunny." - - -def test_roundtrip_json_doneeventpayload(): - """Test that load -> save -> load produces equivalent data.""" - json_data = r""" - { - "response": "The weather in Paris is 72°F and sunny." - } - """ - original_data = json.loads(json_data, strict=False) - instance = DoneEventPayload.load(original_data) - saved_data = instance.save() - reloaded = DoneEventPayload.load(saved_data) - assert reloaded is not None - assert reloaded.response == "The weather in Paris is 72°F and sunny." - - -def test_to_json_doneeventpayload(): - """Test that to_json produces valid JSON.""" - json_data = r""" - { - "response": "The weather in Paris is 72°F and sunny." - } - """ - data = json.loads(json_data, strict=False) - instance = DoneEventPayload.load(data) - json_output = instance.to_json() - assert json_output is not None - parsed = json.loads(json_output) - assert isinstance(parsed, dict) - - -def test_to_yaml_doneeventpayload(): - """Test that to_yaml produces valid YAML.""" - json_data = r""" - { - "response": "The weather in Paris is 72°F and sunny." - } - """ - data = json.loads(json_data, strict=False) - instance = DoneEventPayload.load(data) - yaml_output = instance.to_yaml() - assert yaml_output is not None - parsed = yaml.safe_load(yaml_output) - assert isinstance(parsed, dict) diff --git a/runtime/python/prompty/tests/model/events/test_error_chunk.py b/runtime/python/prompty/tests/model/events/test_error_chunk.py index 2116a0b5..9d72fa79 100644 --- a/runtime/python/prompty/tests/model/events/test_error_chunk.py +++ b/runtime/python/prompty/tests/model/events/test_error_chunk.py @@ -20,7 +20,7 @@ def test_load_json_errorchunk(): def test_load_yaml_errorchunk(): yaml_data = r""" message: Rate limit exceeded - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = ErrorChunk.load(data) diff --git a/runtime/python/prompty/tests/model/events/test_error_event_payload.py b/runtime/python/prompty/tests/model/events/test_error_event_payload.py index a68637b2..ab051896 100644 --- a/runtime/python/prompty/tests/model/events/test_error_event_payload.py +++ b/runtime/python/prompty/tests/model/events/test_error_event_payload.py @@ -8,31 +8,41 @@ def test_load_json_erroreventpayload(): json_data = r""" { - "message": "Rate limit exceeded" + "message": "Rate limit exceeded", + "errorKind": "rate_limit", + "phase": "llm" } """ data = json.loads(json_data, strict=False) instance = ErrorEventPayload.load(data) assert instance is not None assert instance.message == "Rate limit exceeded" + assert instance.error_kind == "rate_limit" + assert instance.phase == "llm" def test_load_yaml_erroreventpayload(): yaml_data = r""" message: Rate limit exceeded - + errorKind: rate_limit + phase: llm + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = ErrorEventPayload.load(data) assert instance is not None assert instance.message == "Rate limit exceeded" + assert instance.error_kind == "rate_limit" + assert instance.phase == "llm" def test_roundtrip_json_erroreventpayload(): """Test that load -> save -> load produces equivalent data.""" json_data = r""" { - "message": "Rate limit exceeded" + "message": "Rate limit exceeded", + "errorKind": "rate_limit", + "phase": "llm" } """ original_data = json.loads(json_data, strict=False) @@ -41,13 +51,17 @@ def test_roundtrip_json_erroreventpayload(): reloaded = ErrorEventPayload.load(saved_data) assert reloaded is not None assert reloaded.message == "Rate limit exceeded" + assert reloaded.error_kind == "rate_limit" + assert reloaded.phase == "llm" def test_to_json_erroreventpayload(): """Test that to_json produces valid JSON.""" json_data = r""" { - "message": "Rate limit exceeded" + "message": "Rate limit exceeded", + "errorKind": "rate_limit", + "phase": "llm" } """ data = json.loads(json_data, strict=False) @@ -62,7 +76,9 @@ def test_to_yaml_erroreventpayload(): """Test that to_yaml produces valid YAML.""" json_data = r""" { - "message": "Rate limit exceeded" + "message": "Rate limit exceeded", + "errorKind": "rate_limit", + "phase": "llm" } """ data = json.loads(json_data, strict=False) diff --git a/runtime/python/prompty/tests/model/events/test_llm_complete_payload.py b/runtime/python/prompty/tests/model/events/test_llm_complete_payload.py new file mode 100644 index 00000000..037cb038 --- /dev/null +++ b/runtime/python/prompty/tests/model/events/test_llm_complete_payload.py @@ -0,0 +1,89 @@ +import json + +import yaml + +from prompty.model import LlmCompletePayload + + +def test_load_json_llmcompletepayload(): + json_data = r""" + { + "requestId": "req_abc123", + "serviceRequestId": "srv_abc123", + "durationMs": 820 + } + """ + data = json.loads(json_data, strict=False) + instance = LlmCompletePayload.load(data) + assert instance is not None + assert instance.request_id == "req_abc123" + assert instance.service_request_id == "srv_abc123" + assert instance.duration_ms == 820 + + +def test_load_yaml_llmcompletepayload(): + yaml_data = r""" + requestId: req_abc123 + serviceRequestId: srv_abc123 + durationMs: 820 + + """ + data = yaml.load(yaml_data, Loader=yaml.FullLoader) + instance = LlmCompletePayload.load(data) + assert instance is not None + assert instance.request_id == "req_abc123" + assert instance.service_request_id == "srv_abc123" + assert instance.duration_ms == 820 + + +def test_roundtrip_json_llmcompletepayload(): + """Test that load -> save -> load produces equivalent data.""" + json_data = r""" + { + "requestId": "req_abc123", + "serviceRequestId": "srv_abc123", + "durationMs": 820 + } + """ + original_data = json.loads(json_data, strict=False) + instance = LlmCompletePayload.load(original_data) + saved_data = instance.save() + reloaded = LlmCompletePayload.load(saved_data) + assert reloaded is not None + assert reloaded.request_id == "req_abc123" + assert reloaded.service_request_id == "srv_abc123" + assert reloaded.duration_ms == 820 + + +def test_to_json_llmcompletepayload(): + """Test that to_json produces valid JSON.""" + json_data = r""" + { + "requestId": "req_abc123", + "serviceRequestId": "srv_abc123", + "durationMs": 820 + } + """ + data = json.loads(json_data, strict=False) + instance = LlmCompletePayload.load(data) + json_output = instance.to_json() + assert json_output is not None + parsed = json.loads(json_output) + assert isinstance(parsed, dict) + + +def test_to_yaml_llmcompletepayload(): + """Test that to_yaml produces valid YAML.""" + json_data = r""" + { + "requestId": "req_abc123", + "serviceRequestId": "srv_abc123", + "durationMs": 820 + } + """ + data = json.loads(json_data, strict=False) + instance = LlmCompletePayload.load(data) + yaml_output = instance.to_yaml() + assert yaml_output is not None + parsed = yaml.safe_load(yaml_output) + assert isinstance(parsed, dict) diff --git a/runtime/python/prompty/tests/model/events/test_llm_start_payload.py b/runtime/python/prompty/tests/model/events/test_llm_start_payload.py new file mode 100644 index 00000000..c0a8f15d --- /dev/null +++ b/runtime/python/prompty/tests/model/events/test_llm_start_payload.py @@ -0,0 +1,97 @@ +import json + +import yaml + +from prompty.model import LlmStartPayload + + +def test_load_json_llmstartpayload(): + json_data = r""" + { + "provider": "openai", + "modelId": "gpt-4o-mini", + "messageCount": 4, + "attempt": 0 + } + """ + data = json.loads(json_data, strict=False) + instance = LlmStartPayload.load(data) + assert instance is not None + assert instance.provider == "openai" + assert instance.model_id == "gpt-4o-mini" + assert instance.message_count == 4 + assert instance.attempt == 0 + + +def test_load_yaml_llmstartpayload(): + yaml_data = r""" + provider: openai + modelId: gpt-4o-mini + messageCount: 4 + attempt: 0 + + """ + data = yaml.load(yaml_data, Loader=yaml.FullLoader) + instance = LlmStartPayload.load(data) + assert instance is not None + assert instance.provider == "openai" + assert instance.model_id == "gpt-4o-mini" + assert instance.message_count == 4 + assert instance.attempt == 0 + + +def test_roundtrip_json_llmstartpayload(): + """Test that load -> save -> load produces equivalent data.""" + json_data = r""" + { + "provider": "openai", + "modelId": "gpt-4o-mini", + "messageCount": 4, + "attempt": 0 + } + """ + original_data = json.loads(json_data, strict=False) + instance = LlmStartPayload.load(original_data) + saved_data = instance.save() + reloaded = LlmStartPayload.load(saved_data) + assert reloaded is not None + assert reloaded.provider == "openai" + assert reloaded.model_id == "gpt-4o-mini" + assert reloaded.message_count == 4 + assert reloaded.attempt == 0 + + +def test_to_json_llmstartpayload(): + """Test that to_json produces valid JSON.""" + json_data = r""" + { + "provider": "openai", + "modelId": "gpt-4o-mini", + "messageCount": 4, + "attempt": 0 + } + """ + data = json.loads(json_data, strict=False) + instance = LlmStartPayload.load(data) + json_output = instance.to_json() + assert json_output is not None + parsed = json.loads(json_output) + assert isinstance(parsed, dict) + + +def test_to_yaml_llmstartpayload(): + """Test that to_yaml produces valid YAML.""" + json_data = r""" + { + "provider": "openai", + "modelId": "gpt-4o-mini", + "messageCount": 4, + "attempt": 0 + } + """ + data = json.loads(json_data, strict=False) + instance = LlmStartPayload.load(data) + yaml_output = instance.to_yaml() + assert yaml_output is not None + parsed = yaml.safe_load(yaml_output) + assert isinstance(parsed, dict) diff --git a/runtime/python/prompty/tests/model/events/test_messages_updated_payload.py b/runtime/python/prompty/tests/model/events/test_messages_updated_payload.py index 8b137891..374aa720 100644 --- a/runtime/python/prompty/tests/model/events/test_messages_updated_payload.py +++ b/runtime/python/prompty/tests/model/events/test_messages_updated_payload.py @@ -1 +1,81 @@ +import json +import yaml + +from prompty.model import MessagesUpdatedPayload + + +def test_load_json_messagesupdatedpayload(): + json_data = r""" + { + "reason": "tool_results", + "removed": 2 + } + """ + data = json.loads(json_data, strict=False) + instance = MessagesUpdatedPayload.load(data) + assert instance is not None + assert instance.reason == "tool_results" + assert instance.removed == 2 + + +def test_load_yaml_messagesupdatedpayload(): + yaml_data = r""" + reason: tool_results + removed: 2 + + """ + data = yaml.load(yaml_data, Loader=yaml.FullLoader) + instance = MessagesUpdatedPayload.load(data) + assert instance is not None + assert instance.reason == "tool_results" + assert instance.removed == 2 + + +def test_roundtrip_json_messagesupdatedpayload(): + """Test that load -> save -> load produces equivalent data.""" + json_data = r""" + { + "reason": "tool_results", + "removed": 2 + } + """ + original_data = json.loads(json_data, strict=False) + instance = MessagesUpdatedPayload.load(original_data) + saved_data = instance.save() + reloaded = MessagesUpdatedPayload.load(saved_data) + assert reloaded is not None + assert reloaded.reason == "tool_results" + assert reloaded.removed == 2 + + +def test_to_json_messagesupdatedpayload(): + """Test that to_json produces valid JSON.""" + json_data = r""" + { + "reason": "tool_results", + "removed": 2 + } + """ + data = json.loads(json_data, strict=False) + instance = MessagesUpdatedPayload.load(data) + json_output = instance.to_json() + assert json_output is not None + parsed = json.loads(json_output) + assert isinstance(parsed, dict) + + +def test_to_yaml_messagesupdatedpayload(): + """Test that to_yaml produces valid YAML.""" + json_data = r""" + { + "reason": "tool_results", + "removed": 2 + } + """ + data = json.loads(json_data, strict=False) + instance = MessagesUpdatedPayload.load(data) + yaml_output = instance.to_yaml() + assert yaml_output is not None + parsed = yaml.safe_load(yaml_output) + assert isinstance(parsed, dict) diff --git a/runtime/python/prompty/tests/model/events/test_permission_completed_payload.py b/runtime/python/prompty/tests/model/events/test_permission_completed_payload.py new file mode 100644 index 00000000..7fbf6d29 --- /dev/null +++ b/runtime/python/prompty/tests/model/events/test_permission_completed_payload.py @@ -0,0 +1,89 @@ +import json + +import yaml + +from prompty.model import PermissionCompletedPayload + + +def test_load_json_permissioncompletedpayload(): + json_data = r""" + { + "permission": "tool.execute", + "approved": true, + "reason": "user_approved" + } + """ + data = json.loads(json_data, strict=False) + instance = PermissionCompletedPayload.load(data) + assert instance is not None + assert instance.permission == "tool.execute" + assert instance.approved + assert instance.reason == "user_approved" + + +def test_load_yaml_permissioncompletedpayload(): + yaml_data = r""" + permission: tool.execute + approved: true + reason: user_approved + + """ + data = yaml.load(yaml_data, Loader=yaml.FullLoader) + instance = PermissionCompletedPayload.load(data) + assert instance is not None + assert instance.permission == "tool.execute" + assert instance.approved + assert instance.reason == "user_approved" + + +def test_roundtrip_json_permissioncompletedpayload(): + """Test that load -> save -> load produces equivalent data.""" + json_data = r""" + { + "permission": "tool.execute", + "approved": true, + "reason": "user_approved" + } + """ + original_data = json.loads(json_data, strict=False) + instance = PermissionCompletedPayload.load(original_data) + saved_data = instance.save() + reloaded = PermissionCompletedPayload.load(saved_data) + assert reloaded is not None + assert reloaded.permission == "tool.execute" + assert reloaded.approved + assert reloaded.reason == "user_approved" + + +def test_to_json_permissioncompletedpayload(): + """Test that to_json produces valid JSON.""" + json_data = r""" + { + "permission": "tool.execute", + "approved": true, + "reason": "user_approved" + } + """ + data = json.loads(json_data, strict=False) + instance = PermissionCompletedPayload.load(data) + json_output = instance.to_json() + assert json_output is not None + parsed = json.loads(json_output) + assert isinstance(parsed, dict) + + +def test_to_yaml_permissioncompletedpayload(): + """Test that to_yaml produces valid YAML.""" + json_data = r""" + { + "permission": "tool.execute", + "approved": true, + "reason": "user_approved" + } + """ + data = json.loads(json_data, strict=False) + instance = PermissionCompletedPayload.load(data) + yaml_output = instance.to_yaml() + assert yaml_output is not None + parsed = yaml.safe_load(yaml_output) + assert isinstance(parsed, dict) diff --git a/runtime/python/prompty/tests/model/events/test_permission_requested_payload.py b/runtime/python/prompty/tests/model/events/test_permission_requested_payload.py new file mode 100644 index 00000000..27a040f0 --- /dev/null +++ b/runtime/python/prompty/tests/model/events/test_permission_requested_payload.py @@ -0,0 +1,81 @@ +import json + +import yaml + +from prompty.model import PermissionRequestedPayload + + +def test_load_json_permissionrequestedpayload(): + json_data = r""" + { + "permission": "tool.execute", + "target": "shell" + } + """ + data = json.loads(json_data, strict=False) + instance = PermissionRequestedPayload.load(data) + assert instance is not None + assert instance.permission == "tool.execute" + assert instance.target == "shell" + + +def test_load_yaml_permissionrequestedpayload(): + yaml_data = r""" + permission: tool.execute + target: shell + + """ + data = yaml.load(yaml_data, Loader=yaml.FullLoader) + instance = PermissionRequestedPayload.load(data) + assert instance is not None + assert instance.permission == "tool.execute" + assert instance.target == "shell" + + +def test_roundtrip_json_permissionrequestedpayload(): + """Test that load -> save -> load produces equivalent data.""" + json_data = r""" + { + "permission": "tool.execute", + "target": "shell" + } + """ + original_data = json.loads(json_data, strict=False) + instance = PermissionRequestedPayload.load(original_data) + saved_data = instance.save() + reloaded = PermissionRequestedPayload.load(saved_data) + assert reloaded is not None + assert reloaded.permission == "tool.execute" + assert reloaded.target == "shell" + + +def test_to_json_permissionrequestedpayload(): + """Test that to_json produces valid JSON.""" + json_data = r""" + { + "permission": "tool.execute", + "target": "shell" + } + """ + data = json.loads(json_data, strict=False) + instance = PermissionRequestedPayload.load(data) + json_output = instance.to_json() + assert json_output is not None + parsed = json.loads(json_output) + assert isinstance(parsed, dict) + + +def test_to_yaml_permissionrequestedpayload(): + """Test that to_yaml produces valid YAML.""" + json_data = r""" + { + "permission": "tool.execute", + "target": "shell" + } + """ + data = json.loads(json_data, strict=False) + instance = PermissionRequestedPayload.load(data) + yaml_output = instance.to_yaml() + assert yaml_output is not None + parsed = yaml.safe_load(yaml_output) + assert isinstance(parsed, dict) diff --git a/runtime/python/prompty/tests/model/events/test_retry_payload.py b/runtime/python/prompty/tests/model/events/test_retry_payload.py new file mode 100644 index 00000000..1aa7e60b --- /dev/null +++ b/runtime/python/prompty/tests/model/events/test_retry_payload.py @@ -0,0 +1,105 @@ +import json + +import yaml + +from prompty.model import RetryPayload + + +def test_load_json_retrypayload(): + json_data = r""" + { + "operation": "llm", + "attempt": 2, + "maxAttempts": 3, + "delayMs": 1250, + "reason": "rate_limit" + } + """ + data = json.loads(json_data, strict=False) + instance = RetryPayload.load(data) + assert instance is not None + assert instance.operation == "llm" + assert instance.attempt == 2 + assert instance.max_attempts == 3 + assert instance.delay_ms == 1250 + assert instance.reason == "rate_limit" + + +def test_load_yaml_retrypayload(): + yaml_data = r""" + operation: llm + attempt: 2 + maxAttempts: 3 + delayMs: 1250 + reason: rate_limit + + """ + data = yaml.load(yaml_data, Loader=yaml.FullLoader) + instance = RetryPayload.load(data) + assert instance is not None + assert instance.operation == "llm" + assert instance.attempt == 2 + assert instance.max_attempts == 3 + assert instance.delay_ms == 1250 + assert instance.reason == "rate_limit" + + +def test_roundtrip_json_retrypayload(): + """Test that load -> save -> load produces equivalent data.""" + json_data = r""" + { + "operation": "llm", + "attempt": 2, + "maxAttempts": 3, + "delayMs": 1250, + "reason": "rate_limit" + } + """ + original_data = json.loads(json_data, strict=False) + instance = RetryPayload.load(original_data) + saved_data = instance.save() + reloaded = RetryPayload.load(saved_data) + assert reloaded is not None + assert reloaded.operation == "llm" + assert reloaded.attempt == 2 + assert reloaded.max_attempts == 3 + assert reloaded.delay_ms == 1250 + assert reloaded.reason == "rate_limit" + + +def test_to_json_retrypayload(): + """Test that to_json produces valid JSON.""" + json_data = r""" + { + "operation": "llm", + "attempt": 2, + "maxAttempts": 3, + "delayMs": 1250, + "reason": "rate_limit" + } + """ + data = json.loads(json_data, strict=False) + instance = RetryPayload.load(data) + json_output = instance.to_json() + assert json_output is not None + parsed = json.loads(json_output) + assert isinstance(parsed, dict) + + +def test_to_yaml_retrypayload(): + """Test that to_yaml produces valid YAML.""" + json_data = r""" + { + "operation": "llm", + "attempt": 2, + "maxAttempts": 3, + "delayMs": 1250, + "reason": "rate_limit" + } + """ + data = json.loads(json_data, strict=False) + instance = RetryPayload.load(data) + yaml_output = instance.to_yaml() + assert yaml_output is not None + parsed = yaml.safe_load(yaml_output) + assert isinstance(parsed, dict) diff --git a/runtime/python/prompty/tests/model/events/test_status_event_payload.py b/runtime/python/prompty/tests/model/events/test_status_event_payload.py index 4fd24528..0f73b67e 100644 --- a/runtime/python/prompty/tests/model/events/test_status_event_payload.py +++ b/runtime/python/prompty/tests/model/events/test_status_event_payload.py @@ -20,7 +20,7 @@ def test_load_json_statuseventpayload(): def test_load_yaml_statuseventpayload(): yaml_data = r""" message: Starting iteration 3 - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = StatusEventPayload.load(data) diff --git a/runtime/python/prompty/tests/model/events/test_text_chunk.py b/runtime/python/prompty/tests/model/events/test_text_chunk.py index 54e5bc68..0b9eac8f 100644 --- a/runtime/python/prompty/tests/model/events/test_text_chunk.py +++ b/runtime/python/prompty/tests/model/events/test_text_chunk.py @@ -20,7 +20,7 @@ def test_load_json_textchunk(): def test_load_yaml_textchunk(): yaml_data = r""" value: Hello - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = TextChunk.load(data) diff --git a/runtime/python/prompty/tests/model/events/test_thinking_chunk.py b/runtime/python/prompty/tests/model/events/test_thinking_chunk.py index de449d7d..9efc4643 100644 --- a/runtime/python/prompty/tests/model/events/test_thinking_chunk.py +++ b/runtime/python/prompty/tests/model/events/test_thinking_chunk.py @@ -20,7 +20,7 @@ def test_load_json_thinkingchunk(): def test_load_yaml_thinkingchunk(): yaml_data = r""" value: Let me consider... - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = ThinkingChunk.load(data) diff --git a/runtime/python/prompty/tests/model/events/test_thinking_event_payload.py b/runtime/python/prompty/tests/model/events/test_thinking_event_payload.py index 06b5e6c9..671fd5cf 100644 --- a/runtime/python/prompty/tests/model/events/test_thinking_event_payload.py +++ b/runtime/python/prompty/tests/model/events/test_thinking_event_payload.py @@ -20,7 +20,7 @@ def test_load_json_thinkingeventpayload(): def test_load_yaml_thinkingeventpayload(): yaml_data = r""" token: Let me consider... - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = ThinkingEventPayload.load(data) diff --git a/runtime/python/prompty/tests/model/events/test_token_event_payload.py b/runtime/python/prompty/tests/model/events/test_token_event_payload.py index e0e566ef..829a4ceb 100644 --- a/runtime/python/prompty/tests/model/events/test_token_event_payload.py +++ b/runtime/python/prompty/tests/model/events/test_token_event_payload.py @@ -20,7 +20,7 @@ def test_load_json_tokeneventpayload(): def test_load_yaml_tokeneventpayload(): yaml_data = r""" token: Hello - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = TokenEventPayload.load(data) diff --git a/runtime/python/prompty/tests/model/events/test_tool_call_complete_payload.py b/runtime/python/prompty/tests/model/events/test_tool_call_complete_payload.py new file mode 100644 index 00000000..532d23d0 --- /dev/null +++ b/runtime/python/prompty/tests/model/events/test_tool_call_complete_payload.py @@ -0,0 +1,105 @@ +import json + +import yaml + +from prompty.model import ToolCallCompletePayload + + +def test_load_json_toolcallcompletepayload(): + json_data = r""" + { + "id": "call_abc123", + "name": "get_weather", + "success": true, + "durationMs": 42, + "errorKind": "timeout" + } + """ + data = json.loads(json_data, strict=False) + instance = ToolCallCompletePayload.load(data) + assert instance is not None + assert instance.id == "call_abc123" + assert instance.name == "get_weather" + assert instance.success + assert instance.duration_ms == 42 + assert instance.error_kind == "timeout" + + +def test_load_yaml_toolcallcompletepayload(): + yaml_data = r""" + id: call_abc123 + name: get_weather + success: true + durationMs: 42 + errorKind: timeout + + """ + data = yaml.load(yaml_data, Loader=yaml.FullLoader) + instance = ToolCallCompletePayload.load(data) + assert instance is not None + assert instance.id == "call_abc123" + assert instance.name == "get_weather" + assert instance.success + assert instance.duration_ms == 42 + assert instance.error_kind == "timeout" + + +def test_roundtrip_json_toolcallcompletepayload(): + """Test that load -> save -> load produces equivalent data.""" + json_data = r""" + { + "id": "call_abc123", + "name": "get_weather", + "success": true, + "durationMs": 42, + "errorKind": "timeout" + } + """ + original_data = json.loads(json_data, strict=False) + instance = ToolCallCompletePayload.load(original_data) + saved_data = instance.save() + reloaded = ToolCallCompletePayload.load(saved_data) + assert reloaded is not None + assert reloaded.id == "call_abc123" + assert reloaded.name == "get_weather" + assert reloaded.success + assert reloaded.duration_ms == 42 + assert reloaded.error_kind == "timeout" + + +def test_to_json_toolcallcompletepayload(): + """Test that to_json produces valid JSON.""" + json_data = r""" + { + "id": "call_abc123", + "name": "get_weather", + "success": true, + "durationMs": 42, + "errorKind": "timeout" + } + """ + data = json.loads(json_data, strict=False) + instance = ToolCallCompletePayload.load(data) + json_output = instance.to_json() + assert json_output is not None + parsed = json.loads(json_output) + assert isinstance(parsed, dict) + + +def test_to_yaml_toolcallcompletepayload(): + """Test that to_yaml produces valid YAML.""" + json_data = r""" + { + "id": "call_abc123", + "name": "get_weather", + "success": true, + "durationMs": 42, + "errorKind": "timeout" + } + """ + data = json.loads(json_data, strict=False) + instance = ToolCallCompletePayload.load(data) + yaml_output = instance.to_yaml() + assert yaml_output is not None + parsed = yaml.safe_load(yaml_output) + assert isinstance(parsed, dict) diff --git a/runtime/python/prompty/tests/model/events/test_tool_call_start_payload.py b/runtime/python/prompty/tests/model/events/test_tool_call_start_payload.py index 41d57fe5..1468afe9 100644 --- a/runtime/python/prompty/tests/model/events/test_tool_call_start_payload.py +++ b/runtime/python/prompty/tests/model/events/test_tool_call_start_payload.py @@ -8,6 +8,7 @@ def test_load_json_toolcallstartpayload(): json_data = r""" { + "id": "call_abc123", "name": "get_weather", "arguments": "{\"city\": \"Paris\"}" } @@ -15,19 +16,22 @@ def test_load_json_toolcallstartpayload(): data = json.loads(json_data, strict=False) instance = ToolCallStartPayload.load(data) assert instance is not None + assert instance.id == "call_abc123" assert instance.name == "get_weather" assert instance.arguments == '{"city": "Paris"}' def test_load_yaml_toolcallstartpayload(): yaml_data = r""" + id: call_abc123 name: get_weather arguments: "{\"city\": \"Paris\"}" - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = ToolCallStartPayload.load(data) assert instance is not None + assert instance.id == "call_abc123" assert instance.name == "get_weather" assert instance.arguments == '{"city": "Paris"}' @@ -36,6 +40,7 @@ def test_roundtrip_json_toolcallstartpayload(): """Test that load -> save -> load produces equivalent data.""" json_data = r""" { + "id": "call_abc123", "name": "get_weather", "arguments": "{\"city\": \"Paris\"}" } @@ -45,6 +50,7 @@ def test_roundtrip_json_toolcallstartpayload(): saved_data = instance.save() reloaded = ToolCallStartPayload.load(saved_data) assert reloaded is not None + assert reloaded.id == "call_abc123" assert reloaded.name == "get_weather" assert reloaded.arguments == '{"city": "Paris"}' @@ -53,6 +59,7 @@ def test_to_json_toolcallstartpayload(): """Test that to_json produces valid JSON.""" json_data = r""" { + "id": "call_abc123", "name": "get_weather", "arguments": "{\"city\": \"Paris\"}" } @@ -69,6 +76,7 @@ def test_to_yaml_toolcallstartpayload(): """Test that to_yaml produces valid YAML.""" json_data = r""" { + "id": "call_abc123", "name": "get_weather", "arguments": "{\"city\": \"Paris\"}" } diff --git a/runtime/python/prompty/tests/model/events/test_tool_chunk.py b/runtime/python/prompty/tests/model/events/test_tool_chunk.py index 670e143c..d64011c4 100644 --- a/runtime/python/prompty/tests/model/events/test_tool_chunk.py +++ b/runtime/python/prompty/tests/model/events/test_tool_chunk.py @@ -26,7 +26,7 @@ def test_load_yaml_toolchunk(): id: call_abc123 name: get_weather arguments: "{\"city\": \"Paris\"}" - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = ToolChunk.load(data) diff --git a/runtime/python/prompty/tests/model/events/test_tool_result_payload.py b/runtime/python/prompty/tests/model/events/test_tool_result_payload.py index 31eac0d1..c5f95332 100644 --- a/runtime/python/prompty/tests/model/events/test_tool_result_payload.py +++ b/runtime/python/prompty/tests/model/events/test_tool_result_payload.py @@ -32,7 +32,7 @@ def test_load_yaml_toolresultpayload(): parts: - kind: text value: 72°F and sunny - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = ToolResultPayload.load(data) diff --git a/runtime/python/prompty/tests/model/events/test_turn_end_payload.py b/runtime/python/prompty/tests/model/events/test_turn_end_payload.py new file mode 100644 index 00000000..de85f141 --- /dev/null +++ b/runtime/python/prompty/tests/model/events/test_turn_end_payload.py @@ -0,0 +1,81 @@ +import json + +import yaml + +from prompty.model import TurnEndPayload + + +def test_load_json_turnendpayload(): + json_data = r""" + { + "iterations": 2, + "durationMs": 1500 + } + """ + data = json.loads(json_data, strict=False) + instance = TurnEndPayload.load(data) + assert instance is not None + assert instance.iterations == 2 + assert instance.duration_ms == 1500 + + +def test_load_yaml_turnendpayload(): + yaml_data = r""" + iterations: 2 + durationMs: 1500 + + """ + data = yaml.load(yaml_data, Loader=yaml.FullLoader) + instance = TurnEndPayload.load(data) + assert instance is not None + assert instance.iterations == 2 + assert instance.duration_ms == 1500 + + +def test_roundtrip_json_turnendpayload(): + """Test that load -> save -> load produces equivalent data.""" + json_data = r""" + { + "iterations": 2, + "durationMs": 1500 + } + """ + original_data = json.loads(json_data, strict=False) + instance = TurnEndPayload.load(original_data) + saved_data = instance.save() + reloaded = TurnEndPayload.load(saved_data) + assert reloaded is not None + assert reloaded.iterations == 2 + assert reloaded.duration_ms == 1500 + + +def test_to_json_turnendpayload(): + """Test that to_json produces valid JSON.""" + json_data = r""" + { + "iterations": 2, + "durationMs": 1500 + } + """ + data = json.loads(json_data, strict=False) + instance = TurnEndPayload.load(data) + json_output = instance.to_json() + assert json_output is not None + parsed = json.loads(json_output) + assert isinstance(parsed, dict) + + +def test_to_yaml_turnendpayload(): + """Test that to_yaml produces valid YAML.""" + json_data = r""" + { + "iterations": 2, + "durationMs": 1500 + } + """ + data = json.loads(json_data, strict=False) + instance = TurnEndPayload.load(data) + yaml_output = instance.to_yaml() + assert yaml_output is not None + parsed = yaml.safe_load(yaml_output) + assert isinstance(parsed, dict) diff --git a/runtime/python/prompty/tests/model/events/test_turn_event.py b/runtime/python/prompty/tests/model/events/test_turn_event.py new file mode 100644 index 00000000..13f86793 --- /dev/null +++ b/runtime/python/prompty/tests/model/events/test_turn_event.py @@ -0,0 +1,113 @@ +import json + +import yaml + +from prompty.model import TurnEvent + + +def test_load_json_turnevent(): + json_data = r""" + { + "id": "evt_abc123", + "timestamp": "2026-06-09T20:00:00Z", + "turnId": "turn_001", + "iteration": 0, + "parentId": "evt_parent", + "spanId": "span_tool_001" + } + """ + data = json.loads(json_data, strict=False) + instance = TurnEvent.load(data) + assert instance is not None + assert instance.id == "evt_abc123" + assert instance.timestamp == "2026-06-09T20:00:00Z" + assert instance.turn_id == "turn_001" + assert instance.iteration == 0 + assert instance.parent_id == "evt_parent" + assert instance.span_id == "span_tool_001" + + +def test_load_yaml_turnevent(): + yaml_data = r""" + id: evt_abc123 + timestamp: "2026-06-09T20:00:00Z" + turnId: turn_001 + iteration: 0 + parentId: evt_parent + spanId: span_tool_001 + + """ + data = yaml.load(yaml_data, Loader=yaml.FullLoader) + instance = TurnEvent.load(data) + assert instance is not None + assert instance.id == "evt_abc123" + assert instance.timestamp == "2026-06-09T20:00:00Z" + assert instance.turn_id == "turn_001" + assert instance.iteration == 0 + assert instance.parent_id == "evt_parent" + assert instance.span_id == "span_tool_001" + + +def test_roundtrip_json_turnevent(): + """Test that load -> save -> load produces equivalent data.""" + json_data = r""" + { + "id": "evt_abc123", + "timestamp": "2026-06-09T20:00:00Z", + "turnId": "turn_001", + "iteration": 0, + "parentId": "evt_parent", + "spanId": "span_tool_001" + } + """ + original_data = json.loads(json_data, strict=False) + instance = TurnEvent.load(original_data) + saved_data = instance.save() + reloaded = TurnEvent.load(saved_data) + assert reloaded is not None + assert reloaded.id == "evt_abc123" + assert reloaded.timestamp == "2026-06-09T20:00:00Z" + assert reloaded.turn_id == "turn_001" + assert reloaded.iteration == 0 + assert reloaded.parent_id == "evt_parent" + assert reloaded.span_id == "span_tool_001" + + +def test_to_json_turnevent(): + """Test that to_json produces valid JSON.""" + json_data = r""" + { + "id": "evt_abc123", + "timestamp": "2026-06-09T20:00:00Z", + "turnId": "turn_001", + "iteration": 0, + "parentId": "evt_parent", + "spanId": "span_tool_001" + } + """ + data = json.loads(json_data, strict=False) + instance = TurnEvent.load(data) + json_output = instance.to_json() + assert json_output is not None + parsed = json.loads(json_output) + assert isinstance(parsed, dict) + + +def test_to_yaml_turnevent(): + """Test that to_yaml produces valid YAML.""" + json_data = r""" + { + "id": "evt_abc123", + "timestamp": "2026-06-09T20:00:00Z", + "turnId": "turn_001", + "iteration": 0, + "parentId": "evt_parent", + "spanId": "span_tool_001" + } + """ + data = json.loads(json_data, strict=False) + instance = TurnEvent.load(data) + yaml_output = instance.to_yaml() + assert yaml_output is not None + parsed = yaml.safe_load(yaml_output) + assert isinstance(parsed, dict) diff --git a/runtime/python/prompty/tests/model/events/test_turn_start_payload.py b/runtime/python/prompty/tests/model/events/test_turn_start_payload.py new file mode 100644 index 00000000..b3334c30 --- /dev/null +++ b/runtime/python/prompty/tests/model/events/test_turn_start_payload.py @@ -0,0 +1,81 @@ +import json + +import yaml + +from prompty.model import TurnStartPayload + + +def test_load_json_turnstartpayload(): + json_data = r""" + { + "agent": "weather-agent", + "maxIterations": 10 + } + """ + data = json.loads(json_data, strict=False) + instance = TurnStartPayload.load(data) + assert instance is not None + assert instance.agent == "weather-agent" + assert instance.max_iterations == 10 + + +def test_load_yaml_turnstartpayload(): + yaml_data = r""" + agent: weather-agent + maxIterations: 10 + + """ + data = yaml.load(yaml_data, Loader=yaml.FullLoader) + instance = TurnStartPayload.load(data) + assert instance is not None + assert instance.agent == "weather-agent" + assert instance.max_iterations == 10 + + +def test_roundtrip_json_turnstartpayload(): + """Test that load -> save -> load produces equivalent data.""" + json_data = r""" + { + "agent": "weather-agent", + "maxIterations": 10 + } + """ + original_data = json.loads(json_data, strict=False) + instance = TurnStartPayload.load(original_data) + saved_data = instance.save() + reloaded = TurnStartPayload.load(saved_data) + assert reloaded is not None + assert reloaded.agent == "weather-agent" + assert reloaded.max_iterations == 10 + + +def test_to_json_turnstartpayload(): + """Test that to_json produces valid JSON.""" + json_data = r""" + { + "agent": "weather-agent", + "maxIterations": 10 + } + """ + data = json.loads(json_data, strict=False) + instance = TurnStartPayload.load(data) + json_output = instance.to_json() + assert json_output is not None + parsed = json.loads(json_output) + assert isinstance(parsed, dict) + + +def test_to_yaml_turnstartpayload(): + """Test that to_yaml produces valid YAML.""" + json_data = r""" + { + "agent": "weather-agent", + "maxIterations": 10 + } + """ + data = json.loads(json_data, strict=False) + instance = TurnStartPayload.load(data) + yaml_output = instance.to_yaml() + assert yaml_output is not None + parsed = yaml.safe_load(yaml_output) + assert isinstance(parsed, dict) diff --git a/runtime/python/prompty/tests/model/events/test_turn_summary.py b/runtime/python/prompty/tests/model/events/test_turn_summary.py new file mode 100644 index 00000000..712be713 --- /dev/null +++ b/runtime/python/prompty/tests/model/events/test_turn_summary.py @@ -0,0 +1,121 @@ +import json + +import yaml + +from prompty.model import TurnSummary + + +def test_load_json_turnsummary(): + json_data = r""" + { + "turnId": "turn_001", + "status": "success", + "iterations": 2, + "llmCalls": 3, + "toolCalls": 2, + "retries": 1, + "durationMs": 2500 + } + """ + data = json.loads(json_data, strict=False) + instance = TurnSummary.load(data) + assert instance is not None + assert instance.turn_id == "turn_001" + assert instance.status == "success" + assert instance.iterations == 2 + assert instance.llm_calls == 3 + assert instance.tool_calls == 2 + assert instance.retries == 1 + assert instance.duration_ms == 2500 + + +def test_load_yaml_turnsummary(): + yaml_data = r""" + turnId: turn_001 + status: success + iterations: 2 + llmCalls: 3 + toolCalls: 2 + retries: 1 + durationMs: 2500 + + """ + data = yaml.load(yaml_data, Loader=yaml.FullLoader) + instance = TurnSummary.load(data) + assert instance is not None + assert instance.turn_id == "turn_001" + assert instance.status == "success" + assert instance.iterations == 2 + assert instance.llm_calls == 3 + assert instance.tool_calls == 2 + assert instance.retries == 1 + assert instance.duration_ms == 2500 + + +def test_roundtrip_json_turnsummary(): + """Test that load -> save -> load produces equivalent data.""" + json_data = r""" + { + "turnId": "turn_001", + "status": "success", + "iterations": 2, + "llmCalls": 3, + "toolCalls": 2, + "retries": 1, + "durationMs": 2500 + } + """ + original_data = json.loads(json_data, strict=False) + instance = TurnSummary.load(original_data) + saved_data = instance.save() + reloaded = TurnSummary.load(saved_data) + assert reloaded is not None + assert reloaded.turn_id == "turn_001" + assert reloaded.status == "success" + assert reloaded.iterations == 2 + assert reloaded.llm_calls == 3 + assert reloaded.tool_calls == 2 + assert reloaded.retries == 1 + assert reloaded.duration_ms == 2500 + + +def test_to_json_turnsummary(): + """Test that to_json produces valid JSON.""" + json_data = r""" + { + "turnId": "turn_001", + "status": "success", + "iterations": 2, + "llmCalls": 3, + "toolCalls": 2, + "retries": 1, + "durationMs": 2500 + } + """ + data = json.loads(json_data, strict=False) + instance = TurnSummary.load(data) + json_output = instance.to_json() + assert json_output is not None + parsed = json.loads(json_output) + assert isinstance(parsed, dict) + + +def test_to_yaml_turnsummary(): + """Test that to_yaml produces valid YAML.""" + json_data = r""" + { + "turnId": "turn_001", + "status": "success", + "iterations": 2, + "llmCalls": 3, + "toolCalls": 2, + "retries": 1, + "durationMs": 2500 + } + """ + data = json.loads(json_data, strict=False) + instance = TurnSummary.load(data) + yaml_output = instance.to_yaml() + assert yaml_output is not None + parsed = yaml.safe_load(yaml_output) + assert isinstance(parsed, dict) diff --git a/runtime/python/prompty/tests/model/events/test_turn_trace.py b/runtime/python/prompty/tests/model/events/test_turn_trace.py new file mode 100644 index 00000000..3d8852df --- /dev/null +++ b/runtime/python/prompty/tests/model/events/test_turn_trace.py @@ -0,0 +1,89 @@ +import json + +import yaml + +from prompty.model import TurnTrace + + +def test_load_json_turntrace(): + json_data = r""" + { + "version": "1", + "runtime": "typescript", + "promptyVersion": "2.0.0" + } + """ + data = json.loads(json_data, strict=False) + instance = TurnTrace.load(data) + assert instance is not None + assert instance.version == "1" + assert instance.runtime == "typescript" + assert instance.prompty_version == "2.0.0" + + +def test_load_yaml_turntrace(): + yaml_data = r""" + version: "1" + runtime: typescript + promptyVersion: 2.0.0 + + """ + data = yaml.load(yaml_data, Loader=yaml.FullLoader) + instance = TurnTrace.load(data) + assert instance is not None + assert instance.version == "1" + assert instance.runtime == "typescript" + assert instance.prompty_version == "2.0.0" + + +def test_roundtrip_json_turntrace(): + """Test that load -> save -> load produces equivalent data.""" + json_data = r""" + { + "version": "1", + "runtime": "typescript", + "promptyVersion": "2.0.0" + } + """ + original_data = json.loads(json_data, strict=False) + instance = TurnTrace.load(original_data) + saved_data = instance.save() + reloaded = TurnTrace.load(saved_data) + assert reloaded is not None + assert reloaded.version == "1" + assert reloaded.runtime == "typescript" + assert reloaded.prompty_version == "2.0.0" + + +def test_to_json_turntrace(): + """Test that to_json produces valid JSON.""" + json_data = r""" + { + "version": "1", + "runtime": "typescript", + "promptyVersion": "2.0.0" + } + """ + data = json.loads(json_data, strict=False) + instance = TurnTrace.load(data) + json_output = instance.to_json() + assert json_output is not None + parsed = json.loads(json_output) + assert isinstance(parsed, dict) + + +def test_to_yaml_turntrace(): + """Test that to_yaml produces valid YAML.""" + json_data = r""" + { + "version": "1", + "runtime": "typescript", + "promptyVersion": "2.0.0" + } + """ + data = json.loads(json_data, strict=False) + instance = TurnTrace.load(data) + yaml_output = instance.to_yaml() + assert yaml_output is not None + parsed = yaml.safe_load(yaml_output) + assert isinstance(parsed, dict) diff --git a/runtime/python/prompty/tests/model/model/test_model.py b/runtime/python/prompty/tests/model/model/test_model.py index d704c191..e5b775be 100644 --- a/runtime/python/prompty/tests/model/model/test_model.py +++ b/runtime/python/prompty/tests/model/model/test_model.py @@ -44,7 +44,7 @@ def test_load_yaml_model(): type: chat temperature: 0.7 maxOutputTokens: 1000 - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = Model.load(data) diff --git a/runtime/python/prompty/tests/model/model/test_model_info.py b/runtime/python/prompty/tests/model/model/test_model_info.py index da7b8da7..3a65b1a9 100644 --- a/runtime/python/prompty/tests/model/model/test_model_info.py +++ b/runtime/python/prompty/tests/model/model/test_model_info.py @@ -46,7 +46,7 @@ def test_load_yaml_modelinfo(): - text additionalProperties: supportsStreaming: true - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = ModelInfo.load(data) diff --git a/runtime/python/prompty/tests/model/model/test_model_options.py b/runtime/python/prompty/tests/model/model/test_model_options.py index 37ee578e..fa7e8e7d 100644 --- a/runtime/python/prompty/tests/model/model/test_model_options.py +++ b/runtime/python/prompty/tests/model/model/test_model_options.py @@ -55,7 +55,7 @@ def test_load_yaml_modeloptions(): additionalProperties: customProperty: value anotherProperty: anotherValue - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = ModelOptions.load(data) diff --git a/runtime/python/prompty/tests/model/model/test_token_usage.py b/runtime/python/prompty/tests/model/model/test_token_usage.py index 458c67ae..6fde31a7 100644 --- a/runtime/python/prompty/tests/model/model/test_token_usage.py +++ b/runtime/python/prompty/tests/model/model/test_token_usage.py @@ -26,7 +26,7 @@ def test_load_yaml_tokenusage(): promptTokens: 150 completionTokens: 42 totalTokens: 192 - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = TokenUsage.load(data) diff --git a/runtime/python/prompty/tests/model/pipeline/test_compaction_config.py b/runtime/python/prompty/tests/model/pipeline/test_compaction_config.py index ce637de9..d3329fe4 100644 --- a/runtime/python/prompty/tests/model/pipeline/test_compaction_config.py +++ b/runtime/python/prompty/tests/model/pipeline/test_compaction_config.py @@ -28,7 +28,7 @@ def test_load_yaml_compactionconfig(): budget: 50000 options: preserveSystemMessages: true - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = CompactionConfig.load(data) diff --git a/runtime/python/prompty/tests/model/pipeline/test_turn_options.py b/runtime/python/prompty/tests/model/pipeline/test_turn_options.py index 8045097d..5320b2a4 100644 --- a/runtime/python/prompty/tests/model/pipeline/test_turn_options.py +++ b/runtime/python/prompty/tests/model/pipeline/test_turn_options.py @@ -40,7 +40,7 @@ def test_load_yaml_turnoptions(): turn: 1 compaction: strategy: summarize - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = TurnOptions.load(data) diff --git a/runtime/python/prompty/tests/model/streaming/test_stream_options.py b/runtime/python/prompty/tests/model/streaming/test_stream_options.py index fafe09e7..1512544a 100644 --- a/runtime/python/prompty/tests/model/streaming/test_stream_options.py +++ b/runtime/python/prompty/tests/model/streaming/test_stream_options.py @@ -20,7 +20,7 @@ def test_load_json_streamoptions(): def test_load_yaml_streamoptions(): yaml_data = r""" includeUsage: true - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = StreamOptions.load(data) diff --git a/runtime/python/prompty/tests/model/template/test_format_config.py b/runtime/python/prompty/tests/model/template/test_format_config.py index f02d7108..1d232e3e 100644 --- a/runtime/python/prompty/tests/model/template/test_format_config.py +++ b/runtime/python/prompty/tests/model/template/test_format_config.py @@ -28,7 +28,7 @@ def test_load_yaml_formatconfig(): strict: true options: key: value - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = FormatConfig.load(data) diff --git a/runtime/python/prompty/tests/model/template/test_parser_config.py b/runtime/python/prompty/tests/model/template/test_parser_config.py index 96b67bc9..81f353ad 100644 --- a/runtime/python/prompty/tests/model/template/test_parser_config.py +++ b/runtime/python/prompty/tests/model/template/test_parser_config.py @@ -25,7 +25,7 @@ def test_load_yaml_parserconfig(): kind: prompty options: key: value - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = ParserConfig.load(data) diff --git a/runtime/python/prompty/tests/model/template/test_template.py b/runtime/python/prompty/tests/model/template/test_template.py index b3f70bbf..aa5bc3a0 100644 --- a/runtime/python/prompty/tests/model/template/test_template.py +++ b/runtime/python/prompty/tests/model/template/test_template.py @@ -27,7 +27,7 @@ def test_load_yaml_template(): kind: mustache parser: kind: mustache - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = Template.load(data) diff --git a/runtime/python/prompty/tests/model/tools/test_binding.py b/runtime/python/prompty/tests/model/tools/test_binding.py index 5726bb56..2f27b071 100644 --- a/runtime/python/prompty/tests/model/tools/test_binding.py +++ b/runtime/python/prompty/tests/model/tools/test_binding.py @@ -23,7 +23,7 @@ def test_load_yaml_binding(): yaml_data = r""" name: my-tool input: input-variable - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = Binding.load(data) diff --git a/runtime/python/prompty/tests/model/tools/test_custom_tool.py b/runtime/python/prompty/tests/model/tools/test_custom_tool.py index 84d56a3d..53b8bdf9 100644 --- a/runtime/python/prompty/tests/model/tools/test_custom_tool.py +++ b/runtime/python/prompty/tests/model/tools/test_custom_tool.py @@ -29,7 +29,7 @@ def test_load_yaml_customtool(): options: timeout: 30 retries: 3 - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = CustomTool.load(data) diff --git a/runtime/python/prompty/tests/model/tools/test_function_tool.py b/runtime/python/prompty/tests/model/tools/test_function_tool.py index fbecb18f..950f9a26 100644 --- a/runtime/python/prompty/tests/model/tools/test_function_tool.py +++ b/runtime/python/prompty/tests/model/tools/test_function_tool.py @@ -47,7 +47,7 @@ def test_load_yaml_functiontool(): kind: string default: What is the meaning of life? strict: true - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = FunctionTool.load(data) @@ -192,7 +192,7 @@ def test_load_yaml_functiontool_1(): kind: string default: What is the meaning of life? strict: true - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = FunctionTool.load(data) diff --git a/runtime/python/prompty/tests/model/tools/test_mcp_approval_mode.py b/runtime/python/prompty/tests/model/tools/test_mcp_approval_mode.py index 7e24ff9a..c81edc9d 100644 --- a/runtime/python/prompty/tests/model/tools/test_mcp_approval_mode.py +++ b/runtime/python/prompty/tests/model/tools/test_mcp_approval_mode.py @@ -30,7 +30,7 @@ def test_load_yaml_mcpapprovalmode(): - operation1 neverRequireApprovalTools: - operation2 - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = McpApprovalMode.load(data) diff --git a/runtime/python/prompty/tests/model/tools/test_mcp_tool.py b/runtime/python/prompty/tests/model/tools/test_mcp_tool.py index 29583f1b..c15dce00 100644 --- a/runtime/python/prompty/tests/model/tools/test_mcp_tool.py +++ b/runtime/python/prompty/tests/model/tools/test_mcp_tool.py @@ -43,7 +43,7 @@ def test_load_yaml_mcptool(): allowedTools: - operation1 - operation2 - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = McpTool.load(data) diff --git a/runtime/python/prompty/tests/model/tools/test_open_api_tool.py b/runtime/python/prompty/tests/model/tools/test_open_api_tool.py index 28b9c85a..09f93de8 100644 --- a/runtime/python/prompty/tests/model/tools/test_open_api_tool.py +++ b/runtime/python/prompty/tests/model/tools/test_open_api_tool.py @@ -28,7 +28,7 @@ def test_load_yaml_openapitool(): connection: kind: reference specification: ./openapi.json - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = OpenApiTool.load(data) diff --git a/runtime/python/prompty/tests/model/tools/test_prompty_tool.py b/runtime/python/prompty/tests/model/tools/test_prompty_tool.py index 08af5ea0..a5200e03 100644 --- a/runtime/python/prompty/tests/model/tools/test_prompty_tool.py +++ b/runtime/python/prompty/tests/model/tools/test_prompty_tool.py @@ -26,7 +26,7 @@ def test_load_yaml_promptytool(): kind: prompty path: ./summarize.prompty mode: single - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = PromptyTool.load(data) diff --git a/runtime/python/prompty/tests/model/tools/test_tool.py b/runtime/python/prompty/tests/model/tools/test_tool.py index d2545228..9df46730 100644 --- a/runtime/python/prompty/tests/model/tools/test_tool.py +++ b/runtime/python/prompty/tests/model/tools/test_tool.py @@ -31,7 +31,7 @@ def test_load_yaml_tool(): description: A description of the tool bindings: input: value - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = Tool.load(data) diff --git a/runtime/python/prompty/tests/model/tools/test_tool_context.py b/runtime/python/prompty/tests/model/tools/test_tool_context.py index 4a7c8552..1ade3a0f 100644 --- a/runtime/python/prompty/tests/model/tools/test_tool_context.py +++ b/runtime/python/prompty/tests/model/tools/test_tool_context.py @@ -22,7 +22,7 @@ def test_load_yaml_toolcontext(): yaml_data = r""" metadata: userId: user-123 - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = ToolContext.load(data) diff --git a/runtime/python/prompty/tests/model/tools/test_tool_dispatch_result.py b/runtime/python/prompty/tests/model/tools/test_tool_dispatch_result.py index 0d8f7ca6..0c38d711 100644 --- a/runtime/python/prompty/tests/model/tools/test_tool_dispatch_result.py +++ b/runtime/python/prompty/tests/model/tools/test_tool_dispatch_result.py @@ -35,7 +35,7 @@ def test_load_yaml_tooldispatchresult(): parts: - kind: text value: 72°F and sunny - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = ToolDispatchResult.load(data) diff --git a/runtime/python/prompty/tests/model/tracing/test_trace_file.py b/runtime/python/prompty/tests/model/tracing/test_trace_file.py index 44da1474..d6fbd6ff 100644 --- a/runtime/python/prompty/tests/model/tracing/test_trace_file.py +++ b/runtime/python/prompty/tests/model/tracing/test_trace_file.py @@ -23,7 +23,7 @@ def test_load_yaml_tracefile(): yaml_data = r""" runtime: python version: 2.0.0 - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = TraceFile.load(data) diff --git a/runtime/python/prompty/tests/model/tracing/test_trace_span.py b/runtime/python/prompty/tests/model/tracing/test_trace_span.py index c0bf9fcb..5cb0cd96 100644 --- a/runtime/python/prompty/tests/model/tracing/test_trace_span.py +++ b/runtime/python/prompty/tests/model/tracing/test_trace_span.py @@ -26,7 +26,7 @@ def test_load_yaml_tracespan(): name: prompty.core.pipeline.run signature: prompty.core.pipeline.run error: Connection refused - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = TraceSpan.load(data) diff --git a/runtime/python/prompty/tests/model/tracing/test_trace_time.py b/runtime/python/prompty/tests/model/tracing/test_trace_time.py index 4b49e7ba..15eeb845 100644 --- a/runtime/python/prompty/tests/model/tracing/test_trace_time.py +++ b/runtime/python/prompty/tests/model/tracing/test_trace_time.py @@ -26,7 +26,7 @@ def test_load_yaml_tracetime(): start: "2026-04-04T12:00:00Z" end: "2026-04-04T12:00:01Z" duration: 1000 - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = TraceTime.load(data) diff --git a/runtime/python/prompty/tests/model/wire/test_anthropic_image_source.py b/runtime/python/prompty/tests/model/wire/test_anthropic_image_source.py index 41b4b1b8..b5e6d5aa 100644 --- a/runtime/python/prompty/tests/model/wire/test_anthropic_image_source.py +++ b/runtime/python/prompty/tests/model/wire/test_anthropic_image_source.py @@ -23,7 +23,7 @@ def test_load_yaml_anthropicimagesource(): yaml_data = r""" media_type: image/png data: iVBORw0KGgo... - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = AnthropicImageSource.load(data) diff --git a/runtime/python/prompty/tests/model/wire/test_anthropic_messages_request.py b/runtime/python/prompty/tests/model/wire/test_anthropic_messages_request.py index a785109a..9f2c0a65 100644 --- a/runtime/python/prompty/tests/model/wire/test_anthropic_messages_request.py +++ b/runtime/python/prompty/tests/model/wire/test_anthropic_messages_request.py @@ -40,7 +40,7 @@ def test_load_yaml_anthropicmessagesrequest(): top_k: 40 stop_sequences: - "\n\nHuman:" - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = AnthropicMessagesRequest.load(data) diff --git a/runtime/python/prompty/tests/model/wire/test_anthropic_messages_response.py b/runtime/python/prompty/tests/model/wire/test_anthropic_messages_response.py index 40f3d812..eb4e2ecf 100644 --- a/runtime/python/prompty/tests/model/wire/test_anthropic_messages_response.py +++ b/runtime/python/prompty/tests/model/wire/test_anthropic_messages_response.py @@ -26,7 +26,7 @@ def test_load_yaml_anthropicmessagesresponse(): id: msg_01XFDUDYJgAACzvnptvVoYEL model: claude-sonnet-4-20250514 stop_reason: end_turn - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = AnthropicMessagesResponse.load(data) diff --git a/runtime/python/prompty/tests/model/wire/test_anthropic_text_block.py b/runtime/python/prompty/tests/model/wire/test_anthropic_text_block.py index 0cfa01a9..bc5e06f4 100644 --- a/runtime/python/prompty/tests/model/wire/test_anthropic_text_block.py +++ b/runtime/python/prompty/tests/model/wire/test_anthropic_text_block.py @@ -20,7 +20,7 @@ def test_load_json_anthropictextblock(): def test_load_yaml_anthropictextblock(): yaml_data = r""" text: Hello, how can I help? - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = AnthropicTextBlock.load(data) diff --git a/runtime/python/prompty/tests/model/wire/test_anthropic_tool_definition.py b/runtime/python/prompty/tests/model/wire/test_anthropic_tool_definition.py index 9567cfb8..3a75f0eb 100644 --- a/runtime/python/prompty/tests/model/wire/test_anthropic_tool_definition.py +++ b/runtime/python/prompty/tests/model/wire/test_anthropic_tool_definition.py @@ -23,7 +23,7 @@ def test_load_yaml_anthropictooldefinition(): yaml_data = r""" name: get_weather description: Get the current weather for a city - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = AnthropicToolDefinition.load(data) diff --git a/runtime/python/prompty/tests/model/wire/test_anthropic_tool_result_block.py b/runtime/python/prompty/tests/model/wire/test_anthropic_tool_result_block.py index a2d244d2..3ae0b0ec 100644 --- a/runtime/python/prompty/tests/model/wire/test_anthropic_tool_result_block.py +++ b/runtime/python/prompty/tests/model/wire/test_anthropic_tool_result_block.py @@ -23,7 +23,7 @@ def test_load_yaml_anthropictoolresultblock(): yaml_data = r""" tool_use_id: toolu_01A09q90qw90lq917835lq9 content: 72°F and sunny in Paris - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = AnthropicToolResultBlock.load(data) diff --git a/runtime/python/prompty/tests/model/wire/test_anthropic_tool_use_block.py b/runtime/python/prompty/tests/model/wire/test_anthropic_tool_use_block.py index 933bbac6..96cbd5e7 100644 --- a/runtime/python/prompty/tests/model/wire/test_anthropic_tool_use_block.py +++ b/runtime/python/prompty/tests/model/wire/test_anthropic_tool_use_block.py @@ -28,7 +28,7 @@ def test_load_yaml_anthropictooluseblock(): name: get_weather input: city: Paris - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = AnthropicToolUseBlock.load(data) diff --git a/runtime/python/prompty/tests/model/wire/test_anthropic_usage.py b/runtime/python/prompty/tests/model/wire/test_anthropic_usage.py index b117e7e8..5e8ad5d6 100644 --- a/runtime/python/prompty/tests/model/wire/test_anthropic_usage.py +++ b/runtime/python/prompty/tests/model/wire/test_anthropic_usage.py @@ -23,7 +23,7 @@ def test_load_yaml_anthropicusage(): yaml_data = r""" input_tokens: 150 output_tokens: 42 - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = AnthropicUsage.load(data) diff --git a/runtime/python/prompty/tests/model/wire/test_anthropic_wire_message.py b/runtime/python/prompty/tests/model/wire/test_anthropic_wire_message.py index 463b607d..d89a84f9 100644 --- a/runtime/python/prompty/tests/model/wire/test_anthropic_wire_message.py +++ b/runtime/python/prompty/tests/model/wire/test_anthropic_wire_message.py @@ -20,7 +20,7 @@ def test_load_json_anthropicwiremessage(): def test_load_yaml_anthropicwiremessage(): yaml_data = r""" role: user - + """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = AnthropicWireMessage.load(data) diff --git a/runtime/rust/prompty/src/model/agent/guardrail_result.rs b/runtime/rust/prompty/src/model/agent/guardrail_result.rs index 881dfcff..7806d46c 100644 --- a/runtime/rust/prompty/src/model/agent/guardrail_result.rs +++ b/runtime/rust/prompty/src/model/agent/guardrail_result.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -45,14 +39,8 @@ impl GuardrailResult { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - allowed: value - .get("allowed") - .and_then(|v| v.as_bool()) - .unwrap_or(false), - reason: value - .get("reason") - .and_then(|v| v.as_str()) - .map(|s| s.to_string()), + allowed: value.get("allowed").and_then(|v| v.as_bool()).unwrap_or(false), + reason: value.get("reason").and_then(|v| v.as_str()).map(|s| s.to_string()), rewrite: value.get("rewrite").cloned(), } } @@ -84,25 +72,14 @@ impl GuardrailResult { } /// Create a GuardrailResult with preset field values. pub fn rewrite(rewrite: impl Into) -> Self { - GuardrailResult { - allowed: true, - rewrite: Some(rewrite.into()), - ..Default::default() - } + GuardrailResult { allowed: true, rewrite: Some(rewrite.into()), ..Default::default() } } /// Create a GuardrailResult with preset field values. pub fn deny(reason: impl Into) -> Self { - GuardrailResult { - allowed: false, - reason: Some(reason.into()), - ..Default::default() - } + GuardrailResult { allowed: false, reason: Some(reason.into()), ..Default::default() } } /// Create a GuardrailResult with preset field values. pub fn allow() -> Self { - GuardrailResult { - allowed: true, - ..Default::default() - } + GuardrailResult { allowed: true, ..Default::default() } } } diff --git a/runtime/rust/prompty/src/model/agent/mod.rs b/runtime/rust/prompty/src/model/agent/mod.rs index fd2959ea..0a791d90 100644 --- a/runtime/rust/prompty/src/model/agent/mod.rs +++ b/runtime/rust/prompty/src/model/agent/mod.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] pub mod prompty; pub use prompty::*; diff --git a/runtime/rust/prompty/src/model/agent/prompty.rs b/runtime/rust/prompty/src/model/agent/prompty.rs index e1bdff83..d1ae92ff 100644 --- a/runtime/rust/prompty/src/model/agent/prompty.rs +++ b/runtime/rust/prompty/src/model/agent/prompty.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -18,7 +12,7 @@ use super::super::template::template::Template; use super::super::tools::tool::Tool; -/// A Prompty is a markdown file format for LLM prompts. The frontmatter defines structured metadata including model configuration, input/output schemas, tools, and template settings. The markdown body becomes the instructions. This is the single root type for the Prompty schema — there is no abstract base class or kind discriminator. A .prompty file always produces a Prompty instance. +/// A Prompty is a markdown file format for LLM prompts. The frontmatter defines structured metadata including model configuration, input/output schemas, tools, and template settings. The markdown body becomes the instructions. This is the single root type for the Prompty schema — there is no abstract base class or kind discriminator. A .prompty file always produces a Prompty instance. Runtime loaders may resolve frontmatter references such as `${env:VAR}` and `${file:relative/path}`. File references must be treated as a host-controlled capability: by default they are scoped to the containing .prompty file's directory tree after canonicalization, and any additional allowed roots must be supplied by the host application's load options rather than frontmatter. #[derive(Debug, Clone, Default)] pub struct Prompty { /// Human-readable name of the prompt @@ -67,48 +61,16 @@ impl Prompty { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - name: value - .get("name") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - display_name: value - .get("displayName") - .and_then(|v| v.as_str()) - .map(|s| s.to_string()), - description: value - .get("description") - .and_then(|v| v.as_str()) - .map(|s| s.to_string()), - metadata: value - .get("metadata") - .cloned() - .unwrap_or(serde_json::Value::Null), - inputs: value - .get("inputs") - .map(|v| Self::load_inputs(v, ctx)) - .unwrap_or_default(), - outputs: value - .get("outputs") - .map(|v| Self::load_outputs(v, ctx)) - .unwrap_or_default(), - model: value - .get("model") - .filter(|v| v.is_object() || v.is_array() || v.is_string()) - .map(|v| Model::load_from_value(v, ctx)) - .unwrap_or_default(), - tools: value - .get("tools") - .map(|v| Self::load_tools(v, ctx)) - .unwrap_or_default(), - template: value - .get("template") - .filter(|v| v.is_object() || v.is_array() || v.is_string()) - .map(|v| Template::load_from_value(v, ctx)), - instructions: value - .get("instructions") - .and_then(|v| v.as_str()) - .map(|s| s.to_string()), + name: value.get("name").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + display_name: value.get("displayName").and_then(|v| v.as_str()).map(|s| s.to_string()), + description: value.get("description").and_then(|v| v.as_str()).map(|s| s.to_string()), + metadata: value.get("metadata").cloned().unwrap_or(serde_json::Value::Null), + inputs: value.get("inputs").map(|v| Self::load_inputs(v, ctx)).unwrap_or_default(), + outputs: value.get("outputs").map(|v| Self::load_outputs(v, ctx)).unwrap_or_default(), + model: value.get("model").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| Model::load_from_value(v, ctx)).unwrap_or_default(), + tools: value.get("tools").map(|v| Self::load_tools(v, ctx)).unwrap_or_default(), + template: value.get("template").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| Template::load_from_value(v, ctx)), + instructions: value.get("instructions").and_then(|v| v.as_str()).map(|s| s.to_string()), } } @@ -119,22 +81,13 @@ impl Prompty { let mut result = serde_json::Map::new(); // Write base fields if !self.name.is_empty() { - result.insert( - "name".to_string(), - serde_json::Value::String(self.name.clone()), - ); + result.insert("name".to_string(), serde_json::Value::String(self.name.clone())); } if let Some(ref val) = self.display_name { - result.insert( - "displayName".to_string(), - serde_json::Value::String(val.clone()), - ); + result.insert("displayName".to_string(), serde_json::Value::String(val.clone())); } if let Some(ref val) = self.description { - result.insert( - "description".to_string(), - serde_json::Value::String(val.clone()), - ); + result.insert("description".to_string(), serde_json::Value::String(val.clone())); } if !self.metadata.is_null() { result.insert("metadata".to_string(), self.metadata.clone()); @@ -143,10 +96,7 @@ impl Prompty { result.insert("inputs".to_string(), Self::save_inputs(&self.inputs, ctx)); } if !self.outputs.is_empty() { - result.insert( - "outputs".to_string(), - Self::save_outputs(&self.outputs, ctx), - ); + result.insert("outputs".to_string(), Self::save_outputs(&self.outputs, ctx)); } { let nested = self.model.to_value(ctx); @@ -164,10 +114,7 @@ impl Prompty { } } if let Some(ref val) = self.instructions { - result.insert( - "instructions".to_string(), - serde_json::Value::String(val.clone()), - ); + result.insert("instructions".to_string(), serde_json::Value::String(val.clone())); } ctx.process_dict(serde_json::Value::Object(result)) } @@ -187,86 +134,77 @@ impl Prompty { self.metadata.as_object() } + /// Load a collection of Property from a JSON value. /// Handles both array format `[{...}]` and dict format `{"name": {...}}`. fn load_inputs(data: &serde_json::Value, ctx: &LoadContext) -> Vec { match data { - serde_json::Value::Array(arr) => arr - .iter() - .map(|v| Property::load_from_value(v, ctx)) - .collect(), - - serde_json::Value::Object(obj) => obj - .iter() - .filter_map(|(name, value)| { - if value.is_array() { - return None; - } - let mut v = if value.is_object() { - value.clone() - } else { - serde_json::json!({ "kind": value }) - }; - if let serde_json::Value::Object(ref mut m) = v { - m.entry("name".to_string()) - .or_insert_with(|| serde_json::Value::String(name.clone())); - } - Some(Property::load_from_value(&v, ctx)) - }) - .collect(), + serde_json::Value::Array(arr) => { + arr.iter().map(|v| Property::load_from_value(v, ctx)).collect() + } + + serde_json::Value::Object(obj) => { + obj.iter() + .filter_map(|(name, value)| { + if value.is_array() { + return None; + } + let mut v = if value.is_object() { + value.clone() + } else { + serde_json::json!({ "kind": value }) + }; + if let serde_json::Value::Object(ref mut m) = v { + m.entry("name".to_string()).or_insert_with(|| serde_json::Value::String(name.clone())); + } + Some(Property::load_from_value(&v, ctx)) + }) + .collect() + } _ => Vec::new(), + } } /// Save a collection of Property to a JSON value. fn save_inputs(items: &[Property], ctx: &SaveContext) -> serde_json::Value { + if ctx.collection_format == "array" { - return serde_json::Value::Array( - items - .iter() - .map(|item| item.to_value(ctx)) - .collect::>(), - ); + return serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()); } // Object format: use name as key let mut result = serde_json::Map::new(); for item in items { let mut item_data = match item.to_value(ctx) { serde_json::Value::Object(m) => m, - other => { - let mut m = serde_json::Map::new(); - m.insert("value".to_string(), other); - m - } + other => { let mut m = serde_json::Map::new(); m.insert("value".to_string(), other); m }, }; if let Some(serde_json::Value::String(name)) = item_data.remove("name") { result.insert(name, serde_json::Value::Object(item_data)); } } serde_json::Value::Object(result) + } /// Load a collection of Property from a JSON value. /// Handles both array format `[{...}]`. fn load_outputs(data: &serde_json::Value, ctx: &LoadContext) -> Vec { match data { - serde_json::Value::Array(arr) => arr - .iter() - .map(|v| Property::load_from_value(v, ctx)) - .collect(), + serde_json::Value::Array(arr) => { + arr.iter().map(|v| Property::load_from_value(v, ctx)).collect() + } _ => Vec::new(), + } } /// Save a collection of Property to a JSON value. fn save_outputs(items: &[Property], ctx: &SaveContext) -> serde_json::Value { - serde_json::Value::Array( - items - .iter() - .map(|item| item.to_value(ctx)) - .collect::>(), - ) + + serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()) + } /// Load a collection of Tool from a JSON value. @@ -277,53 +215,47 @@ impl Prompty { arr.iter().map(|v| Tool::load_from_value(v, ctx)).collect() } - serde_json::Value::Object(obj) => obj - .iter() - .filter_map(|(name, value)| { - if value.is_array() { - return None; - } - let mut v = if value.is_object() { - value.clone() - } else { - serde_json::json!({ "kind": value }) - }; - if let serde_json::Value::Object(ref mut m) = v { - m.entry("name".to_string()) - .or_insert_with(|| serde_json::Value::String(name.clone())); - } - Some(Tool::load_from_value(&v, ctx)) - }) - .collect(), + serde_json::Value::Object(obj) => { + obj.iter() + .filter_map(|(name, value)| { + if value.is_array() { + return None; + } + let mut v = if value.is_object() { + value.clone() + } else { + serde_json::json!({ "kind": value }) + }; + if let serde_json::Value::Object(ref mut m) = v { + m.entry("name".to_string()).or_insert_with(|| serde_json::Value::String(name.clone())); + } + Some(Tool::load_from_value(&v, ctx)) + }) + .collect() + } _ => Vec::new(), + } } /// Save a collection of Tool to a JSON value. fn save_tools(items: &[Tool], ctx: &SaveContext) -> serde_json::Value { + if ctx.collection_format == "array" { - return serde_json::Value::Array( - items - .iter() - .map(|item| item.to_value(ctx)) - .collect::>(), - ); + return serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()); } // Object format: use name as key let mut result = serde_json::Map::new(); for item in items { let mut item_data = match item.to_value(ctx) { serde_json::Value::Object(m) => m, - other => { - let mut m = serde_json::Map::new(); - m.insert("value".to_string(), other); - m - } + other => { let mut m = serde_json::Map::new(); m.insert("value".to_string(), other); m }, }; if let Some(serde_json::Value::String(name)) = item_data.remove("name") { result.insert(name, serde_json::Value::Object(item_data)); } } serde_json::Value::Object(result) + } } diff --git a/runtime/rust/prompty/src/model/connection/connection.rs b/runtime/rust/prompty/src/model/connection/connection.rs index b6aaed31..c34ea881 100644 --- a/runtime/rust/prompty/src/model/connection/connection.rs +++ b/runtime/rust/prompty/src/model/connection/connection.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -48,6 +42,7 @@ impl AuthenticationMode { } } + /// Variant-specific data for [`Connection`], discriminated by `kind`. #[derive(Debug, Clone)] pub enum ConnectionKind { @@ -146,100 +141,37 @@ impl Connection { let kind_str = value.get("kind").and_then(|v| v.as_str()).unwrap_or(""); let kind = match kind_str { "reference" => ConnectionKind::Reference { - name: value - .get("name") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - target: value - .get("target") - .and_then(|v| v.as_str()) - .map(|s| s.to_string()), + name: value.get("name").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + target: value.get("target").and_then(|v| v.as_str()).map(|s| s.to_string()), }, "remote" => ConnectionKind::Remote { - name: value - .get("name") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - endpoint: value - .get("endpoint") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), + name: value.get("name").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + endpoint: value.get("endpoint").and_then(|v| v.as_str()).unwrap_or_default().to_string(), }, "key" => ConnectionKind::ApiKey { - endpoint: value - .get("endpoint") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - api_key: value - .get("apiKey") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), + endpoint: value.get("endpoint").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + api_key: value.get("apiKey").and_then(|v| v.as_str()).unwrap_or_default().to_string(), }, "anonymous" => ConnectionKind::Anonymous { - endpoint: value - .get("endpoint") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), + endpoint: value.get("endpoint").and_then(|v| v.as_str()).unwrap_or_default().to_string(), }, "oauth" => ConnectionKind::OAuth { - endpoint: value - .get("endpoint") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - client_id: value - .get("clientId") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - client_secret: value - .get("clientSecret") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - token_url: value - .get("tokenUrl") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - scopes: value.get("scopes").and_then(|v| v.as_array()).map(|arr| { - arr.iter() - .filter_map(|v| v.as_str().map(|s| s.to_string())) - .collect() - }), + endpoint: value.get("endpoint").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + client_id: value.get("clientId").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + client_secret: value.get("clientSecret").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + token_url: value.get("tokenUrl").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + scopes: value.get("scopes").and_then(|v| v.as_array()).map(|arr| arr.iter().filter_map(|v| v.as_str().map(|s| s.to_string())).collect()), }, "foundry" => ConnectionKind::Foundry { - endpoint: value - .get("endpoint") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - name: value - .get("name") - .and_then(|v| v.as_str()) - .map(|s| s.to_string()), - connection_type: value - .get("connectionType") - .and_then(|v| v.as_str()) - .map(|s| s.to_string()), + endpoint: value.get("endpoint").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + name: value.get("name").and_then(|v| v.as_str()).map(|s| s.to_string()), + connection_type: value.get("connectionType").and_then(|v| v.as_str()).map(|s| s.to_string()), }, _ => ConnectionKind::default(), }; Self { - authentication_mode: value - .get("authenticationMode") - .and_then(|v| v.as_str()) - .and_then(|s| AuthenticationMode::from_str_opt(s)), - usage_description: value - .get("usageDescription") - .and_then(|v| v.as_str()) - .map(|s| s.to_string()), + authentication_mode: value.get("authenticationMode").and_then(|v| v.as_str()).and_then(|s| AuthenticationMode::from_str_opt(s)), + usage_description: value.get("usageDescription").and_then(|v| v.as_str()).map(|s| s.to_string()), kind: kind, } } @@ -262,26 +194,17 @@ impl Connection { pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { let mut result = serde_json::Map::new(); // Write the discriminator - result.insert( - "kind".to_string(), - serde_json::Value::String(self.kind_str().to_string()), - ); + result.insert("kind".to_string(), serde_json::Value::String(self.kind_str().to_string())); // Write base fields if let Some(ref val) = self.authentication_mode { - result.insert( - "authenticationMode".to_string(), - serde_json::Value::String(val.to_string()), - ); + result.insert("authenticationMode".to_string(), serde_json::Value::String(val.to_string())); } if let Some(ref val) = self.usage_description { - result.insert( - "usageDescription".to_string(), - serde_json::Value::String(val.clone()), - ); + result.insert("usageDescription".to_string(), serde_json::Value::String(val.clone())); } // Write variant-specific fields match &self.kind { - ConnectionKind::Reference { name, target, .. } => { + ConnectionKind::Reference { name, target, .. } => { if !name.is_empty() { result.insert("name".to_string(), serde_json::Value::String(name.clone())); } @@ -289,100 +212,53 @@ impl Connection { result.insert("target".to_string(), serde_json::Value::String(val.clone())); } } - ConnectionKind::Remote { name, endpoint, .. } => { + ConnectionKind::Remote { name, endpoint, .. } => { if !name.is_empty() { result.insert("name".to_string(), serde_json::Value::String(name.clone())); } if !endpoint.is_empty() { - result.insert( - "endpoint".to_string(), - serde_json::Value::String(endpoint.clone()), - ); + result.insert("endpoint".to_string(), serde_json::Value::String(endpoint.clone())); } } - ConnectionKind::ApiKey { - endpoint, api_key, .. - } => { + ConnectionKind::ApiKey { endpoint, api_key, .. } => { if !endpoint.is_empty() { - result.insert( - "endpoint".to_string(), - serde_json::Value::String(endpoint.clone()), - ); + result.insert("endpoint".to_string(), serde_json::Value::String(endpoint.clone())); } if !api_key.is_empty() { - result.insert( - "apiKey".to_string(), - serde_json::Value::String(api_key.clone()), - ); + result.insert("apiKey".to_string(), serde_json::Value::String(api_key.clone())); } } - ConnectionKind::Anonymous { endpoint, .. } => { + ConnectionKind::Anonymous { endpoint, .. } => { if !endpoint.is_empty() { - result.insert( - "endpoint".to_string(), - serde_json::Value::String(endpoint.clone()), - ); + result.insert("endpoint".to_string(), serde_json::Value::String(endpoint.clone())); } } - ConnectionKind::OAuth { - endpoint, - client_id, - client_secret, - token_url, - scopes, - .. - } => { + ConnectionKind::OAuth { endpoint, client_id, client_secret, token_url, scopes, .. } => { if !endpoint.is_empty() { - result.insert( - "endpoint".to_string(), - serde_json::Value::String(endpoint.clone()), - ); + result.insert("endpoint".to_string(), serde_json::Value::String(endpoint.clone())); } if !client_id.is_empty() { - result.insert( - "clientId".to_string(), - serde_json::Value::String(client_id.clone()), - ); + result.insert("clientId".to_string(), serde_json::Value::String(client_id.clone())); } if !client_secret.is_empty() { - result.insert( - "clientSecret".to_string(), - serde_json::Value::String(client_secret.clone()), - ); + result.insert("clientSecret".to_string(), serde_json::Value::String(client_secret.clone())); } if !token_url.is_empty() { - result.insert( - "tokenUrl".to_string(), - serde_json::Value::String(token_url.clone()), - ); + result.insert("tokenUrl".to_string(), serde_json::Value::String(token_url.clone())); } if let Some(items) = scopes { - result.insert( - "scopes".to_string(), - serde_json::to_value(items).unwrap_or(serde_json::Value::Null), - ); + result.insert("scopes".to_string(), serde_json::to_value(items).unwrap_or(serde_json::Value::Null)); } } - ConnectionKind::Foundry { - endpoint, - name, - connection_type, - .. - } => { + ConnectionKind::Foundry { endpoint, name, connection_type, .. } => { if !endpoint.is_empty() { - result.insert( - "endpoint".to_string(), - serde_json::Value::String(endpoint.clone()), - ); + result.insert("endpoint".to_string(), serde_json::Value::String(endpoint.clone())); } if let Some(val) = name { result.insert("name".to_string(), serde_json::Value::String(val.clone())); } if let Some(val) = connection_type { - result.insert( - "connectionType".to_string(), - serde_json::Value::String(val.clone()), - ); + result.insert("connectionType".to_string(), serde_json::Value::String(val.clone())); } } } diff --git a/runtime/rust/prompty/src/model/connection/mod.rs b/runtime/rust/prompty/src/model/connection/mod.rs index e340a4a6..c0f3a1e2 100644 --- a/runtime/rust/prompty/src/model/connection/mod.rs +++ b/runtime/rust/prompty/src/model/connection/mod.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] pub mod connection; pub use connection::*; diff --git a/runtime/rust/prompty/src/model/context.rs b/runtime/rust/prompty/src/model/context.rs index 43af8e61..a660f24c 100644 --- a/runtime/rust/prompty/src/model/context.rs +++ b/runtime/rust/prompty/src/model/context.rs @@ -1,13 +1,7 @@ // Code generated by Prompty emitter; DO NOT EDIT. // Prompty Context -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] /// Callback type for pre-processing input data before parsing. pub type PreProcessFn = Box serde_json::Value + Send + Sync>; @@ -168,11 +162,7 @@ impl SaveContext { } /// Convert a value to a JSON string. - pub fn to_json( - &self, - data: &serde_json::Value, - indent: bool, - ) -> Result { + pub fn to_json(&self, data: &serde_json::Value, indent: bool) -> Result { if indent { serde_json::to_string_pretty(data) } else { diff --git a/runtime/rust/prompty/src/model/conversation/content_part.rs b/runtime/rust/prompty/src/model/conversation/content_part.rs index 732c3176..f2a1ae2e 100644 --- a/runtime/rust/prompty/src/model/conversation/content_part.rs +++ b/runtime/rust/prompty/src/model/conversation/content_part.rs @@ -1,15 +1,10 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; + /// Variant-specific data for [`ContentPart`], discriminated by `kind`. #[derive(Debug, Clone)] pub enum ContentPartKind { @@ -83,52 +78,26 @@ impl ContentPart { let kind_str = value.get("kind").and_then(|v| v.as_str()).unwrap_or(""); let kind = match kind_str { "text" => ContentPartKind::TextPart { - value: value - .get("value") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), + value: value.get("value").and_then(|v| v.as_str()).unwrap_or_default().to_string(), }, "image" => ContentPartKind::ImagePart { - source: value - .get("source") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - detail: value - .get("detail") - .and_then(|v| v.as_str()) - .map(|s| s.to_string()), - media_type: value - .get("mediaType") - .and_then(|v| v.as_str()) - .map(|s| s.to_string()), + source: value.get("source").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + detail: value.get("detail").and_then(|v| v.as_str()).map(|s| s.to_string()), + media_type: value.get("mediaType").and_then(|v| v.as_str()).map(|s| s.to_string()), }, "file" => ContentPartKind::FilePart { - source: value - .get("source") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - media_type: value - .get("mediaType") - .and_then(|v| v.as_str()) - .map(|s| s.to_string()), + source: value.get("source").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + media_type: value.get("mediaType").and_then(|v| v.as_str()).map(|s| s.to_string()), }, "audio" => ContentPartKind::AudioPart { - source: value - .get("source") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - media_type: value - .get("mediaType") - .and_then(|v| v.as_str()) - .map(|s| s.to_string()), + source: value.get("source").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + media_type: value.get("mediaType").and_then(|v| v.as_str()).map(|s| s.to_string()), }, _ => ContentPartKind::default(), }; - Self { kind: kind } + Self { + kind: kind, + } } /// Returns the `kind` discriminator string for this instance. @@ -147,73 +116,40 @@ impl ContentPart { pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { let mut result = serde_json::Map::new(); // Write the discriminator - result.insert( - "kind".to_string(), - serde_json::Value::String(self.kind_str().to_string()), - ); + result.insert("kind".to_string(), serde_json::Value::String(self.kind_str().to_string())); // Write base fields // Write variant-specific fields match &self.kind { - ContentPartKind::TextPart { value, .. } => { + ContentPartKind::TextPart { value, .. } => { if !value.is_empty() { - result.insert( - "value".to_string(), - serde_json::Value::String(value.clone()), - ); + result.insert("value".to_string(), serde_json::Value::String(value.clone())); } } - ContentPartKind::ImagePart { - source, - detail, - media_type, - .. - } => { + ContentPartKind::ImagePart { source, detail, media_type, .. } => { if !source.is_empty() { - result.insert( - "source".to_string(), - serde_json::Value::String(source.clone()), - ); + result.insert("source".to_string(), serde_json::Value::String(source.clone())); } if let Some(val) = detail { result.insert("detail".to_string(), serde_json::Value::String(val.clone())); } if let Some(val) = media_type { - result.insert( - "mediaType".to_string(), - serde_json::Value::String(val.clone()), - ); + result.insert("mediaType".to_string(), serde_json::Value::String(val.clone())); } } - ContentPartKind::FilePart { - source, media_type, .. - } => { + ContentPartKind::FilePart { source, media_type, .. } => { if !source.is_empty() { - result.insert( - "source".to_string(), - serde_json::Value::String(source.clone()), - ); + result.insert("source".to_string(), serde_json::Value::String(source.clone())); } if let Some(val) = media_type { - result.insert( - "mediaType".to_string(), - serde_json::Value::String(val.clone()), - ); + result.insert("mediaType".to_string(), serde_json::Value::String(val.clone())); } } - ContentPartKind::AudioPart { - source, media_type, .. - } => { + ContentPartKind::AudioPart { source, media_type, .. } => { if !source.is_empty() { - result.insert( - "source".to_string(), - serde_json::Value::String(source.clone()), - ); + result.insert("source".to_string(), serde_json::Value::String(source.clone())); } if let Some(val) = media_type { - result.insert( - "mediaType".to_string(), - serde_json::Value::String(val.clone()), - ); + result.insert("mediaType".to_string(), serde_json::Value::String(val.clone())); } } } diff --git a/runtime/rust/prompty/src/model/conversation/message.rs b/runtime/rust/prompty/src/model/conversation/message.rs index a41f7c94..a6ccc9ae 100644 --- a/runtime/rust/prompty/src/model/conversation/message.rs +++ b/runtime/rust/prompty/src/model/conversation/message.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -97,19 +91,9 @@ impl Message { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - role: value - .get("role") - .and_then(|v| v.as_str()) - .and_then(|s| Role::from_str_opt(s)) - .unwrap_or(Role::User), - parts: value - .get("parts") - .map(|v| Self::load_parts(v, ctx)) - .unwrap_or_default(), - metadata: value - .get("metadata") - .cloned() - .unwrap_or(serde_json::Value::Null), + role: value.get("role").and_then(|v| v.as_str()).and_then(|s| Role::from_str_opt(s)).unwrap_or(Role::User), + parts: value.get("parts").map(|v| Self::load_parts(v, ctx)).unwrap_or_default(), + metadata: value.get("metadata").cloned().unwrap_or(serde_json::Value::Null), } } @@ -119,10 +103,7 @@ impl Message { pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { let mut result = serde_json::Map::new(); // Write base fields - result.insert( - "role".to_string(), - serde_json::Value::String(self.role.to_string()), - ); + result.insert("role".to_string(), serde_json::Value::String(self.role.to_string())); if !self.parts.is_empty() { result.insert("parts".to_string(), Self::save_parts(&self.parts, ctx)); } @@ -147,60 +128,37 @@ impl Message { self.metadata.as_object() } + /// Load a collection of ContentPart from a JSON value. /// Handles both array format `[{...}]`. fn load_parts(data: &serde_json::Value, ctx: &LoadContext) -> Vec { match data { - serde_json::Value::Array(arr) => arr - .iter() - .map(|v| ContentPart::load_from_value(v, ctx)) - .collect(), + serde_json::Value::Array(arr) => { + arr.iter().map(|v| ContentPart::load_from_value(v, ctx)).collect() + } _ => Vec::new(), + } } /// Save a collection of ContentPart to a JSON value. fn save_parts(items: &[ContentPart], ctx: &SaveContext) -> serde_json::Value { - serde_json::Value::Array( - items - .iter() - .map(|item| item.to_value(ctx)) - .collect::>(), - ) + + serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()) + } /// Create a Message with preset field values. pub fn assistant(text: impl Into) -> Self { - Message { - role: Role::Assistant, - parts: vec![ContentPart { - kind: ContentPartKind::TextPart { value: text.into() }, - ..Default::default() - }], - ..Default::default() - } + Message { role: Role::Assistant, parts: vec![ContentPart { kind: ContentPartKind::TextPart { value: text.into() }, ..Default::default() }], ..Default::default() } } /// Create a Message with preset field values. pub fn system(text: impl Into) -> Self { - Message { - role: Role::System, - parts: vec![ContentPart { - kind: ContentPartKind::TextPart { value: text.into() }, - ..Default::default() - }], - ..Default::default() - } + Message { role: Role::System, parts: vec![ContentPart { kind: ContentPartKind::TextPart { value: text.into() }, ..Default::default() }], ..Default::default() } } /// Create a Message with preset field values. pub fn user(text: impl Into) -> Self { - Message { - role: Role::User, - parts: vec![ContentPart { - kind: ContentPartKind::TextPart { value: text.into() }, - ..Default::default() - }], - ..Default::default() - } + Message { role: Role::User, parts: vec![ContentPart { kind: ContentPartKind::TextPart { value: text.into() }, ..Default::default() }], ..Default::default() } } } /// Helpers for [`Message`]. Implement in a separate file. diff --git a/runtime/rust/prompty/src/model/conversation/mod.rs b/runtime/rust/prompty/src/model/conversation/mod.rs index 62881c2c..ba57a8b5 100644 --- a/runtime/rust/prompty/src/model/conversation/mod.rs +++ b/runtime/rust/prompty/src/model/conversation/mod.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] pub mod content_part; pub use content_part::*; diff --git a/runtime/rust/prompty/src/model/conversation/thread_marker.rs b/runtime/rust/prompty/src/model/conversation/thread_marker.rs index 0cfc6c8a..1e61e4d2 100644 --- a/runtime/rust/prompty/src/model/conversation/thread_marker.rs +++ b/runtime/rust/prompty/src/model/conversation/thread_marker.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -43,16 +37,8 @@ impl ThreadMarker { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - name: value - .get("name") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - kind: value - .get("kind") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), + name: value.get("name").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + kind: value.get("kind").and_then(|v| v.as_str()).unwrap_or_default().to_string(), } } @@ -63,16 +49,10 @@ impl ThreadMarker { let mut result = serde_json::Map::new(); // Write base fields if !self.name.is_empty() { - result.insert( - "name".to_string(), - serde_json::Value::String(self.name.clone()), - ); + result.insert("name".to_string(), serde_json::Value::String(self.name.clone())); } if !self.kind.is_empty() { - result.insert( - "kind".to_string(), - serde_json::Value::String(self.kind.clone()), - ); + result.insert("kind".to_string(), serde_json::Value::String(self.kind.clone())); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/conversation/tool_call.rs b/runtime/rust/prompty/src/model/conversation/tool_call.rs index aadecaee..d4d8f871 100644 --- a/runtime/rust/prompty/src/model/conversation/tool_call.rs +++ b/runtime/rust/prompty/src/model/conversation/tool_call.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -45,21 +39,9 @@ impl ToolCall { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - id: value - .get("id") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - name: value - .get("name") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - arguments: value - .get("arguments") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), + id: value.get("id").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + name: value.get("name").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + arguments: value.get("arguments").and_then(|v| v.as_str()).unwrap_or_default().to_string(), } } @@ -73,16 +55,10 @@ impl ToolCall { result.insert("id".to_string(), serde_json::Value::String(self.id.clone())); } if !self.name.is_empty() { - result.insert( - "name".to_string(), - serde_json::Value::String(self.name.clone()), - ); + result.insert("name".to_string(), serde_json::Value::String(self.name.clone())); } if !self.arguments.is_empty() { - result.insert( - "arguments".to_string(), - serde_json::Value::String(self.arguments.clone()), - ); + result.insert("arguments".to_string(), serde_json::Value::String(self.arguments.clone())); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/conversation/tool_result.rs b/runtime/rust/prompty/src/model/conversation/tool_result.rs index a4f511ed..351b0418 100644 --- a/runtime/rust/prompty/src/model/conversation/tool_result.rs +++ b/runtime/rust/prompty/src/model/conversation/tool_result.rs @@ -1,22 +1,70 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; use super::content_part::{ContentPart, ContentPartKind}; +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum ToolResultStatus { + Success, + Error, + Cancelled, + Timeout, +} + +impl Default for ToolResultStatus { + fn default() -> Self { + Self::Success + } +} + +impl std::fmt::Display for ToolResultStatus { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Success => write!(f, "success"), + Self::Error => write!(f, "error"), + Self::Cancelled => write!(f, "cancelled"), + Self::Timeout => write!(f, "timeout"), + } + } +} + +impl ToolResultStatus { + pub fn from_str_opt(s: &str) -> Option { + match s { + "success" => Some(Self::Success), + "error" => Some(Self::Error), + "cancelled" => Some(Self::Cancelled), + "timeout" => Some(Self::Timeout), + _ => None, + } + } + + pub fn as_str(&self) -> &str { + match self { + Self::Success => "success", + Self::Error => "error", + Self::Cancelled => "cancelled", + Self::Timeout => "timeout", + } + } +} + /// The result of a tool execution. Contains a list of content parts, enabling rich tool results (text, images, files, audio) rather than just strings. Implementations MUST support conversion from a plain string to a ToolResult containing a single TextPart for backward compatibility. #[derive(Debug, Clone, Default)] pub struct ToolResult { /// The content parts of the tool result pub parts: Vec, + /// Semantic execution status for the tool result + pub status: Option, + /// Stable machine-readable error category when status is not success + pub error_kind: Option, + /// Human-readable error message when status is not success + pub error_message: Option, + /// Tool execution duration in milliseconds + pub duration_ms: Option, } impl ToolResult { @@ -43,10 +91,11 @@ impl ToolResult { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - parts: value - .get("parts") - .map(|v| Self::load_parts(v, ctx)) - .unwrap_or_default(), + parts: value.get("parts").map(|v| Self::load_parts(v, ctx)).unwrap_or_default(), + status: value.get("status").and_then(|v| v.as_str()).and_then(|s| ToolResultStatus::from_str_opt(s)), + error_kind: value.get("errorKind").and_then(|v| v.as_str()).map(|s| s.to_string()), + error_message: value.get("errorMessage").and_then(|v| v.as_str()).map(|s| s.to_string()), + duration_ms: value.get("durationMs").and_then(|v| v.as_f64()), } } @@ -59,6 +108,18 @@ impl ToolResult { if !self.parts.is_empty() { result.insert("parts".to_string(), Self::save_parts(&self.parts, ctx)); } + if let Some(ref val) = self.status { + result.insert("status".to_string(), serde_json::Value::String(val.to_string())); + } + if let Some(ref val) = self.error_kind { + result.insert("errorKind".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(ref val) = self.error_message { + result.insert("errorMessage".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(val) = self.duration_ms { + result.insert("durationMs".to_string(), serde_json::Number::from_f64(val as f64).map(serde_json::Value::Number).unwrap_or(serde_json::Value::Null)); + } ctx.process_dict(serde_json::Value::Object(result)) } @@ -76,35 +137,24 @@ impl ToolResult { /// Handles both array format `[{...}]`. fn load_parts(data: &serde_json::Value, ctx: &LoadContext) -> Vec { match data { - serde_json::Value::Array(arr) => arr - .iter() - .map(|v| ContentPart::load_from_value(v, ctx)) - .collect(), + serde_json::Value::Array(arr) => { + arr.iter().map(|v| ContentPart::load_from_value(v, ctx)).collect() + } _ => Vec::new(), + } } /// Save a collection of ContentPart to a JSON value. fn save_parts(items: &[ContentPart], ctx: &SaveContext) -> serde_json::Value { - serde_json::Value::Array( - items - .iter() - .map(|item| item.to_value(ctx)) - .collect::>(), - ) + + serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()) + } /// Create a ToolResult with preset field values. pub fn text(value: impl Into) -> Self { - ToolResult { - parts: vec![ContentPart { - kind: ContentPartKind::TextPart { - value: value.into(), - }, - ..Default::default() - }], - ..Default::default() - } + ToolResult { parts: vec![ContentPart { kind: ContentPartKind::TextPart { value: value.into() }, ..Default::default() }], ..Default::default() } } } /// Helpers for [`ToolResult`]. Implement in a separate file. diff --git a/runtime/rust/prompty/src/model/core/file_not_found_error.rs b/runtime/rust/prompty/src/model/core/file_not_found_error.rs index 7be33010..f5b24962 100644 --- a/runtime/rust/prompty/src/model/core/file_not_found_error.rs +++ b/runtime/rust/prompty/src/model/core/file_not_found_error.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -43,16 +37,8 @@ impl FileNotFoundError { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - message: value - .get("message") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - path: value - .get("path") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), + message: value.get("message").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + path: value.get("path").and_then(|v| v.as_str()).unwrap_or_default().to_string(), } } @@ -63,16 +49,10 @@ impl FileNotFoundError { let mut result = serde_json::Map::new(); // Write base fields if !self.message.is_empty() { - result.insert( - "message".to_string(), - serde_json::Value::String(self.message.clone()), - ); + result.insert("message".to_string(), serde_json::Value::String(self.message.clone())); } if !self.path.is_empty() { - result.insert( - "path".to_string(), - serde_json::Value::String(self.path.clone()), - ); + result.insert("path".to_string(), serde_json::Value::String(self.path.clone())); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/core/invoker_error.rs b/runtime/rust/prompty/src/model/core/invoker_error.rs index abeee49f..6140e913 100644 --- a/runtime/rust/prompty/src/model/core/invoker_error.rs +++ b/runtime/rust/prompty/src/model/core/invoker_error.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -45,21 +39,9 @@ impl InvokerError { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - message: value - .get("message") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - component: value - .get("component") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - key: value - .get("key") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), + message: value.get("message").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + component: value.get("component").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + key: value.get("key").and_then(|v| v.as_str()).unwrap_or_default().to_string(), } } @@ -70,22 +52,13 @@ impl InvokerError { let mut result = serde_json::Map::new(); // Write base fields if !self.message.is_empty() { - result.insert( - "message".to_string(), - serde_json::Value::String(self.message.clone()), - ); + result.insert("message".to_string(), serde_json::Value::String(self.message.clone())); } if !self.component.is_empty() { - result.insert( - "component".to_string(), - serde_json::Value::String(self.component.clone()), - ); + result.insert("component".to_string(), serde_json::Value::String(self.component.clone())); } if !self.key.is_empty() { - result.insert( - "key".to_string(), - serde_json::Value::String(self.key.clone()), - ); + result.insert("key".to_string(), serde_json::Value::String(self.key.clone())); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/core/mod.rs b/runtime/rust/prompty/src/model/core/mod.rs index b4509728..bf18c31f 100644 --- a/runtime/rust/prompty/src/model/core/mod.rs +++ b/runtime/rust/prompty/src/model/core/mod.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] pub mod property; pub use property::*; diff --git a/runtime/rust/prompty/src/model/core/property.rs b/runtime/rust/prompty/src/model/core/property.rs index 16149f5b..69e9c63c 100644 --- a/runtime/rust/prompty/src/model/core/property.rs +++ b/runtime/rust/prompty/src/model/core/property.rs @@ -1,15 +1,10 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; + /// Variant-specific data for [`Property`], discriminated by `kind`. #[derive(Debug, Clone)] pub enum PropertyKind { @@ -80,68 +75,34 @@ impl Property { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); if let Some(value) = value.as_bool() { - return Property { - kind: PropertyKind::Custom { - kind_name: "boolean".to_string(), - }, - example: Some(value.into()), - ..Default::default() - }; + return Property { kind: PropertyKind::Custom { kind_name: "boolean".to_string() }, example: Some(value.into()), ..Default::default() }; } if let Some(value) = value.as_i64() { - return Property { - kind: PropertyKind::Custom { - kind_name: "integer".to_string(), - }, - example: Some(value.into()), - ..Default::default() - }; + return Property { kind: PropertyKind::Custom { kind_name: "integer".to_string() }, example: Some(value.into()), ..Default::default() }; } if let Some(s) = value.as_str() { let value = s.to_string(); - return Property { - kind: PropertyKind::Custom { - kind_name: "string".to_string(), - }, - example: Some(value.into()), - ..Default::default() - }; + return Property { kind: PropertyKind::Custom { kind_name: "string".to_string() }, example: Some(value.into()), ..Default::default() }; } let kind_str = value.get("kind").and_then(|v| v.as_str()).unwrap_or(""); let kind = match kind_str { "array" => PropertyKind::Array { - items: value - .get("items") - .cloned() - .unwrap_or(serde_json::Value::Null), + items: value.get("items").cloned().unwrap_or(serde_json::Value::Null), }, "object" => PropertyKind::Object { - properties: value - .get("properties") - .map(|v| Self::load_properties(v, ctx)) - .unwrap_or_default(), + properties: value.get("properties").map(|v| Self::load_properties(v, ctx)).unwrap_or_default(), }, _ => PropertyKind::Custom { kind_name: kind_str.to_string(), }, }; Self { - name: value - .get("name") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - description: value - .get("description") - .and_then(|v| v.as_str()) - .map(|s| s.to_string()), + name: value.get("name").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + description: value.get("description").and_then(|v| v.as_str()).map(|s| s.to_string()), required: value.get("required").and_then(|v| v.as_bool()), default: value.get("default").cloned(), example: value.get("example").cloned(), - enum_values: value - .get("enumValues") - .and_then(|v| v.as_array()) - .map(|arr| arr.to_vec()), + enum_values: value.get("enumValues").and_then(|v| v.as_array()).map(|arr| arr.to_vec()), kind: kind, } } @@ -161,22 +122,13 @@ impl Property { pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { let mut result = serde_json::Map::new(); // Write the discriminator - result.insert( - "kind".to_string(), - serde_json::Value::String(self.kind_str().to_string()), - ); + result.insert("kind".to_string(), serde_json::Value::String(self.kind_str().to_string())); // Write base fields if !self.name.is_empty() { - result.insert( - "name".to_string(), - serde_json::Value::String(self.name.clone()), - ); + result.insert("name".to_string(), serde_json::Value::String(self.name.clone())); } if let Some(ref val) = self.description { - result.insert( - "description".to_string(), - serde_json::Value::String(val.clone()), - ); + result.insert("description".to_string(), serde_json::Value::String(val.clone())); } if let Some(val) = self.required { result.insert("required".to_string(), serde_json::Value::Bool(val)); @@ -188,29 +140,22 @@ impl Property { result.insert("example".to_string(), val.clone()); } if let Some(ref items) = self.enum_values { - result.insert( - "enumValues".to_string(), - serde_json::to_value(items).unwrap_or(serde_json::Value::Null), - ); + result.insert("enumValues".to_string(), serde_json::to_value(items).unwrap_or(serde_json::Value::Null)); } // Write variant-specific fields match &self.kind { - PropertyKind::Array { items, .. } => { + PropertyKind::Array { items, .. } => { if !items.is_null() { result.insert("items".to_string(), items.clone()); } } - PropertyKind::Object { properties, .. } => { + PropertyKind::Object { properties, .. } => { if !properties.is_empty() { - result.insert( - "properties".to_string(), - serde_json::Value::Array( - properties.iter().map(|item| item.to_value(ctx)).collect(), - ), - ); + result.insert("properties".to_string(), serde_json::Value::Array(properties.iter().map(|item| item.to_value(ctx)).collect())); } } - PropertyKind::Custom { kind_name: _, .. } => {} + PropertyKind::Custom { kind_name: _, .. } => { + } } ctx.process_dict(serde_json::Value::Object(result)) } @@ -229,22 +174,19 @@ impl Property { /// Handles both array format `[{...}]`. fn load_properties(data: &serde_json::Value, ctx: &LoadContext) -> Vec { match data { - serde_json::Value::Array(arr) => arr - .iter() - .map(|v| Property::load_from_value(v, ctx)) - .collect(), + serde_json::Value::Array(arr) => { + arr.iter().map(|v| Property::load_from_value(v, ctx)).collect() + } _ => Vec::new(), + } } /// Save a collection of Property to a JSON value. fn save_properties(items: &[Property], ctx: &SaveContext) -> serde_json::Value { - serde_json::Value::Array( - items - .iter() - .map(|item| item.to_value(ctx)) - .collect::>(), - ) + + serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()) + } } diff --git a/runtime/rust/prompty/src/model/core/validation_error.rs b/runtime/rust/prompty/src/model/core/validation_error.rs index f56c9115..ec2abb0d 100644 --- a/runtime/rust/prompty/src/model/core/validation_error.rs +++ b/runtime/rust/prompty/src/model/core/validation_error.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -45,21 +39,9 @@ impl ValidationError { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - message: value - .get("message") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - property: value - .get("property") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - constraint: value - .get("constraint") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), + message: value.get("message").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + property: value.get("property").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + constraint: value.get("constraint").and_then(|v| v.as_str()).unwrap_or_default().to_string(), } } @@ -70,22 +52,13 @@ impl ValidationError { let mut result = serde_json::Map::new(); // Write base fields if !self.message.is_empty() { - result.insert( - "message".to_string(), - serde_json::Value::String(self.message.clone()), - ); + result.insert("message".to_string(), serde_json::Value::String(self.message.clone())); } if !self.property.is_empty() { - result.insert( - "property".to_string(), - serde_json::Value::String(self.property.clone()), - ); + result.insert("property".to_string(), serde_json::Value::String(self.property.clone())); } if !self.constraint.is_empty() { - result.insert( - "constraint".to_string(), - serde_json::Value::String(self.constraint.clone()), - ); + result.insert("constraint".to_string(), serde_json::Value::String(self.constraint.clone())); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/core/validation_result.rs b/runtime/rust/prompty/src/model/core/validation_result.rs index 823d12c4..ed40b9b4 100644 --- a/runtime/rust/prompty/src/model/core/validation_result.rs +++ b/runtime/rust/prompty/src/model/core/validation_result.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -45,14 +39,8 @@ impl ValidationResult { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - valid: value - .get("valid") - .and_then(|v| v.as_bool()) - .unwrap_or(false), - errors: value - .get("errors") - .map(|v| Self::load_errors(v, ctx)) - .unwrap_or_default(), + valid: value.get("valid").and_then(|v| v.as_bool()).unwrap_or(false), + errors: value.get("errors").map(|v| Self::load_errors(v, ctx)).unwrap_or_default(), } } @@ -83,22 +71,19 @@ impl ValidationResult { /// Handles both array format `[{...}]`. fn load_errors(data: &serde_json::Value, ctx: &LoadContext) -> Vec { match data { - serde_json::Value::Array(arr) => arr - .iter() - .map(|v| ValidationError::load_from_value(v, ctx)) - .collect(), + serde_json::Value::Array(arr) => { + arr.iter().map(|v| ValidationError::load_from_value(v, ctx)).collect() + } _ => Vec::new(), + } } /// Save a collection of ValidationError to a JSON value. fn save_errors(items: &[ValidationError], ctx: &SaveContext) -> serde_json::Value { - serde_json::Value::Array( - items - .iter() - .map(|item| item.to_value(ctx)) - .collect::>(), - ) + + serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()) + } } diff --git a/runtime/rust/prompty/src/model/events/compaction_complete_payload.rs b/runtime/rust/prompty/src/model/events/compaction_complete_payload.rs index 4c710e86..b17a52a0 100644 --- a/runtime/rust/prompty/src/model/events/compaction_complete_payload.rs +++ b/runtime/rust/prompty/src/model/events/compaction_complete_payload.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -17,6 +11,8 @@ pub struct CompactionCompletePayload { pub removed: i32, /// Number of messages remaining after compaction pub remaining: i32, + /// Length of the generated summary, when a summarization strategy is used + pub summary_length: Option, } impl CompactionCompletePayload { @@ -45,6 +41,7 @@ impl CompactionCompletePayload { Self { removed: value.get("removed").and_then(|v| v.as_i64()).unwrap_or(0) as i32, remaining: value.get("remaining").and_then(|v| v.as_i64()).unwrap_or(0) as i32, + summary_length: value.get("summaryLength").and_then(|v| v.as_i64()).map(|v| v as i32), } } @@ -55,16 +52,13 @@ impl CompactionCompletePayload { let mut result = serde_json::Map::new(); // Write base fields if self.removed != 0 { - result.insert( - "removed".to_string(), - serde_json::Value::Number(serde_json::Number::from(self.removed)), - ); + result.insert("removed".to_string(), serde_json::Value::Number(serde_json::Number::from(self.removed))); } if self.remaining != 0 { - result.insert( - "remaining".to_string(), - serde_json::Value::Number(serde_json::Number::from(self.remaining)), - ); + result.insert("remaining".to_string(), serde_json::Value::Number(serde_json::Number::from(self.remaining))); + } + if let Some(val) = self.summary_length { + result.insert("summaryLength".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/events/compaction_failed_payload.rs b/runtime/rust/prompty/src/model/events/compaction_failed_payload.rs index d8c2ccc1..8bc29779 100644 --- a/runtime/rust/prompty/src/model/events/compaction_failed_payload.rs +++ b/runtime/rust/prompty/src/model/events/compaction_failed_payload.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -41,11 +35,7 @@ impl CompactionFailedPayload { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - message: value - .get("message") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), + message: value.get("message").and_then(|v| v.as_str()).unwrap_or_default().to_string(), } } @@ -56,10 +46,7 @@ impl CompactionFailedPayload { let mut result = serde_json::Map::new(); // Write base fields if !self.message.is_empty() { - result.insert( - "message".to_string(), - serde_json::Value::String(self.message.clone()), - ); + result.insert("message".to_string(), serde_json::Value::String(self.message.clone())); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/events/compaction_start_payload.rs b/runtime/rust/prompty/src/model/events/compaction_start_payload.rs new file mode 100644 index 00000000..376bfb7a --- /dev/null +++ b/runtime/rust/prompty/src/model/events/compaction_start_payload.rs @@ -0,0 +1,63 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use super::super::context::{LoadContext, SaveContext}; + +/// Payload for "compaction_start" events — context compaction is beginning. +#[derive(Debug, Clone, Default)] +pub struct CompactionStartPayload { + /// Number of messages selected for compaction + pub dropped_count: i32, +} + +impl CompactionStartPayload { + /// Create a new CompactionStartPayload with default values. + pub fn new() -> Self { + Self::default() + } + + /// Load CompactionStartPayload from a JSON string. + pub fn from_json(json: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_json::from_str(json)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load CompactionStartPayload from a YAML string. + pub fn from_yaml(yaml: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_yaml::from_str(yaml)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load CompactionStartPayload from a `serde_json::Value`. + /// + /// Calls `ctx.process_input` before field extraction. + pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { + let value = ctx.process_input(value.clone()); + Self { + dropped_count: value.get("droppedCount").and_then(|v| v.as_i64()).unwrap_or(0) as i32, + } + } + + /// Serialize CompactionStartPayload to a `serde_json::Value`. + /// + /// Calls `ctx.process_dict` after serialization. + pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { + let mut result = serde_json::Map::new(); + // Write base fields + if self.dropped_count != 0 { + result.insert("droppedCount".to_string(), serde_json::Value::Number(serde_json::Number::from(self.dropped_count))); + } + ctx.process_dict(serde_json::Value::Object(result)) + } + + /// Serialize CompactionStartPayload to a JSON string. + pub fn to_json(&self, ctx: &SaveContext) -> Result { + serde_json::to_string_pretty(&self.to_value(ctx)) + } + + /// Serialize CompactionStartPayload to a YAML string. + pub fn to_yaml(&self, ctx: &SaveContext) -> Result { + serde_yaml::to_string(&self.to_value(ctx)) + } +} diff --git a/runtime/rust/prompty/src/model/events/done_event_payload.rs b/runtime/rust/prompty/src/model/events/done_event_payload.rs index c3ad2cfe..cbaba5b7 100644 --- a/runtime/rust/prompty/src/model/events/done_event_payload.rs +++ b/runtime/rust/prompty/src/model/events/done_event_payload.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -15,8 +9,8 @@ use super::super::conversation::message::Message; /// Payload for "done" events — the agent loop completed successfully. #[derive(Debug, Clone, Default)] pub struct DoneEventPayload { - /// The final text response from the LLM - pub response: String, + /// The final response from the LLM after processing + pub response: serde_json::Value, /// The final conversation state including all messages pub messages: Vec, } @@ -45,15 +39,8 @@ impl DoneEventPayload { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - response: value - .get("response") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - messages: value - .get("messages") - .map(|v| Self::load_messages(v, ctx)) - .unwrap_or_default(), + response: value.get("response").cloned().unwrap_or(serde_json::Value::Null), + messages: value.get("messages").map(|v| Self::load_messages(v, ctx)).unwrap_or_default(), } } @@ -63,17 +50,11 @@ impl DoneEventPayload { pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { let mut result = serde_json::Map::new(); // Write base fields - if !self.response.is_empty() { - result.insert( - "response".to_string(), - serde_json::Value::String(self.response.clone()), - ); + if !self.response.is_null() { + result.insert("response".to_string(), self.response.clone()); } if !self.messages.is_empty() { - result.insert( - "messages".to_string(), - Self::save_messages(&self.messages, ctx), - ); + result.insert("messages".to_string(), Self::save_messages(&self.messages, ctx)); } ctx.process_dict(serde_json::Value::Object(result)) } @@ -92,22 +73,19 @@ impl DoneEventPayload { /// Handles both array format `[{...}]`. fn load_messages(data: &serde_json::Value, ctx: &LoadContext) -> Vec { match data { - serde_json::Value::Array(arr) => arr - .iter() - .map(|v| Message::load_from_value(v, ctx)) - .collect(), + serde_json::Value::Array(arr) => { + arr.iter().map(|v| Message::load_from_value(v, ctx)).collect() + } _ => Vec::new(), + } } /// Save a collection of Message to a JSON value. fn save_messages(items: &[Message], ctx: &SaveContext) -> serde_json::Value { - serde_json::Value::Array( - items - .iter() - .map(|item| item.to_value(ctx)) - .collect::>(), - ) + + serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()) + } } diff --git a/runtime/rust/prompty/src/model/events/error_event_payload.rs b/runtime/rust/prompty/src/model/events/error_event_payload.rs index d3f1a9e2..d71bea3d 100644 --- a/runtime/rust/prompty/src/model/events/error_event_payload.rs +++ b/runtime/rust/prompty/src/model/events/error_event_payload.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -15,6 +9,10 @@ use super::super::context::{LoadContext, SaveContext}; pub struct ErrorEventPayload { /// Human-readable error description pub message: String, + /// Stable machine-readable error category + pub error_kind: Option, + /// Operation or phase where the error occurred + pub phase: Option, } impl ErrorEventPayload { @@ -41,11 +39,9 @@ impl ErrorEventPayload { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - message: value - .get("message") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), + message: value.get("message").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + error_kind: value.get("errorKind").and_then(|v| v.as_str()).map(|s| s.to_string()), + phase: value.get("phase").and_then(|v| v.as_str()).map(|s| s.to_string()), } } @@ -56,10 +52,13 @@ impl ErrorEventPayload { let mut result = serde_json::Map::new(); // Write base fields if !self.message.is_empty() { - result.insert( - "message".to_string(), - serde_json::Value::String(self.message.clone()), - ); + result.insert("message".to_string(), serde_json::Value::String(self.message.clone())); + } + if let Some(ref val) = self.error_kind { + result.insert("errorKind".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(ref val) = self.phase { + result.insert("phase".to_string(), serde_json::Value::String(val.clone())); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/events/llm_complete_payload.rs b/runtime/rust/prompty/src/model/events/llm_complete_payload.rs new file mode 100644 index 00000000..db82dd0c --- /dev/null +++ b/runtime/rust/prompty/src/model/events/llm_complete_payload.rs @@ -0,0 +1,86 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use super::super::context::{LoadContext, SaveContext}; + +use super::super::model::token_usage::TokenUsage; + +/// Payload for "llm_complete" events — an LLM request completed. +#[derive(Debug, Clone, Default)] +pub struct LlmCompletePayload { + /// Provider request identifier, when supplied by the SDK/API + pub request_id: Option, + /// Service request identifier, when supplied by the SDK/API + pub service_request_id: Option, + /// Token usage reported by the provider + pub usage: Option, + /// LLM call duration in milliseconds + pub duration_ms: Option, +} + +impl LlmCompletePayload { + /// Create a new LlmCompletePayload with default values. + pub fn new() -> Self { + Self::default() + } + + /// Load LlmCompletePayload from a JSON string. + pub fn from_json(json: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_json::from_str(json)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load LlmCompletePayload from a YAML string. + pub fn from_yaml(yaml: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_yaml::from_str(yaml)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load LlmCompletePayload from a `serde_json::Value`. + /// + /// Calls `ctx.process_input` before field extraction. + pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { + let value = ctx.process_input(value.clone()); + Self { + request_id: value.get("requestId").and_then(|v| v.as_str()).map(|s| s.to_string()), + service_request_id: value.get("serviceRequestId").and_then(|v| v.as_str()).map(|s| s.to_string()), + usage: value.get("usage").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| TokenUsage::load_from_value(v, ctx)), + duration_ms: value.get("durationMs").and_then(|v| v.as_f64()), + } + } + + /// Serialize LlmCompletePayload to a `serde_json::Value`. + /// + /// Calls `ctx.process_dict` after serialization. + pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { + let mut result = serde_json::Map::new(); + // Write base fields + if let Some(ref val) = self.request_id { + result.insert("requestId".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(ref val) = self.service_request_id { + result.insert("serviceRequestId".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(ref val) = self.usage { + let nested = val.to_value(ctx); + if !nested.is_null() { + result.insert("usage".to_string(), nested); + } + } + if let Some(val) = self.duration_ms { + result.insert("durationMs".to_string(), serde_json::Number::from_f64(val as f64).map(serde_json::Value::Number).unwrap_or(serde_json::Value::Null)); + } + ctx.process_dict(serde_json::Value::Object(result)) + } + + /// Serialize LlmCompletePayload to a JSON string. + pub fn to_json(&self, ctx: &SaveContext) -> Result { + serde_json::to_string_pretty(&self.to_value(ctx)) + } + + /// Serialize LlmCompletePayload to a YAML string. + pub fn to_yaml(&self, ctx: &SaveContext) -> Result { + serde_yaml::to_string(&self.to_value(ctx)) + } +} diff --git a/runtime/rust/prompty/src/model/events/llm_start_payload.rs b/runtime/rust/prompty/src/model/events/llm_start_payload.rs new file mode 100644 index 00000000..e3b41166 --- /dev/null +++ b/runtime/rust/prompty/src/model/events/llm_start_payload.rs @@ -0,0 +1,81 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use super::super::context::{LoadContext, SaveContext}; + +/// Payload for "llm_start" events — an LLM request is about to be sent. +#[derive(Debug, Clone, Default)] +pub struct LlmStartPayload { + /// Provider identifier used for the request + pub provider: Option, + /// Model or deployment identifier used for the request + pub model_id: Option, + /// Number of messages sent to the provider + pub message_count: Option, + /// Retry attempt number, zero for the initial attempt + pub attempt: Option, +} + +impl LlmStartPayload { + /// Create a new LlmStartPayload with default values. + pub fn new() -> Self { + Self::default() + } + + /// Load LlmStartPayload from a JSON string. + pub fn from_json(json: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_json::from_str(json)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load LlmStartPayload from a YAML string. + pub fn from_yaml(yaml: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_yaml::from_str(yaml)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load LlmStartPayload from a `serde_json::Value`. + /// + /// Calls `ctx.process_input` before field extraction. + pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { + let value = ctx.process_input(value.clone()); + Self { + provider: value.get("provider").and_then(|v| v.as_str()).map(|s| s.to_string()), + model_id: value.get("modelId").and_then(|v| v.as_str()).map(|s| s.to_string()), + message_count: value.get("messageCount").and_then(|v| v.as_i64()).map(|v| v as i32), + attempt: value.get("attempt").and_then(|v| v.as_i64()).map(|v| v as i32), + } + } + + /// Serialize LlmStartPayload to a `serde_json::Value`. + /// + /// Calls `ctx.process_dict` after serialization. + pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { + let mut result = serde_json::Map::new(); + // Write base fields + if let Some(ref val) = self.provider { + result.insert("provider".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(ref val) = self.model_id { + result.insert("modelId".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(val) = self.message_count { + result.insert("messageCount".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + } + if let Some(val) = self.attempt { + result.insert("attempt".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + } + ctx.process_dict(serde_json::Value::Object(result)) + } + + /// Serialize LlmStartPayload to a JSON string. + pub fn to_json(&self, ctx: &SaveContext) -> Result { + serde_json::to_string_pretty(&self.to_value(ctx)) + } + + /// Serialize LlmStartPayload to a YAML string. + pub fn to_yaml(&self, ctx: &SaveContext) -> Result { + serde_yaml::to_string(&self.to_value(ctx)) + } +} diff --git a/runtime/rust/prompty/src/model/events/messages_updated_payload.rs b/runtime/rust/prompty/src/model/events/messages_updated_payload.rs index a15da8c9..bbf7ad8f 100644 --- a/runtime/rust/prompty/src/model/events/messages_updated_payload.rs +++ b/runtime/rust/prompty/src/model/events/messages_updated_payload.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -17,6 +11,12 @@ use super::super::conversation::message::Message; pub struct MessagesUpdatedPayload { /// The current full message list after the update pub messages: Vec, + /// Why the message list changed + pub reason: Option, + /// Messages appended by this update, when available + pub appended: Vec, + /// Number of messages removed by this update, when available + pub removed: Option, } impl MessagesUpdatedPayload { @@ -43,10 +43,10 @@ impl MessagesUpdatedPayload { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - messages: value - .get("messages") - .map(|v| Self::load_messages(v, ctx)) - .unwrap_or_default(), + messages: value.get("messages").map(|v| Self::load_messages(v, ctx)).unwrap_or_default(), + reason: value.get("reason").and_then(|v| v.as_str()).map(|s| s.to_string()), + appended: value.get("appended").map(|v| Self::load_appended(v, ctx)).unwrap_or_default(), + removed: value.get("removed").and_then(|v| v.as_i64()).map(|v| v as i32), } } @@ -57,10 +57,16 @@ impl MessagesUpdatedPayload { let mut result = serde_json::Map::new(); // Write base fields if !self.messages.is_empty() { - result.insert( - "messages".to_string(), - Self::save_messages(&self.messages, ctx), - ); + result.insert("messages".to_string(), Self::save_messages(&self.messages, ctx)); + } + if let Some(ref val) = self.reason { + result.insert("reason".to_string(), serde_json::Value::String(val.clone())); + } + if !self.appended.is_empty() { + result.insert("appended".to_string(), Self::save_appended(&self.appended, ctx)); + } + if let Some(val) = self.removed { + result.insert("removed".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); } ctx.process_dict(serde_json::Value::Object(result)) } @@ -79,22 +85,39 @@ impl MessagesUpdatedPayload { /// Handles both array format `[{...}]`. fn load_messages(data: &serde_json::Value, ctx: &LoadContext) -> Vec { match data { - serde_json::Value::Array(arr) => arr - .iter() - .map(|v| Message::load_from_value(v, ctx)) - .collect(), + serde_json::Value::Array(arr) => { + arr.iter().map(|v| Message::load_from_value(v, ctx)).collect() + } _ => Vec::new(), + } } /// Save a collection of Message to a JSON value. fn save_messages(items: &[Message], ctx: &SaveContext) -> serde_json::Value { - serde_json::Value::Array( - items - .iter() - .map(|item| item.to_value(ctx)) - .collect::>(), - ) + + serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()) + + } + + /// Load a collection of Message from a JSON value. + /// Handles both array format `[{...}]`. + fn load_appended(data: &serde_json::Value, ctx: &LoadContext) -> Vec { + match data { + serde_json::Value::Array(arr) => { + arr.iter().map(|v| Message::load_from_value(v, ctx)).collect() + } + + _ => Vec::new(), + + } + } + + /// Save a collection of Message to a JSON value. + fn save_appended(items: &[Message], ctx: &SaveContext) -> serde_json::Value { + + serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()) + } } diff --git a/runtime/rust/prompty/src/model/events/mod.rs b/runtime/rust/prompty/src/model/events/mod.rs index 6019c3cd..3c0cba60 100644 --- a/runtime/rust/prompty/src/model/events/mod.rs +++ b/runtime/rust/prompty/src/model/events/mod.rs @@ -1,12 +1,30 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +pub mod turn_event; +pub use turn_event::*; + +pub mod turn_start_payload; +pub use turn_start_payload::*; + +pub mod turn_end_payload; +pub use turn_end_payload::*; + +pub mod llm_start_payload; +pub use llm_start_payload::*; + +pub mod llm_complete_payload; +pub use llm_complete_payload::*; + +pub mod retry_payload; +pub use retry_payload::*; + +pub mod permission_requested_payload; +pub use permission_requested_payload::*; + +pub mod permission_completed_payload; +pub use permission_completed_payload::*; pub mod token_event_payload; pub use token_event_payload::*; @@ -17,6 +35,9 @@ pub use thinking_event_payload::*; pub mod tool_call_start_payload; pub use tool_call_start_payload::*; +pub mod tool_call_complete_payload; +pub use tool_call_complete_payload::*; + pub mod tool_result_payload; pub use tool_result_payload::*; @@ -32,11 +53,20 @@ pub use done_event_payload::*; pub mod error_event_payload; pub use error_event_payload::*; +pub mod compaction_start_payload; +pub use compaction_start_payload::*; + pub mod compaction_complete_payload; pub use compaction_complete_payload::*; pub mod compaction_failed_payload; pub use compaction_failed_payload::*; +pub mod turn_summary; +pub use turn_summary::*; + +pub mod turn_trace; +pub use turn_trace::*; + pub mod stream_chunk; pub use stream_chunk::*; diff --git a/runtime/rust/prompty/src/model/events/permission_completed_payload.rs b/runtime/rust/prompty/src/model/events/permission_completed_payload.rs new file mode 100644 index 00000000..f704814e --- /dev/null +++ b/runtime/rust/prompty/src/model/events/permission_completed_payload.rs @@ -0,0 +1,73 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use super::super::context::{LoadContext, SaveContext}; + +/// Payload for permission completion events — an approval decision was made. +#[derive(Debug, Clone, Default)] +pub struct PermissionCompletedPayload { + /// Permission/action name that was decided + pub permission: String, + /// Whether the requested permission was approved + pub approved: bool, + /// Decision reason, if available + pub reason: Option, +} + +impl PermissionCompletedPayload { + /// Create a new PermissionCompletedPayload with default values. + pub fn new() -> Self { + Self::default() + } + + /// Load PermissionCompletedPayload from a JSON string. + pub fn from_json(json: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_json::from_str(json)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load PermissionCompletedPayload from a YAML string. + pub fn from_yaml(yaml: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_yaml::from_str(yaml)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load PermissionCompletedPayload from a `serde_json::Value`. + /// + /// Calls `ctx.process_input` before field extraction. + pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { + let value = ctx.process_input(value.clone()); + Self { + permission: value.get("permission").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + approved: value.get("approved").and_then(|v| v.as_bool()).unwrap_or(false), + reason: value.get("reason").and_then(|v| v.as_str()).map(|s| s.to_string()), + } + } + + /// Serialize PermissionCompletedPayload to a `serde_json::Value`. + /// + /// Calls `ctx.process_dict` after serialization. + pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { + let mut result = serde_json::Map::new(); + // Write base fields + if !self.permission.is_empty() { + result.insert("permission".to_string(), serde_json::Value::String(self.permission.clone())); + } + result.insert("approved".to_string(), serde_json::Value::Bool(self.approved)); + if let Some(ref val) = self.reason { + result.insert("reason".to_string(), serde_json::Value::String(val.clone())); + } + ctx.process_dict(serde_json::Value::Object(result)) + } + + /// Serialize PermissionCompletedPayload to a JSON string. + pub fn to_json(&self, ctx: &SaveContext) -> Result { + serde_json::to_string_pretty(&self.to_value(ctx)) + } + + /// Serialize PermissionCompletedPayload to a YAML string. + pub fn to_yaml(&self, ctx: &SaveContext) -> Result { + serde_yaml::to_string(&self.to_value(ctx)) + } +} diff --git a/runtime/rust/prompty/src/model/events/permission_requested_payload.rs b/runtime/rust/prompty/src/model/events/permission_requested_payload.rs new file mode 100644 index 00000000..f370f2b3 --- /dev/null +++ b/runtime/rust/prompty/src/model/events/permission_requested_payload.rs @@ -0,0 +1,81 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use super::super::context::{LoadContext, SaveContext}; + +/// Payload for permission request events — a host is asked to approve an action. +#[derive(Debug, Clone, Default)] +pub struct PermissionRequestedPayload { + /// Permission/action name being requested + pub permission: String, + /// Resource or tool the permission applies to + pub target: Option, + /// Additional host-specific permission details + pub details: serde_json::Value, +} + +impl PermissionRequestedPayload { + /// Create a new PermissionRequestedPayload with default values. + pub fn new() -> Self { + Self::default() + } + + /// Load PermissionRequestedPayload from a JSON string. + pub fn from_json(json: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_json::from_str(json)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load PermissionRequestedPayload from a YAML string. + pub fn from_yaml(yaml: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_yaml::from_str(yaml)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load PermissionRequestedPayload from a `serde_json::Value`. + /// + /// Calls `ctx.process_input` before field extraction. + pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { + let value = ctx.process_input(value.clone()); + Self { + permission: value.get("permission").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + target: value.get("target").and_then(|v| v.as_str()).map(|s| s.to_string()), + details: value.get("details").cloned().unwrap_or(serde_json::Value::Null), + } + } + + /// Serialize PermissionRequestedPayload to a `serde_json::Value`. + /// + /// Calls `ctx.process_dict` after serialization. + pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { + let mut result = serde_json::Map::new(); + // Write base fields + if !self.permission.is_empty() { + result.insert("permission".to_string(), serde_json::Value::String(self.permission.clone())); + } + if let Some(ref val) = self.target { + result.insert("target".to_string(), serde_json::Value::String(val.clone())); + } + if !self.details.is_null() { + result.insert("details".to_string(), self.details.clone()); + } + ctx.process_dict(serde_json::Value::Object(result)) + } + + /// Serialize PermissionRequestedPayload to a JSON string. + pub fn to_json(&self, ctx: &SaveContext) -> Result { + serde_json::to_string_pretty(&self.to_value(ctx)) + } + + /// Serialize PermissionRequestedPayload to a YAML string. + pub fn to_yaml(&self, ctx: &SaveContext) -> Result { + serde_yaml::to_string(&self.to_value(ctx)) + } + /// Returns typed reference to the map if the field is an object. + /// Returns `None` if the field is null or not an object. + pub fn as_details_dict(&self) -> Option<&serde_json::Map> { + self.details.as_object() + } + +} diff --git a/runtime/rust/prompty/src/model/events/retry_payload.rs b/runtime/rust/prompty/src/model/events/retry_payload.rs new file mode 100644 index 00000000..2e5b718a --- /dev/null +++ b/runtime/rust/prompty/src/model/events/retry_payload.rs @@ -0,0 +1,87 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use super::super::context::{LoadContext, SaveContext}; + +/// Payload for "retry" events — a transient operation will be retried. +#[derive(Debug, Clone, Default)] +pub struct RetryPayload { + /// Operation being retried + pub operation: String, + /// Attempt number about to run + pub attempt: i32, + /// Maximum configured attempts + pub max_attempts: Option, + /// Backoff delay before the next attempt in milliseconds + pub delay_ms: Option, + /// Reason for the retry + pub reason: Option, +} + +impl RetryPayload { + /// Create a new RetryPayload with default values. + pub fn new() -> Self { + Self::default() + } + + /// Load RetryPayload from a JSON string. + pub fn from_json(json: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_json::from_str(json)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load RetryPayload from a YAML string. + pub fn from_yaml(yaml: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_yaml::from_str(yaml)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load RetryPayload from a `serde_json::Value`. + /// + /// Calls `ctx.process_input` before field extraction. + pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { + let value = ctx.process_input(value.clone()); + Self { + operation: value.get("operation").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + attempt: value.get("attempt").and_then(|v| v.as_i64()).unwrap_or(0) as i32, + max_attempts: value.get("maxAttempts").and_then(|v| v.as_i64()).map(|v| v as i32), + delay_ms: value.get("delayMs").and_then(|v| v.as_f64()), + reason: value.get("reason").and_then(|v| v.as_str()).map(|s| s.to_string()), + } + } + + /// Serialize RetryPayload to a `serde_json::Value`. + /// + /// Calls `ctx.process_dict` after serialization. + pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { + let mut result = serde_json::Map::new(); + // Write base fields + if !self.operation.is_empty() { + result.insert("operation".to_string(), serde_json::Value::String(self.operation.clone())); + } + if self.attempt != 0 { + result.insert("attempt".to_string(), serde_json::Value::Number(serde_json::Number::from(self.attempt))); + } + if let Some(val) = self.max_attempts { + result.insert("maxAttempts".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + } + if let Some(val) = self.delay_ms { + result.insert("delayMs".to_string(), serde_json::Number::from_f64(val as f64).map(serde_json::Value::Number).unwrap_or(serde_json::Value::Null)); + } + if let Some(ref val) = self.reason { + result.insert("reason".to_string(), serde_json::Value::String(val.clone())); + } + ctx.process_dict(serde_json::Value::Object(result)) + } + + /// Serialize RetryPayload to a JSON string. + pub fn to_json(&self, ctx: &SaveContext) -> Result { + serde_json::to_string_pretty(&self.to_value(ctx)) + } + + /// Serialize RetryPayload to a YAML string. + pub fn to_yaml(&self, ctx: &SaveContext) -> Result { + serde_yaml::to_string(&self.to_value(ctx)) + } +} diff --git a/runtime/rust/prompty/src/model/events/status_event_payload.rs b/runtime/rust/prompty/src/model/events/status_event_payload.rs index f99d90f6..e2150318 100644 --- a/runtime/rust/prompty/src/model/events/status_event_payload.rs +++ b/runtime/rust/prompty/src/model/events/status_event_payload.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -41,11 +35,7 @@ impl StatusEventPayload { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - message: value - .get("message") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), + message: value.get("message").and_then(|v| v.as_str()).unwrap_or_default().to_string(), } } @@ -56,10 +46,7 @@ impl StatusEventPayload { let mut result = serde_json::Map::new(); // Write base fields if !self.message.is_empty() { - result.insert( - "message".to_string(), - serde_json::Value::String(self.message.clone()), - ); + result.insert("message".to_string(), serde_json::Value::String(self.message.clone())); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/events/stream_chunk.rs b/runtime/rust/prompty/src/model/events/stream_chunk.rs index 0a561319..f76b4eb4 100644 --- a/runtime/rust/prompty/src/model/events/stream_chunk.rs +++ b/runtime/rust/prompty/src/model/events/stream_chunk.rs @@ -1,17 +1,12 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; use super::super::conversation::tool_call::ToolCall; + /// Variant-specific data for [`StreamChunk`], discriminated by `kind`. #[derive(Debug, Clone)] pub enum StreamChunkKind { @@ -77,36 +72,22 @@ impl StreamChunk { let kind_str = value.get("kind").and_then(|v| v.as_str()).unwrap_or(""); let kind = match kind_str { "text" => StreamChunkKind::TextChunk { - value: value - .get("value") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), + value: value.get("value").and_then(|v| v.as_str()).unwrap_or_default().to_string(), }, "thinking" => StreamChunkKind::ThinkingChunk { - value: value - .get("value") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), + value: value.get("value").and_then(|v| v.as_str()).unwrap_or_default().to_string(), }, "tool" => StreamChunkKind::ToolChunk { - tool_call: value - .get("toolCall") - .filter(|v| v.is_object() || v.is_array() || v.is_string()) - .map(|v| ToolCall::load_from_value(v, ctx)) - .unwrap_or_default(), + tool_call: value.get("toolCall").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| ToolCall::load_from_value(v, ctx)).unwrap_or_default(), }, "error" => StreamChunkKind::ErrorChunk { - message: value - .get("message") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), + message: value.get("message").and_then(|v| v.as_str()).unwrap_or_default().to_string(), }, _ => StreamChunkKind::default(), }; - Self { kind: kind } + Self { + kind: kind, + } } /// Returns the `kind` discriminator string for this instance. @@ -125,41 +106,31 @@ impl StreamChunk { pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { let mut result = serde_json::Map::new(); // Write the discriminator - result.insert( - "kind".to_string(), - serde_json::Value::String(self.kind_str().to_string()), - ); + result.insert("kind".to_string(), serde_json::Value::String(self.kind_str().to_string())); // Write base fields // Write variant-specific fields match &self.kind { - StreamChunkKind::TextChunk { value, .. } => { + StreamChunkKind::TextChunk { value, .. } => { if !value.is_empty() { - result.insert( - "value".to_string(), - serde_json::Value::String(value.clone()), - ); + result.insert("value".to_string(), serde_json::Value::String(value.clone())); } } - StreamChunkKind::ThinkingChunk { value, .. } => { + StreamChunkKind::ThinkingChunk { value, .. } => { if !value.is_empty() { - result.insert( - "value".to_string(), - serde_json::Value::String(value.clone()), - ); + result.insert("value".to_string(), serde_json::Value::String(value.clone())); } } - StreamChunkKind::ToolChunk { tool_call, .. } => { - let nested = tool_call.to_value(ctx); - if !nested.is_null() { - result.insert("toolCall".to_string(), nested); + StreamChunkKind::ToolChunk { tool_call, .. } => { + { + let nested = tool_call.to_value(ctx); + if !nested.is_null() { + result.insert("toolCall".to_string(), nested); + } } } - StreamChunkKind::ErrorChunk { message, .. } => { + StreamChunkKind::ErrorChunk { message, .. } => { if !message.is_empty() { - result.insert( - "message".to_string(), - serde_json::Value::String(message.clone()), - ); + result.insert("message".to_string(), serde_json::Value::String(message.clone())); } } } diff --git a/runtime/rust/prompty/src/model/events/thinking_event_payload.rs b/runtime/rust/prompty/src/model/events/thinking_event_payload.rs index 6971f3f8..a5613146 100644 --- a/runtime/rust/prompty/src/model/events/thinking_event_payload.rs +++ b/runtime/rust/prompty/src/model/events/thinking_event_payload.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -41,11 +35,7 @@ impl ThinkingEventPayload { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - token: value - .get("token") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), + token: value.get("token").and_then(|v| v.as_str()).unwrap_or_default().to_string(), } } @@ -56,10 +46,7 @@ impl ThinkingEventPayload { let mut result = serde_json::Map::new(); // Write base fields if !self.token.is_empty() { - result.insert( - "token".to_string(), - serde_json::Value::String(self.token.clone()), - ); + result.insert("token".to_string(), serde_json::Value::String(self.token.clone())); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/events/token_event_payload.rs b/runtime/rust/prompty/src/model/events/token_event_payload.rs index 0d291aa0..fc0fc29b 100644 --- a/runtime/rust/prompty/src/model/events/token_event_payload.rs +++ b/runtime/rust/prompty/src/model/events/token_event_payload.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -41,11 +35,7 @@ impl TokenEventPayload { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - token: value - .get("token") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), + token: value.get("token").and_then(|v| v.as_str()).unwrap_or_default().to_string(), } } @@ -56,10 +46,7 @@ impl TokenEventPayload { let mut result = serde_json::Map::new(); // Write base fields if !self.token.is_empty() { - result.insert( - "token".to_string(), - serde_json::Value::String(self.token.clone()), - ); + result.insert("token".to_string(), serde_json::Value::String(self.token.clone())); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/events/tool_call_complete_payload.rs b/runtime/rust/prompty/src/model/events/tool_call_complete_payload.rs new file mode 100644 index 00000000..639ff869 --- /dev/null +++ b/runtime/rust/prompty/src/model/events/tool_call_complete_payload.rs @@ -0,0 +1,96 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use super::super::context::{LoadContext, SaveContext}; + +use super::super::conversation::tool_result::ToolResult; + +/// Payload for "tool_call_complete" events — a tool dispatch finished. +#[derive(Debug, Clone, Default)] +pub struct ToolCallCompletePayload { + /// The unique identifier of the tool call + pub id: Option, + /// The name of the tool that completed + pub name: String, + /// Whether the tool dispatch succeeded semantically + pub success: bool, + /// Normalized tool result + pub result: Option, + /// Tool execution duration in milliseconds + pub duration_ms: Option, + /// Machine-readable error category when success is false + pub error_kind: Option, +} + +impl ToolCallCompletePayload { + /// Create a new ToolCallCompletePayload with default values. + pub fn new() -> Self { + Self::default() + } + + /// Load ToolCallCompletePayload from a JSON string. + pub fn from_json(json: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_json::from_str(json)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load ToolCallCompletePayload from a YAML string. + pub fn from_yaml(yaml: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_yaml::from_str(yaml)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load ToolCallCompletePayload from a `serde_json::Value`. + /// + /// Calls `ctx.process_input` before field extraction. + pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { + let value = ctx.process_input(value.clone()); + Self { + id: value.get("id").and_then(|v| v.as_str()).map(|s| s.to_string()), + name: value.get("name").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + success: value.get("success").and_then(|v| v.as_bool()).unwrap_or(false), + result: value.get("result").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| ToolResult::load_from_value(v, ctx)), + duration_ms: value.get("durationMs").and_then(|v| v.as_f64()), + error_kind: value.get("errorKind").and_then(|v| v.as_str()).map(|s| s.to_string()), + } + } + + /// Serialize ToolCallCompletePayload to a `serde_json::Value`. + /// + /// Calls `ctx.process_dict` after serialization. + pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { + let mut result = serde_json::Map::new(); + // Write base fields + if let Some(ref val) = self.id { + result.insert("id".to_string(), serde_json::Value::String(val.clone())); + } + if !self.name.is_empty() { + result.insert("name".to_string(), serde_json::Value::String(self.name.clone())); + } + result.insert("success".to_string(), serde_json::Value::Bool(self.success)); + if let Some(ref val) = self.result { + let nested = val.to_value(ctx); + if !nested.is_null() { + result.insert("result".to_string(), nested); + } + } + if let Some(val) = self.duration_ms { + result.insert("durationMs".to_string(), serde_json::Number::from_f64(val as f64).map(serde_json::Value::Number).unwrap_or(serde_json::Value::Null)); + } + if let Some(ref val) = self.error_kind { + result.insert("errorKind".to_string(), serde_json::Value::String(val.clone())); + } + ctx.process_dict(serde_json::Value::Object(result)) + } + + /// Serialize ToolCallCompletePayload to a JSON string. + pub fn to_json(&self, ctx: &SaveContext) -> Result { + serde_json::to_string_pretty(&self.to_value(ctx)) + } + + /// Serialize ToolCallCompletePayload to a YAML string. + pub fn to_yaml(&self, ctx: &SaveContext) -> Result { + serde_yaml::to_string(&self.to_value(ctx)) + } +} diff --git a/runtime/rust/prompty/src/model/events/tool_call_start_payload.rs b/runtime/rust/prompty/src/model/events/tool_call_start_payload.rs index ffbbc8e2..0582fb2c 100644 --- a/runtime/rust/prompty/src/model/events/tool_call_start_payload.rs +++ b/runtime/rust/prompty/src/model/events/tool_call_start_payload.rs @@ -1,18 +1,14 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; /// Payload for "tool_call_start" events — the LLM has requested a tool call. #[derive(Debug, Clone, Default)] pub struct ToolCallStartPayload { + /// The unique identifier of the tool call + pub id: Option, /// The name of the tool being called pub name: String, /// The serialized JSON arguments for the tool call @@ -43,16 +39,9 @@ impl ToolCallStartPayload { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - name: value - .get("name") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - arguments: value - .get("arguments") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), + id: value.get("id").and_then(|v| v.as_str()).map(|s| s.to_string()), + name: value.get("name").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + arguments: value.get("arguments").and_then(|v| v.as_str()).unwrap_or_default().to_string(), } } @@ -62,17 +51,14 @@ impl ToolCallStartPayload { pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { let mut result = serde_json::Map::new(); // Write base fields + if let Some(ref val) = self.id { + result.insert("id".to_string(), serde_json::Value::String(val.clone())); + } if !self.name.is_empty() { - result.insert( - "name".to_string(), - serde_json::Value::String(self.name.clone()), - ); + result.insert("name".to_string(), serde_json::Value::String(self.name.clone())); } if !self.arguments.is_empty() { - result.insert( - "arguments".to_string(), - serde_json::Value::String(self.arguments.clone()), - ); + result.insert("arguments".to_string(), serde_json::Value::String(self.arguments.clone())); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/events/tool_result_payload.rs b/runtime/rust/prompty/src/model/events/tool_result_payload.rs index fc29f0b1..b91fd1bb 100644 --- a/runtime/rust/prompty/src/model/events/tool_result_payload.rs +++ b/runtime/rust/prompty/src/model/events/tool_result_payload.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -45,16 +39,8 @@ impl ToolResultPayload { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - name: value - .get("name") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - result: value - .get("result") - .filter(|v| v.is_object() || v.is_array() || v.is_string()) - .map(|v| ToolResult::load_from_value(v, ctx)) - .unwrap_or_default(), + name: value.get("name").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + result: value.get("result").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| ToolResult::load_from_value(v, ctx)).unwrap_or_default(), } } @@ -65,10 +51,7 @@ impl ToolResultPayload { let mut result = serde_json::Map::new(); // Write base fields if !self.name.is_empty() { - result.insert( - "name".to_string(), - serde_json::Value::String(self.name.clone()), - ); + result.insert("name".to_string(), serde_json::Value::String(self.name.clone())); } { let nested = self.result.to_value(ctx); diff --git a/runtime/rust/prompty/src/model/events/turn_end_payload.rs b/runtime/rust/prompty/src/model/events/turn_end_payload.rs new file mode 100644 index 00000000..1bd23791 --- /dev/null +++ b/runtime/rust/prompty/src/model/events/turn_end_payload.rs @@ -0,0 +1,123 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use super::super::context::{LoadContext, SaveContext}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum TurnStatus { + Success, + Error, + Cancelled, +} + +impl Default for TurnStatus { + fn default() -> Self { + Self::Success + } +} + +impl std::fmt::Display for TurnStatus { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Success => write!(f, "success"), + Self::Error => write!(f, "error"), + Self::Cancelled => write!(f, "cancelled"), + } + } +} + +impl TurnStatus { + pub fn from_str_opt(s: &str) -> Option { + match s { + "success" => Some(Self::Success), + "error" => Some(Self::Error), + "cancelled" => Some(Self::Cancelled), + _ => None, + } + } + + pub fn as_str(&self) -> &str { + match self { + Self::Success => "success", + Self::Error => "error", + Self::Cancelled => "cancelled", + } + } +} + +/// Payload for "turn_end" events — a turn has completed. +#[derive(Debug, Clone, Default)] +pub struct TurnEndPayload { + /// Number of tool-call iterations performed + pub iterations: Option, + /// Final semantic status of the turn + pub status: Option, + /// Final response after processing, if available + pub response: Option, + /// Total elapsed turn duration in milliseconds + pub duration_ms: Option, +} + +impl TurnEndPayload { + /// Create a new TurnEndPayload with default values. + pub fn new() -> Self { + Self::default() + } + + /// Load TurnEndPayload from a JSON string. + pub fn from_json(json: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_json::from_str(json)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load TurnEndPayload from a YAML string. + pub fn from_yaml(yaml: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_yaml::from_str(yaml)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load TurnEndPayload from a `serde_json::Value`. + /// + /// Calls `ctx.process_input` before field extraction. + pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { + let value = ctx.process_input(value.clone()); + Self { + iterations: value.get("iterations").and_then(|v| v.as_i64()).map(|v| v as i32), + status: value.get("status").and_then(|v| v.as_str()).and_then(|s| TurnStatus::from_str_opt(s)), + response: value.get("response").cloned(), + duration_ms: value.get("durationMs").and_then(|v| v.as_f64()), + } + } + + /// Serialize TurnEndPayload to a `serde_json::Value`. + /// + /// Calls `ctx.process_dict` after serialization. + pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { + let mut result = serde_json::Map::new(); + // Write base fields + if let Some(val) = self.iterations { + result.insert("iterations".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + } + if let Some(ref val) = self.status { + result.insert("status".to_string(), serde_json::Value::String(val.to_string())); + } + if let Some(ref val) = self.response { + result.insert("response".to_string(), val.clone()); + } + if let Some(val) = self.duration_ms { + result.insert("durationMs".to_string(), serde_json::Number::from_f64(val as f64).map(serde_json::Value::Number).unwrap_or(serde_json::Value::Null)); + } + ctx.process_dict(serde_json::Value::Object(result)) + } + + /// Serialize TurnEndPayload to a JSON string. + pub fn to_json(&self, ctx: &SaveContext) -> Result { + serde_json::to_string_pretty(&self.to_value(ctx)) + } + + /// Serialize TurnEndPayload to a YAML string. + pub fn to_yaml(&self, ctx: &SaveContext) -> Result { + serde_yaml::to_string(&self.to_value(ctx)) + } +} diff --git a/runtime/rust/prompty/src/model/events/turn_event.rs b/runtime/rust/prompty/src/model/events/turn_event.rs new file mode 100644 index 00000000..ae2bd627 --- /dev/null +++ b/runtime/rust/prompty/src/model/events/turn_event.rs @@ -0,0 +1,219 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use super::super::context::{LoadContext, SaveContext}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum TurnEventType { + Turn_start, + Turn_end, + Llm_start, + Llm_complete, + Retry, + Permission_requested, + Permission_completed, + Token, + Thinking, + Tool_call_start, + Tool_call_complete, + Tool_result, + Status, + Messages_updated, + Done, + Error, + Cancelled, + Compaction_start, + Compaction_complete, + Compaction_failed, +} + +impl Default for TurnEventType { + fn default() -> Self { + Self::Turn_start + } +} + +impl std::fmt::Display for TurnEventType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Turn_start => write!(f, "turn_start"), + Self::Turn_end => write!(f, "turn_end"), + Self::Llm_start => write!(f, "llm_start"), + Self::Llm_complete => write!(f, "llm_complete"), + Self::Retry => write!(f, "retry"), + Self::Permission_requested => write!(f, "permission_requested"), + Self::Permission_completed => write!(f, "permission_completed"), + Self::Token => write!(f, "token"), + Self::Thinking => write!(f, "thinking"), + Self::Tool_call_start => write!(f, "tool_call_start"), + Self::Tool_call_complete => write!(f, "tool_call_complete"), + Self::Tool_result => write!(f, "tool_result"), + Self::Status => write!(f, "status"), + Self::Messages_updated => write!(f, "messages_updated"), + Self::Done => write!(f, "done"), + Self::Error => write!(f, "error"), + Self::Cancelled => write!(f, "cancelled"), + Self::Compaction_start => write!(f, "compaction_start"), + Self::Compaction_complete => write!(f, "compaction_complete"), + Self::Compaction_failed => write!(f, "compaction_failed"), + } + } +} + +impl TurnEventType { + pub fn from_str_opt(s: &str) -> Option { + match s { + "turn_start" => Some(Self::Turn_start), + "turn_end" => Some(Self::Turn_end), + "llm_start" => Some(Self::Llm_start), + "llm_complete" => Some(Self::Llm_complete), + "retry" => Some(Self::Retry), + "permission_requested" => Some(Self::Permission_requested), + "permission_completed" => Some(Self::Permission_completed), + "token" => Some(Self::Token), + "thinking" => Some(Self::Thinking), + "tool_call_start" => Some(Self::Tool_call_start), + "tool_call_complete" => Some(Self::Tool_call_complete), + "tool_result" => Some(Self::Tool_result), + "status" => Some(Self::Status), + "messages_updated" => Some(Self::Messages_updated), + "done" => Some(Self::Done), + "error" => Some(Self::Error), + "cancelled" => Some(Self::Cancelled), + "compaction_start" => Some(Self::Compaction_start), + "compaction_complete" => Some(Self::Compaction_complete), + "compaction_failed" => Some(Self::Compaction_failed), + _ => None, + } + } + + pub fn as_str(&self) -> &str { + match self { + Self::Turn_start => "turn_start", + Self::Turn_end => "turn_end", + Self::Llm_start => "llm_start", + Self::Llm_complete => "llm_complete", + Self::Retry => "retry", + Self::Permission_requested => "permission_requested", + Self::Permission_completed => "permission_completed", + Self::Token => "token", + Self::Thinking => "thinking", + Self::Tool_call_start => "tool_call_start", + Self::Tool_call_complete => "tool_call_complete", + Self::Tool_result => "tool_result", + Self::Status => "status", + Self::Messages_updated => "messages_updated", + Self::Done => "done", + Self::Error => "error", + Self::Cancelled => "cancelled", + Self::Compaction_start => "compaction_start", + Self::Compaction_complete => "compaction_complete", + Self::Compaction_failed => "compaction_failed", + } + } +} + +/// A canonical event envelope emitted by the turn harness. The payload is kept JSON-shaped so runtimes can load all events even when newer payload types are added; event-specific typed payload models below define the canonical shapes. +#[derive(Debug, Clone, Default)] +pub struct TurnEvent { + /// Unique identifier for this event + pub id: String, + /// Event type discriminator + pub r#type: TurnEventType, + /// ISO 8601 UTC timestamp when the event was emitted + pub timestamp: String, + /// Stable identifier for the outer turn + pub turn_id: Option, + /// Zero-based agent-loop iteration associated with the event + pub iteration: Option, + /// Parent event or span identifier for reconstructing event hierarchy + pub parent_id: Option, + /// Trace span identifier associated with this event + pub span_id: Option, + /// Event-specific payload. Use the typed payload model matching 'type'. + pub payload: serde_json::Value, +} + +impl TurnEvent { + /// Create a new TurnEvent with default values. + pub fn new() -> Self { + Self::default() + } + + /// Load TurnEvent from a JSON string. + pub fn from_json(json: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_json::from_str(json)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load TurnEvent from a YAML string. + pub fn from_yaml(yaml: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_yaml::from_str(yaml)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load TurnEvent from a `serde_json::Value`. + /// + /// Calls `ctx.process_input` before field extraction. + pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { + let value = ctx.process_input(value.clone()); + Self { + id: value.get("id").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + r#type: value.get("type").and_then(|v| v.as_str()).and_then(|s| TurnEventType::from_str_opt(s)).unwrap_or(TurnEventType::Turn_start), + timestamp: value.get("timestamp").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + turn_id: value.get("turnId").and_then(|v| v.as_str()).map(|s| s.to_string()), + iteration: value.get("iteration").and_then(|v| v.as_i64()).map(|v| v as i32), + parent_id: value.get("parentId").and_then(|v| v.as_str()).map(|s| s.to_string()), + span_id: value.get("spanId").and_then(|v| v.as_str()).map(|s| s.to_string()), + payload: value.get("payload").cloned().unwrap_or(serde_json::Value::Null), + } + } + + /// Serialize TurnEvent to a `serde_json::Value`. + /// + /// Calls `ctx.process_dict` after serialization. + pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { + let mut result = serde_json::Map::new(); + // Write base fields + if !self.id.is_empty() { + result.insert("id".to_string(), serde_json::Value::String(self.id.clone())); + } + result.insert("type".to_string(), serde_json::Value::String(self.r#type.to_string())); + if !self.timestamp.is_empty() { + result.insert("timestamp".to_string(), serde_json::Value::String(self.timestamp.clone())); + } + if let Some(ref val) = self.turn_id { + result.insert("turnId".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(val) = self.iteration { + result.insert("iteration".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + } + if let Some(ref val) = self.parent_id { + result.insert("parentId".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(ref val) = self.span_id { + result.insert("spanId".to_string(), serde_json::Value::String(val.clone())); + } + if !self.payload.is_null() { + result.insert("payload".to_string(), self.payload.clone()); + } + ctx.process_dict(serde_json::Value::Object(result)) + } + + /// Serialize TurnEvent to a JSON string. + pub fn to_json(&self, ctx: &SaveContext) -> Result { + serde_json::to_string_pretty(&self.to_value(ctx)) + } + + /// Serialize TurnEvent to a YAML string. + pub fn to_yaml(&self, ctx: &SaveContext) -> Result { + serde_yaml::to_string(&self.to_value(ctx)) + } + /// Returns typed reference to the map if the field is an object. + /// Returns `None` if the field is null or not an object. + pub fn as_payload_dict(&self) -> Option<&serde_json::Map> { + self.payload.as_object() + } + +} diff --git a/runtime/rust/prompty/src/model/events/turn_start_payload.rs b/runtime/rust/prompty/src/model/events/turn_start_payload.rs new file mode 100644 index 00000000..019bd1af --- /dev/null +++ b/runtime/rust/prompty/src/model/events/turn_start_payload.rs @@ -0,0 +1,81 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use super::super::context::{LoadContext, SaveContext}; + +/// Payload for "turn_start" events — a turn is beginning. +#[derive(Debug, Clone, Default)] +pub struct TurnStartPayload { + /// Name of the loaded prompt/agent, when available + pub agent: Option, + /// Input values supplied to the turn after host-side sanitization + pub inputs: serde_json::Value, + /// Configured maximum tool-call iterations + pub max_iterations: Option, +} + +impl TurnStartPayload { + /// Create a new TurnStartPayload with default values. + pub fn new() -> Self { + Self::default() + } + + /// Load TurnStartPayload from a JSON string. + pub fn from_json(json: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_json::from_str(json)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load TurnStartPayload from a YAML string. + pub fn from_yaml(yaml: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_yaml::from_str(yaml)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load TurnStartPayload from a `serde_json::Value`. + /// + /// Calls `ctx.process_input` before field extraction. + pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { + let value = ctx.process_input(value.clone()); + Self { + agent: value.get("agent").and_then(|v| v.as_str()).map(|s| s.to_string()), + inputs: value.get("inputs").cloned().unwrap_or(serde_json::Value::Null), + max_iterations: value.get("maxIterations").and_then(|v| v.as_i64()).map(|v| v as i32), + } + } + + /// Serialize TurnStartPayload to a `serde_json::Value`. + /// + /// Calls `ctx.process_dict` after serialization. + pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { + let mut result = serde_json::Map::new(); + // Write base fields + if let Some(ref val) = self.agent { + result.insert("agent".to_string(), serde_json::Value::String(val.clone())); + } + if !self.inputs.is_null() { + result.insert("inputs".to_string(), self.inputs.clone()); + } + if let Some(val) = self.max_iterations { + result.insert("maxIterations".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + } + ctx.process_dict(serde_json::Value::Object(result)) + } + + /// Serialize TurnStartPayload to a JSON string. + pub fn to_json(&self, ctx: &SaveContext) -> Result { + serde_json::to_string_pretty(&self.to_value(ctx)) + } + + /// Serialize TurnStartPayload to a YAML string. + pub fn to_yaml(&self, ctx: &SaveContext) -> Result { + serde_yaml::to_string(&self.to_value(ctx)) + } + /// Returns typed reference to the map if the field is an object. + /// Returns `None` if the field is null or not an object. + pub fn as_inputs_dict(&self) -> Option<&serde_json::Map> { + self.inputs.as_object() + } + +} diff --git a/runtime/rust/prompty/src/model/events/turn_summary.rs b/runtime/rust/prompty/src/model/events/turn_summary.rs new file mode 100644 index 00000000..cbde60df --- /dev/null +++ b/runtime/rust/prompty/src/model/events/turn_summary.rs @@ -0,0 +1,110 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use super::super::context::{LoadContext, SaveContext}; + +use super::super::model::token_usage::TokenUsage; + +/// Summary statistics for a completed turn trace. +#[derive(Debug, Clone, Default)] +pub struct TurnSummary { + /// Stable identifier for the outer turn + pub turn_id: String, + /// Final turn status: 'success', 'error', or 'cancelled' + pub status: String, + /// Number of agent-loop iterations + pub iterations: i32, + /// Number of LLM calls made during the turn + pub llm_calls: Option, + /// Number of tool calls dispatched during the turn + pub tool_calls: Option, + /// Number of retry events during the turn + pub retries: Option, + /// Aggregated token usage for the turn + pub usage: Option, + /// Total elapsed turn duration in milliseconds + pub duration_ms: Option, +} + +impl TurnSummary { + /// Create a new TurnSummary with default values. + pub fn new() -> Self { + Self::default() + } + + /// Load TurnSummary from a JSON string. + pub fn from_json(json: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_json::from_str(json)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load TurnSummary from a YAML string. + pub fn from_yaml(yaml: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_yaml::from_str(yaml)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load TurnSummary from a `serde_json::Value`. + /// + /// Calls `ctx.process_input` before field extraction. + pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { + let value = ctx.process_input(value.clone()); + Self { + turn_id: value.get("turnId").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + status: value.get("status").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + iterations: value.get("iterations").and_then(|v| v.as_i64()).unwrap_or(0) as i32, + llm_calls: value.get("llmCalls").and_then(|v| v.as_i64()).map(|v| v as i32), + tool_calls: value.get("toolCalls").and_then(|v| v.as_i64()).map(|v| v as i32), + retries: value.get("retries").and_then(|v| v.as_i64()).map(|v| v as i32), + usage: value.get("usage").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| TokenUsage::load_from_value(v, ctx)), + duration_ms: value.get("durationMs").and_then(|v| v.as_f64()), + } + } + + /// Serialize TurnSummary to a `serde_json::Value`. + /// + /// Calls `ctx.process_dict` after serialization. + pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { + let mut result = serde_json::Map::new(); + // Write base fields + if !self.turn_id.is_empty() { + result.insert("turnId".to_string(), serde_json::Value::String(self.turn_id.clone())); + } + if !self.status.is_empty() { + result.insert("status".to_string(), serde_json::Value::String(self.status.clone())); + } + if self.iterations != 0 { + result.insert("iterations".to_string(), serde_json::Value::Number(serde_json::Number::from(self.iterations))); + } + if let Some(val) = self.llm_calls { + result.insert("llmCalls".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + } + if let Some(val) = self.tool_calls { + result.insert("toolCalls".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + } + if let Some(val) = self.retries { + result.insert("retries".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + } + if let Some(ref val) = self.usage { + let nested = val.to_value(ctx); + if !nested.is_null() { + result.insert("usage".to_string(), nested); + } + } + if let Some(val) = self.duration_ms { + result.insert("durationMs".to_string(), serde_json::Number::from_f64(val as f64).map(serde_json::Value::Number).unwrap_or(serde_json::Value::Null)); + } + ctx.process_dict(serde_json::Value::Object(result)) + } + + /// Serialize TurnSummary to a JSON string. + pub fn to_json(&self, ctx: &SaveContext) -> Result { + serde_json::to_string_pretty(&self.to_value(ctx)) + } + + /// Serialize TurnSummary to a YAML string. + pub fn to_yaml(&self, ctx: &SaveContext) -> Result { + serde_yaml::to_string(&self.to_value(ctx)) + } +} diff --git a/runtime/rust/prompty/src/model/events/turn_trace.rs b/runtime/rust/prompty/src/model/events/turn_trace.rs new file mode 100644 index 00000000..7e4cfdff --- /dev/null +++ b/runtime/rust/prompty/src/model/events/turn_trace.rs @@ -0,0 +1,114 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use super::super::context::{LoadContext, SaveContext}; + +use super::turn_event::TurnEvent; + +use super::turn_summary::TurnSummary; + +/// Portable JSONL/replay container for a recorded turn harness run. +#[derive(Debug, Clone, Default)] +pub struct TurnTrace { + /// Trace schema version + pub version: String, + /// Runtime name that produced the trace + pub runtime: Option, + /// Prompty library version that produced the trace + pub prompty_version: Option, + /// Recorded turn events in emission order + pub events: Vec, + /// Optional summary computed from the event stream + pub summary: Option, +} + +impl TurnTrace { + /// Create a new TurnTrace with default values. + pub fn new() -> Self { + Self::default() + } + + /// Load TurnTrace from a JSON string. + pub fn from_json(json: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_json::from_str(json)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load TurnTrace from a YAML string. + pub fn from_yaml(yaml: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_yaml::from_str(yaml)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load TurnTrace from a `serde_json::Value`. + /// + /// Calls `ctx.process_input` before field extraction. + pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { + let value = ctx.process_input(value.clone()); + Self { + version: value.get("version").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + runtime: value.get("runtime").and_then(|v| v.as_str()).map(|s| s.to_string()), + prompty_version: value.get("promptyVersion").and_then(|v| v.as_str()).map(|s| s.to_string()), + events: value.get("events").map(|v| Self::load_events(v, ctx)).unwrap_or_default(), + summary: value.get("summary").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| TurnSummary::load_from_value(v, ctx)), + } + } + + /// Serialize TurnTrace to a `serde_json::Value`. + /// + /// Calls `ctx.process_dict` after serialization. + pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { + let mut result = serde_json::Map::new(); + // Write base fields + if !self.version.is_empty() { + result.insert("version".to_string(), serde_json::Value::String(self.version.clone())); + } + if let Some(ref val) = self.runtime { + result.insert("runtime".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(ref val) = self.prompty_version { + result.insert("promptyVersion".to_string(), serde_json::Value::String(val.clone())); + } + if !self.events.is_empty() { + result.insert("events".to_string(), Self::save_events(&self.events, ctx)); + } + if let Some(ref val) = self.summary { + let nested = val.to_value(ctx); + if !nested.is_null() { + result.insert("summary".to_string(), nested); + } + } + ctx.process_dict(serde_json::Value::Object(result)) + } + + /// Serialize TurnTrace to a JSON string. + pub fn to_json(&self, ctx: &SaveContext) -> Result { + serde_json::to_string_pretty(&self.to_value(ctx)) + } + + /// Serialize TurnTrace to a YAML string. + pub fn to_yaml(&self, ctx: &SaveContext) -> Result { + serde_yaml::to_string(&self.to_value(ctx)) + } + + /// Load a collection of TurnEvent from a JSON value. + /// Handles both array format `[{...}]`. + fn load_events(data: &serde_json::Value, ctx: &LoadContext) -> Vec { + match data { + serde_json::Value::Array(arr) => { + arr.iter().map(|v| TurnEvent::load_from_value(v, ctx)).collect() + } + + _ => Vec::new(), + + } + } + + /// Save a collection of TurnEvent to a JSON value. + fn save_events(items: &[TurnEvent], ctx: &SaveContext) -> serde_json::Value { + + serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()) + + } +} diff --git a/runtime/rust/prompty/src/model/mod.rs b/runtime/rust/prompty/src/model/mod.rs index b49cac0e..af91b666 100644 --- a/runtime/rust/prompty/src/model/mod.rs +++ b/runtime/rust/prompty/src/model/mod.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] pub mod context; pub use context::*; diff --git a/runtime/rust/prompty/src/model/model/mod.rs b/runtime/rust/prompty/src/model/model/mod.rs index 6323da0c..e0e6fe59 100644 --- a/runtime/rust/prompty/src/model/model/mod.rs +++ b/runtime/rust/prompty/src/model/model/mod.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] pub mod model_options; pub use model_options::*; diff --git a/runtime/rust/prompty/src/model/model/model.rs b/runtime/rust/prompty/src/model/model/model.rs index ea4374da..e90286f9 100644 --- a/runtime/rust/prompty/src/model/model/model.rs +++ b/runtime/rust/prompty/src/model/model/model.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -104,33 +98,14 @@ impl Model { let value = ctx.process_input(value.clone()); if let Some(s) = value.as_str() { let value = s.to_string(); - return Model { - id: value.into(), - ..Default::default() - }; + return Model { id: value.into(), ..Default::default() }; } Self { - id: value - .get("id") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - provider: value - .get("provider") - .and_then(|v| v.as_str()) - .map(|s| s.to_string()), - api_type: value - .get("apiType") - .and_then(|v| v.as_str()) - .and_then(|s| apiType::from_str_opt(s)), - connection: value - .get("connection") - .cloned() - .unwrap_or(serde_json::Value::Null), - options: value - .get("options") - .filter(|v| v.is_object() || v.is_array() || v.is_string()) - .map(|v| ModelOptions::load_from_value(v, ctx)), + id: value.get("id").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + provider: value.get("provider").and_then(|v| v.as_str()).map(|s| s.to_string()), + api_type: value.get("apiType").and_then(|v| v.as_str()).and_then(|s| apiType::from_str_opt(s)), + connection: value.get("connection").cloned().unwrap_or(serde_json::Value::Null), + options: value.get("options").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| ModelOptions::load_from_value(v, ctx)), } } @@ -144,16 +119,10 @@ impl Model { result.insert("id".to_string(), serde_json::Value::String(self.id.clone())); } if let Some(ref val) = self.provider { - result.insert( - "provider".to_string(), - serde_json::Value::String(val.clone()), - ); + result.insert("provider".to_string(), serde_json::Value::String(val.clone())); } if let Some(ref val) = self.api_type { - result.insert( - "apiType".to_string(), - serde_json::Value::String(val.to_string()), - ); + result.insert("apiType".to_string(), serde_json::Value::String(val.to_string())); } if !self.connection.is_null() { result.insert("connection".to_string(), self.connection.clone()); diff --git a/runtime/rust/prompty/src/model/model/model_info.rs b/runtime/rust/prompty/src/model/model/model_info.rs index afb597c5..291abc9a 100644 --- a/runtime/rust/prompty/src/model/model/model_info.rs +++ b/runtime/rust/prompty/src/model/model/model_info.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -53,43 +47,13 @@ impl ModelInfo { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - id: value - .get("id") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - display_name: value - .get("displayName") - .and_then(|v| v.as_str()) - .map(|s| s.to_string()), - owned_by: value - .get("ownedBy") - .and_then(|v| v.as_str()) - .map(|s| s.to_string()), - context_window: value - .get("contextWindow") - .and_then(|v| v.as_i64()) - .map(|v| v as i32), - input_modalities: value - .get("inputModalities") - .and_then(|v| v.as_array()) - .map(|arr| { - arr.iter() - .filter_map(|v| v.as_str().map(|s| s.to_string())) - .collect() - }), - output_modalities: value - .get("outputModalities") - .and_then(|v| v.as_array()) - .map(|arr| { - arr.iter() - .filter_map(|v| v.as_str().map(|s| s.to_string())) - .collect() - }), - additional_properties: value - .get("additionalProperties") - .cloned() - .unwrap_or(serde_json::Value::Null), + id: value.get("id").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + display_name: value.get("displayName").and_then(|v| v.as_str()).map(|s| s.to_string()), + owned_by: value.get("ownedBy").and_then(|v| v.as_str()).map(|s| s.to_string()), + context_window: value.get("contextWindow").and_then(|v| v.as_i64()).map(|v| v as i32), + input_modalities: value.get("inputModalities").and_then(|v| v.as_array()).map(|arr| arr.iter().filter_map(|v| v.as_str().map(|s| s.to_string())).collect()), + output_modalities: value.get("outputModalities").and_then(|v| v.as_array()).map(|arr| arr.iter().filter_map(|v| v.as_str().map(|s| s.to_string())).collect()), + additional_properties: value.get("additionalProperties").cloned().unwrap_or(serde_json::Value::Null), } } @@ -103,40 +67,22 @@ impl ModelInfo { result.insert("id".to_string(), serde_json::Value::String(self.id.clone())); } if let Some(ref val) = self.display_name { - result.insert( - "displayName".to_string(), - serde_json::Value::String(val.clone()), - ); + result.insert("displayName".to_string(), serde_json::Value::String(val.clone())); } if let Some(ref val) = self.owned_by { - result.insert( - "ownedBy".to_string(), - serde_json::Value::String(val.clone()), - ); + result.insert("ownedBy".to_string(), serde_json::Value::String(val.clone())); } if let Some(val) = self.context_window { - result.insert( - "contextWindow".to_string(), - serde_json::Value::Number(serde_json::Number::from(val)), - ); + result.insert("contextWindow".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); } if let Some(ref items) = self.input_modalities { - result.insert( - "inputModalities".to_string(), - serde_json::to_value(items).unwrap_or(serde_json::Value::Null), - ); + result.insert("inputModalities".to_string(), serde_json::to_value(items).unwrap_or(serde_json::Value::Null)); } if let Some(ref items) = self.output_modalities { - result.insert( - "outputModalities".to_string(), - serde_json::to_value(items).unwrap_or(serde_json::Value::Null), - ); + result.insert("outputModalities".to_string(), serde_json::to_value(items).unwrap_or(serde_json::Value::Null)); } if !self.additional_properties.is_null() { - result.insert( - "additionalProperties".to_string(), - self.additional_properties.clone(), - ); + result.insert("additionalProperties".to_string(), self.additional_properties.clone()); } ctx.process_dict(serde_json::Value::Object(result)) } @@ -152,9 +98,8 @@ impl ModelInfo { } /// Returns typed reference to the map if the field is an object. /// Returns `None` if the field is null or not an object. - pub fn as_additional_properties_dict( - &self, - ) -> Option<&serde_json::Map> { + pub fn as_additional_properties_dict(&self) -> Option<&serde_json::Map> { self.additional_properties.as_object() } + } diff --git a/runtime/rust/prompty/src/model/model/model_options.rs b/runtime/rust/prompty/src/model/model/model_options.rs index bc1e51fe..2ec4ca0f 100644 --- a/runtime/rust/prompty/src/model/model/model_options.rs +++ b/runtime/rust/prompty/src/model/model/model_options.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -60,40 +54,16 @@ impl ModelOptions { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - frequency_penalty: value - .get("frequencyPenalty") - .and_then(|v| v.as_f64()) - .map(|v| v as f32), - max_output_tokens: value - .get("maxOutputTokens") - .and_then(|v| v.as_i64()) - .map(|v| v as i32), - presence_penalty: value - .get("presencePenalty") - .and_then(|v| v.as_f64()) - .map(|v| v as f32), + frequency_penalty: value.get("frequencyPenalty").and_then(|v| v.as_f64()).map(|v| v as f32), + max_output_tokens: value.get("maxOutputTokens").and_then(|v| v.as_i64()).map(|v| v as i32), + presence_penalty: value.get("presencePenalty").and_then(|v| v.as_f64()).map(|v| v as f32), seed: value.get("seed").and_then(|v| v.as_i64()).map(|v| v as i32), - temperature: value - .get("temperature") - .and_then(|v| v.as_f64()) - .map(|v| v as f32), + temperature: value.get("temperature").and_then(|v| v.as_f64()).map(|v| v as f32), top_k: value.get("topK").and_then(|v| v.as_i64()).map(|v| v as i32), top_p: value.get("topP").and_then(|v| v.as_f64()).map(|v| v as f32), - stop_sequences: value - .get("stopSequences") - .and_then(|v| v.as_array()) - .map(|arr| { - arr.iter() - .filter_map(|v| v.as_str().map(|s| s.to_string())) - .collect() - }), - allow_multiple_tool_calls: value - .get("allowMultipleToolCalls") - .and_then(|v| v.as_bool()), - additional_properties: value - .get("additionalProperties") - .cloned() - .unwrap_or(serde_json::Value::Null), + stop_sequences: value.get("stopSequences").and_then(|v| v.as_array()).map(|arr| arr.iter().filter_map(|v| v.as_str().map(|s| s.to_string())).collect()), + allow_multiple_tool_calls: value.get("allowMultipleToolCalls").and_then(|v| v.as_bool()), + additional_properties: value.get("additionalProperties").cloned().unwrap_or(serde_json::Value::Null), } } @@ -104,72 +74,34 @@ impl ModelOptions { let mut result = serde_json::Map::new(); // Write base fields if let Some(val) = self.frequency_penalty { - result.insert( - "frequencyPenalty".to_string(), - serde_json::Number::from_f64(val as f64) - .map(serde_json::Value::Number) - .unwrap_or(serde_json::Value::Null), - ); + result.insert("frequencyPenalty".to_string(), serde_json::Number::from_f64(val as f64).map(serde_json::Value::Number).unwrap_or(serde_json::Value::Null)); } if let Some(val) = self.max_output_tokens { - result.insert( - "maxOutputTokens".to_string(), - serde_json::Value::Number(serde_json::Number::from(val)), - ); + result.insert("maxOutputTokens".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); } if let Some(val) = self.presence_penalty { - result.insert( - "presencePenalty".to_string(), - serde_json::Number::from_f64(val as f64) - .map(serde_json::Value::Number) - .unwrap_or(serde_json::Value::Null), - ); + result.insert("presencePenalty".to_string(), serde_json::Number::from_f64(val as f64).map(serde_json::Value::Number).unwrap_or(serde_json::Value::Null)); } if let Some(val) = self.seed { - result.insert( - "seed".to_string(), - serde_json::Value::Number(serde_json::Number::from(val)), - ); + result.insert("seed".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); } if let Some(val) = self.temperature { - result.insert( - "temperature".to_string(), - serde_json::Number::from_f64(val as f64) - .map(serde_json::Value::Number) - .unwrap_or(serde_json::Value::Null), - ); + result.insert("temperature".to_string(), serde_json::Number::from_f64(val as f64).map(serde_json::Value::Number).unwrap_or(serde_json::Value::Null)); } if let Some(val) = self.top_k { - result.insert( - "topK".to_string(), - serde_json::Value::Number(serde_json::Number::from(val)), - ); + result.insert("topK".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); } if let Some(val) = self.top_p { - result.insert( - "topP".to_string(), - serde_json::Number::from_f64(val as f64) - .map(serde_json::Value::Number) - .unwrap_or(serde_json::Value::Null), - ); + result.insert("topP".to_string(), serde_json::Number::from_f64(val as f64).map(serde_json::Value::Number).unwrap_or(serde_json::Value::Null)); } if let Some(ref items) = self.stop_sequences { - result.insert( - "stopSequences".to_string(), - serde_json::to_value(items).unwrap_or(serde_json::Value::Null), - ); + result.insert("stopSequences".to_string(), serde_json::to_value(items).unwrap_or(serde_json::Value::Null)); } if let Some(val) = self.allow_multiple_tool_calls { - result.insert( - "allowMultipleToolCalls".to_string(), - serde_json::Value::Bool(val), - ); + result.insert("allowMultipleToolCalls".to_string(), serde_json::Value::Bool(val)); } if !self.additional_properties.is_null() { - result.insert( - "additionalProperties".to_string(), - self.additional_properties.clone(), - ); + result.insert("additionalProperties".to_string(), self.additional_properties.clone()); } ctx.process_dict(serde_json::Value::Object(result)) } @@ -188,60 +120,17 @@ impl ModelOptions { pub fn to_wire(&self, provider: &str) -> serde_json::Value { let data = serde_json::to_value(self).unwrap_or_default(); let mut result = serde_json::Map::new(); - let wire_map: std::collections::HashMap<&str, std::collections::HashMap<&str, &str>> = - std::collections::HashMap::from([ - ( - "frequencyPenalty", - std::collections::HashMap::from([("openai", "frequency_penalty")]), - ), - ( - "maxOutputTokens", - std::collections::HashMap::from([ - ("openai", "max_completion_tokens"), - ("responses", "max_output_tokens"), - ("anthropic", "max_tokens"), - ]), - ), - ( - "presencePenalty", - std::collections::HashMap::from([("openai", "presence_penalty")]), - ), - ( - "seed", - std::collections::HashMap::from([("openai", "seed")]), - ), - ( - "temperature", - std::collections::HashMap::from([ - ("openai", "temperature"), - ("responses", "temperature"), - ("anthropic", "temperature"), - ]), - ), - ( - "topK", - std::collections::HashMap::from([("openai", "top_k"), ("anthropic", "top_k")]), - ), - ( - "topP", - std::collections::HashMap::from([ - ("openai", "top_p"), - ("responses", "top_p"), - ("anthropic", "top_p"), - ]), - ), - ( - "stopSequences", - std::collections::HashMap::from([ - ("openai", "stop"), - ("anthropic", "stop_sequences"), - ]), - ), - ( - "allowMultipleToolCalls", - std::collections::HashMap::from([("openai", "parallel_tool_calls")]), - ), - ]); + let wire_map: std::collections::HashMap<&str, std::collections::HashMap<&str, &str>> = std::collections::HashMap::from([ + ("frequencyPenalty", std::collections::HashMap::from([("openai", "frequency_penalty")])), + ("maxOutputTokens", std::collections::HashMap::from([("openai", "max_completion_tokens"), ("responses", "max_output_tokens"), ("anthropic", "max_tokens")])), + ("presencePenalty", std::collections::HashMap::from([("openai", "presence_penalty")])), + ("seed", std::collections::HashMap::from([("openai", "seed")])), + ("temperature", std::collections::HashMap::from([("openai", "temperature"), ("responses", "temperature"), ("anthropic", "temperature")])), + ("topK", std::collections::HashMap::from([("openai", "top_k"), ("anthropic", "top_k")])), + ("topP", std::collections::HashMap::from([("openai", "top_p"), ("responses", "top_p"), ("anthropic", "top_p")])), + ("stopSequences", std::collections::HashMap::from([("openai", "stop"), ("anthropic", "stop_sequences")])), + ("allowMultipleToolCalls", std::collections::HashMap::from([("openai", "parallel_tool_calls")])), + ]); if let serde_json::Value::Object(map) = data { for (key, value) in map { if let Some(mapping) = wire_map.get(key.as_str()) { @@ -255,9 +144,8 @@ impl ModelOptions { } /// Returns typed reference to the map if the field is an object. /// Returns `None` if the field is null or not an object. - pub fn as_additional_properties_dict( - &self, - ) -> Option<&serde_json::Map> { + pub fn as_additional_properties_dict(&self) -> Option<&serde_json::Map> { self.additional_properties.as_object() } + } diff --git a/runtime/rust/prompty/src/model/model/token_usage.rs b/runtime/rust/prompty/src/model/model/token_usage.rs index 7aa10164..986626ee 100644 --- a/runtime/rust/prompty/src/model/model/token_usage.rs +++ b/runtime/rust/prompty/src/model/model/token_usage.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -46,18 +40,9 @@ impl TokenUsage { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - prompt_tokens: value - .get("promptTokens") - .and_then(|v| v.as_i64()) - .map(|v| v as i32), - completion_tokens: value - .get("completionTokens") - .and_then(|v| v.as_i64()) - .map(|v| v as i32), - total_tokens: value - .get("totalTokens") - .and_then(|v| v.as_i64()) - .map(|v| v as i32), + prompt_tokens: value.get("promptTokens").and_then(|v| v.as_i64()).map(|v| v as i32), + completion_tokens: value.get("completionTokens").and_then(|v| v.as_i64()).map(|v| v as i32), + total_tokens: value.get("totalTokens").and_then(|v| v.as_i64()).map(|v| v as i32), } } @@ -68,22 +53,13 @@ impl TokenUsage { let mut result = serde_json::Map::new(); // Write base fields if let Some(val) = self.prompt_tokens { - result.insert( - "promptTokens".to_string(), - serde_json::Value::Number(serde_json::Number::from(val)), - ); + result.insert("promptTokens".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); } if let Some(val) = self.completion_tokens { - result.insert( - "completionTokens".to_string(), - serde_json::Value::Number(serde_json::Number::from(val)), - ); + result.insert("completionTokens".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); } if let Some(val) = self.total_tokens { - result.insert( - "totalTokens".to_string(), - serde_json::Value::Number(serde_json::Number::from(val)), - ); + result.insert("totalTokens".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); } ctx.process_dict(serde_json::Value::Object(result)) } @@ -102,27 +78,11 @@ impl TokenUsage { pub fn to_wire(&self, provider: &str) -> serde_json::Value { let data = serde_json::to_value(self).unwrap_or_default(); let mut result = serde_json::Map::new(); - let wire_map: std::collections::HashMap<&str, std::collections::HashMap<&str, &str>> = - std::collections::HashMap::from([ - ( - "promptTokens", - std::collections::HashMap::from([ - ("openai", "prompt_tokens"), - ("anthropic", "input_tokens"), - ]), - ), - ( - "completionTokens", - std::collections::HashMap::from([ - ("openai", "completion_tokens"), - ("anthropic", "output_tokens"), - ]), - ), - ( - "totalTokens", - std::collections::HashMap::from([("openai", "total_tokens")]), - ), - ]); + let wire_map: std::collections::HashMap<&str, std::collections::HashMap<&str, &str>> = std::collections::HashMap::from([ + ("promptTokens", std::collections::HashMap::from([("openai", "prompt_tokens"), ("anthropic", "input_tokens")])), + ("completionTokens", std::collections::HashMap::from([("openai", "completion_tokens"), ("anthropic", "output_tokens")])), + ("totalTokens", std::collections::HashMap::from([("openai", "total_tokens")])), + ]); if let serde_json::Value::Object(map) = data { for (key, value) in map { if let Some(mapping) = wire_map.get(key.as_str()) { diff --git a/runtime/rust/prompty/src/model/pipeline/compaction_config.rs b/runtime/rust/prompty/src/model/pipeline/compaction_config.rs index bc5b26d9..ba3b2594 100644 --- a/runtime/rust/prompty/src/model/pipeline/compaction_config.rs +++ b/runtime/rust/prompty/src/model/pipeline/compaction_config.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -45,18 +39,9 @@ impl CompactionConfig { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - strategy: value - .get("strategy") - .and_then(|v| v.as_str()) - .map(|s| s.to_string()), - budget: value - .get("budget") - .and_then(|v| v.as_i64()) - .map(|v| v as i32), - options: value - .get("options") - .cloned() - .unwrap_or(serde_json::Value::Null), + strategy: value.get("strategy").and_then(|v| v.as_str()).map(|s| s.to_string()), + budget: value.get("budget").and_then(|v| v.as_i64()).map(|v| v as i32), + options: value.get("options").cloned().unwrap_or(serde_json::Value::Null), } } @@ -67,16 +52,10 @@ impl CompactionConfig { let mut result = serde_json::Map::new(); // Write base fields if let Some(ref val) = self.strategy { - result.insert( - "strategy".to_string(), - serde_json::Value::String(val.clone()), - ); + result.insert("strategy".to_string(), serde_json::Value::String(val.clone())); } if let Some(val) = self.budget { - result.insert( - "budget".to_string(), - serde_json::Value::Number(serde_json::Number::from(val)), - ); + result.insert("budget".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); } if !self.options.is_null() { result.insert("options".to_string(), self.options.clone()); @@ -98,4 +77,5 @@ impl CompactionConfig { pub fn as_options_dict(&self) -> Option<&serde_json::Map> { self.options.as_object() } + } diff --git a/runtime/rust/prompty/src/model/pipeline/executor.rs b/runtime/rust/prompty/src/model/pipeline/executor.rs index ee18d842..e52c6999 100644 --- a/runtime/rust/prompty/src/model/pipeline/executor.rs +++ b/runtime/rust/prompty/src/model/pipeline/executor.rs @@ -1,12 +1,7 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + use super::super::conversation::message::Message; @@ -18,25 +13,11 @@ use super::super::conversation::tool_call::ToolCall; #[async_trait::async_trait] pub trait Executor: Send + Sync { /// Call an LLM provider with messages and return the raw response - async fn execute( - &self, - agent: &Prompty, - messages: &Vec, - ) -> Result>; + async fn execute(&self, agent: &Prompty, messages: &Vec) -> Result>; /// Call an LLM provider and return a streaming response. Returns a language-specific async iterable/stream of raw chunks. Not all providers support streaming; the default implementation should signal lack of support. - async fn execute_stream( - &self, - agent: &Prompty, - messages: &Vec, - ) -> Result> { + async fn execute_stream(&self, agent: &Prompty, messages: &Vec) -> Result> { Err("not supported".into()) } /// Format tool call results into messages for the next iteration - fn format_tool_messages( - &self, - raw_response: &serde_json::Value, - tool_calls: &Vec, - tool_results: &Vec, - text_content: &Option, - ) -> Vec; + fn format_tool_messages(&self, raw_response: &serde_json::Value, tool_calls: &Vec, tool_results: &Vec, text_content: &Option) -> Vec; } diff --git a/runtime/rust/prompty/src/model/pipeline/mod.rs b/runtime/rust/prompty/src/model/pipeline/mod.rs index 37040aa2..ab85d056 100644 --- a/runtime/rust/prompty/src/model/pipeline/mod.rs +++ b/runtime/rust/prompty/src/model/pipeline/mod.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] pub mod compaction_config; pub use compaction_config::*; diff --git a/runtime/rust/prompty/src/model/pipeline/parser.rs b/runtime/rust/prompty/src/model/pipeline/parser.rs index bd0a1ae4..4158dfd5 100644 --- a/runtime/rust/prompty/src/model/pipeline/parser.rs +++ b/runtime/rust/prompty/src/model/pipeline/parser.rs @@ -1,12 +1,7 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + use super::super::conversation::message::Message; @@ -20,10 +15,5 @@ pub trait Parser: Send + Sync { None } /// Parse rendered text into a structured message array - async fn parse( - &self, - agent: &Prompty, - rendered: &String, - context: &Option, - ) -> Result, Box>; + async fn parse(&self, agent: &Prompty, rendered: &String, context: &Option) -> Result, Box>; } diff --git a/runtime/rust/prompty/src/model/pipeline/processor.rs b/runtime/rust/prompty/src/model/pipeline/processor.rs index 9c844735..1dc21209 100644 --- a/runtime/rust/prompty/src/model/pipeline/processor.rs +++ b/runtime/rust/prompty/src/model/pipeline/processor.rs @@ -1,12 +1,7 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + use super::super::agent::prompty::Prompty; @@ -14,16 +9,9 @@ use super::super::agent::prompty::Prompty; #[async_trait::async_trait] pub trait Processor: Send + Sync { /// Extract a clean result from a raw LLM response - async fn process( - &self, - agent: &Prompty, - response: &serde_json::Value, - ) -> Result>; + async fn process(&self, agent: &Prompty, response: &serde_json::Value) -> Result>; /// Process a streaming response into a stream of StreamChunk items. Takes raw chunks from the executor and yields processed text, thinking, tool, or error chunks. Not all providers support streaming; the default implementation should signal lack of support. - async fn process_stream( - &self, - stream: &serde_json::Value, - ) -> Result> { + async fn process_stream(&self, stream: &serde_json::Value) -> Result> { Err("not supported".into()) } } diff --git a/runtime/rust/prompty/src/model/pipeline/renderer.rs b/runtime/rust/prompty/src/model/pipeline/renderer.rs index b25e511c..a4bfff80 100644 --- a/runtime/rust/prompty/src/model/pipeline/renderer.rs +++ b/runtime/rust/prompty/src/model/pipeline/renderer.rs @@ -1,12 +1,7 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + use super::super::agent::prompty::Prompty; @@ -14,10 +9,5 @@ use super::super::agent::prompty::Prompty; #[async_trait::async_trait] pub trait Renderer: Send + Sync { /// Render the template string with input values - async fn render( - &self, - agent: &Prompty, - template: &String, - inputs: &serde_json::Value, - ) -> Result>; + async fn render(&self, agent: &Prompty, template: &String, inputs: &serde_json::Value) -> Result>; } diff --git a/runtime/rust/prompty/src/model/pipeline/turn_options.rs b/runtime/rust/prompty/src/model/pipeline/turn_options.rs index 09929a6d..a26bbcde 100644 --- a/runtime/rust/prompty/src/model/pipeline/turn_options.rs +++ b/runtime/rust/prompty/src/model/pipeline/turn_options.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -55,25 +49,13 @@ impl TurnOptions { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - max_iterations: value - .get("maxIterations") - .and_then(|v| v.as_i64()) - .map(|v| v as i32), - max_llm_retries: value - .get("maxLlmRetries") - .and_then(|v| v.as_i64()) - .map(|v| v as i32), - context_budget: value - .get("contextBudget") - .and_then(|v| v.as_i64()) - .map(|v| v as i32), + max_iterations: value.get("maxIterations").and_then(|v| v.as_i64()).map(|v| v as i32), + max_llm_retries: value.get("maxLlmRetries").and_then(|v| v.as_i64()).map(|v| v as i32), + context_budget: value.get("contextBudget").and_then(|v| v.as_i64()).map(|v| v as i32), parallel_tool_calls: value.get("parallelToolCalls").and_then(|v| v.as_bool()), raw: value.get("raw").and_then(|v| v.as_bool()), turn: value.get("turn").and_then(|v| v.as_i64()).map(|v| v as i32), - compaction: value - .get("compaction") - .filter(|v| v.is_object() || v.is_array() || v.is_string()) - .map(|v| CompactionConfig::load_from_value(v, ctx)), + compaction: value.get("compaction").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| CompactionConfig::load_from_value(v, ctx)), } } @@ -84,37 +66,22 @@ impl TurnOptions { let mut result = serde_json::Map::new(); // Write base fields if let Some(val) = self.max_iterations { - result.insert( - "maxIterations".to_string(), - serde_json::Value::Number(serde_json::Number::from(val)), - ); + result.insert("maxIterations".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); } if let Some(val) = self.max_llm_retries { - result.insert( - "maxLlmRetries".to_string(), - serde_json::Value::Number(serde_json::Number::from(val)), - ); + result.insert("maxLlmRetries".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); } if let Some(val) = self.context_budget { - result.insert( - "contextBudget".to_string(), - serde_json::Value::Number(serde_json::Number::from(val)), - ); + result.insert("contextBudget".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); } if let Some(val) = self.parallel_tool_calls { - result.insert( - "parallelToolCalls".to_string(), - serde_json::Value::Bool(val), - ); + result.insert("parallelToolCalls".to_string(), serde_json::Value::Bool(val)); } if let Some(val) = self.raw { result.insert("raw".to_string(), serde_json::Value::Bool(val)); } if let Some(val) = self.turn { - result.insert( - "turn".to_string(), - serde_json::Value::Number(serde_json::Number::from(val)), - ); + result.insert("turn".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); } if let Some(ref val) = self.compaction { let nested = val.to_value(ctx); diff --git a/runtime/rust/prompty/src/model/streaming/mod.rs b/runtime/rust/prompty/src/model/streaming/mod.rs index b44116fe..7c6c11e4 100644 --- a/runtime/rust/prompty/src/model/streaming/mod.rs +++ b/runtime/rust/prompty/src/model/streaming/mod.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] pub mod stream_options; pub use stream_options::*; diff --git a/runtime/rust/prompty/src/model/streaming/stream_options.rs b/runtime/rust/prompty/src/model/streaming/stream_options.rs index 006443d3..35329205 100644 --- a/runtime/rust/prompty/src/model/streaming/stream_options.rs +++ b/runtime/rust/prompty/src/model/streaming/stream_options.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; diff --git a/runtime/rust/prompty/src/model/template/format_config.rs b/runtime/rust/prompty/src/model/template/format_config.rs index f22a6fd6..96674a07 100644 --- a/runtime/rust/prompty/src/model/template/format_config.rs +++ b/runtime/rust/prompty/src/model/template/format_config.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -46,22 +40,12 @@ impl FormatConfig { let value = ctx.process_input(value.clone()); if let Some(s) = value.as_str() { let value = s.to_string(); - return FormatConfig { - kind: value.into(), - ..Default::default() - }; + return FormatConfig { kind: value.into(), ..Default::default() }; } Self { - kind: value - .get("kind") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), + kind: value.get("kind").and_then(|v| v.as_str()).unwrap_or_default().to_string(), strict: value.get("strict").and_then(|v| v.as_bool()), - options: value - .get("options") - .cloned() - .unwrap_or(serde_json::Value::Null), + options: value.get("options").cloned().unwrap_or(serde_json::Value::Null), } } @@ -72,10 +56,7 @@ impl FormatConfig { let mut result = serde_json::Map::new(); // Write base fields if !self.kind.is_empty() { - result.insert( - "kind".to_string(), - serde_json::Value::String(self.kind.clone()), - ); + result.insert("kind".to_string(), serde_json::Value::String(self.kind.clone())); } if let Some(val) = self.strict { result.insert("strict".to_string(), serde_json::Value::Bool(val)); @@ -100,4 +81,5 @@ impl FormatConfig { pub fn as_options_dict(&self) -> Option<&serde_json::Map> { self.options.as_object() } + } diff --git a/runtime/rust/prompty/src/model/template/mod.rs b/runtime/rust/prompty/src/model/template/mod.rs index ee4b7e72..dd0c9598 100644 --- a/runtime/rust/prompty/src/model/template/mod.rs +++ b/runtime/rust/prompty/src/model/template/mod.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] pub mod format_config; pub use format_config::*; diff --git a/runtime/rust/prompty/src/model/template/parser_config.rs b/runtime/rust/prompty/src/model/template/parser_config.rs index 1928db3a..1fe09579 100644 --- a/runtime/rust/prompty/src/model/template/parser_config.rs +++ b/runtime/rust/prompty/src/model/template/parser_config.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -44,21 +38,11 @@ impl ParserConfig { let value = ctx.process_input(value.clone()); if let Some(s) = value.as_str() { let value = s.to_string(); - return ParserConfig { - kind: value.into(), - ..Default::default() - }; + return ParserConfig { kind: value.into(), ..Default::default() }; } Self { - kind: value - .get("kind") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - options: value - .get("options") - .cloned() - .unwrap_or(serde_json::Value::Null), + kind: value.get("kind").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + options: value.get("options").cloned().unwrap_or(serde_json::Value::Null), } } @@ -69,10 +53,7 @@ impl ParserConfig { let mut result = serde_json::Map::new(); // Write base fields if !self.kind.is_empty() { - result.insert( - "kind".to_string(), - serde_json::Value::String(self.kind.clone()), - ); + result.insert("kind".to_string(), serde_json::Value::String(self.kind.clone())); } if !self.options.is_null() { result.insert("options".to_string(), self.options.clone()); @@ -94,4 +75,5 @@ impl ParserConfig { pub fn as_options_dict(&self) -> Option<&serde_json::Map> { self.options.as_object() } + } diff --git a/runtime/rust/prompty/src/model/template/template.rs b/runtime/rust/prompty/src/model/template/template.rs index 4804bc44..13354b81 100644 --- a/runtime/rust/prompty/src/model/template/template.rs +++ b/runtime/rust/prompty/src/model/template/template.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -47,16 +41,8 @@ impl Template { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - format: value - .get("format") - .filter(|v| v.is_object() || v.is_array() || v.is_string()) - .map(|v| FormatConfig::load_from_value(v, ctx)) - .unwrap_or_default(), - parser: value - .get("parser") - .filter(|v| v.is_object() || v.is_array() || v.is_string()) - .map(|v| ParserConfig::load_from_value(v, ctx)) - .unwrap_or_default(), + format: value.get("format").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| FormatConfig::load_from_value(v, ctx)).unwrap_or_default(), + parser: value.get("parser").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| ParserConfig::load_from_value(v, ctx)).unwrap_or_default(), } } diff --git a/runtime/rust/prompty/src/model/tools/binding.rs b/runtime/rust/prompty/src/model/tools/binding.rs index 18e5e062..f526582e 100644 --- a/runtime/rust/prompty/src/model/tools/binding.rs +++ b/runtime/rust/prompty/src/model/tools/binding.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -44,22 +38,11 @@ impl Binding { let value = ctx.process_input(value.clone()); if let Some(s) = value.as_str() { let value = s.to_string(); - return Binding { - input: value.into(), - ..Default::default() - }; + return Binding { input: value.into(), ..Default::default() }; } Self { - name: value - .get("name") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - input: value - .get("input") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), + name: value.get("name").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + input: value.get("input").and_then(|v| v.as_str()).unwrap_or_default().to_string(), } } @@ -70,16 +53,10 @@ impl Binding { let mut result = serde_json::Map::new(); // Write base fields if !self.name.is_empty() { - result.insert( - "name".to_string(), - serde_json::Value::String(self.name.clone()), - ); + result.insert("name".to_string(), serde_json::Value::String(self.name.clone())); } if !self.input.is_empty() { - result.insert( - "input".to_string(), - serde_json::Value::String(self.input.clone()), - ); + result.insert("input".to_string(), serde_json::Value::String(self.input.clone())); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/tools/mcp_approval_mode.rs b/runtime/rust/prompty/src/model/tools/mcp_approval_mode.rs index ef20e5e6..9588b51a 100644 --- a/runtime/rust/prompty/src/model/tools/mcp_approval_mode.rs +++ b/runtime/rust/prompty/src/model/tools/mcp_approval_mode.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -88,34 +82,12 @@ impl McpApprovalMode { let value = ctx.process_input(value.clone()); if let Some(s) = value.as_str() { let value = s.to_string(); - return McpApprovalMode { - kind: mcpApprovalModeKind::from_str_opt(&value) - .unwrap_or(mcpApprovalModeKind::Always), - ..Default::default() - }; + return McpApprovalMode { kind: mcpApprovalModeKind::from_str_opt(&value).unwrap_or(mcpApprovalModeKind::Always), ..Default::default() }; } Self { - kind: value - .get("kind") - .and_then(|v| v.as_str()) - .and_then(|s| mcpApprovalModeKind::from_str_opt(s)) - .unwrap_or(mcpApprovalModeKind::Always), - always_require_approval_tools: value - .get("alwaysRequireApprovalTools") - .and_then(|v| v.as_array()) - .map(|arr| { - arr.iter() - .filter_map(|v| v.as_str().map(|s| s.to_string())) - .collect() - }), - never_require_approval_tools: value - .get("neverRequireApprovalTools") - .and_then(|v| v.as_array()) - .map(|arr| { - arr.iter() - .filter_map(|v| v.as_str().map(|s| s.to_string())) - .collect() - }), + kind: value.get("kind").and_then(|v| v.as_str()).and_then(|s| mcpApprovalModeKind::from_str_opt(s)).unwrap_or(mcpApprovalModeKind::Always), + always_require_approval_tools: value.get("alwaysRequireApprovalTools").and_then(|v| v.as_array()).map(|arr| arr.iter().filter_map(|v| v.as_str().map(|s| s.to_string())).collect()), + never_require_approval_tools: value.get("neverRequireApprovalTools").and_then(|v| v.as_array()).map(|arr| arr.iter().filter_map(|v| v.as_str().map(|s| s.to_string())).collect()), } } @@ -125,21 +97,12 @@ impl McpApprovalMode { pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { let mut result = serde_json::Map::new(); // Write base fields - result.insert( - "kind".to_string(), - serde_json::Value::String(self.kind.to_string()), - ); + result.insert("kind".to_string(), serde_json::Value::String(self.kind.to_string())); if let Some(ref items) = self.always_require_approval_tools { - result.insert( - "alwaysRequireApprovalTools".to_string(), - serde_json::to_value(items).unwrap_or(serde_json::Value::Null), - ); + result.insert("alwaysRequireApprovalTools".to_string(), serde_json::to_value(items).unwrap_or(serde_json::Value::Null)); } if let Some(ref items) = self.never_require_approval_tools { - result.insert( - "neverRequireApprovalTools".to_string(), - serde_json::to_value(items).unwrap_or(serde_json::Value::Null), - ); + result.insert("neverRequireApprovalTools".to_string(), serde_json::to_value(items).unwrap_or(serde_json::Value::Null)); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/tools/mod.rs b/runtime/rust/prompty/src/model/tools/mod.rs index d94aad5e..e294fa1f 100644 --- a/runtime/rust/prompty/src/model/tools/mod.rs +++ b/runtime/rust/prompty/src/model/tools/mod.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] pub mod binding; pub use binding::*; diff --git a/runtime/rust/prompty/src/model/tools/tool.rs b/runtime/rust/prompty/src/model/tools/tool.rs index 691c8f91..cfe10da8 100644 --- a/runtime/rust/prompty/src/model/tools/tool.rs +++ b/runtime/rust/prompty/src/model/tools/tool.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -18,6 +12,7 @@ use super::mcp_approval_mode::McpApprovalMode; use super::super::core::property::Property; + /// Variant-specific data for [`Tool`], discriminated by `kind`. #[derive(Debug, Clone)] pub enum ToolKind { @@ -114,89 +109,34 @@ impl Tool { let kind_str = value.get("kind").and_then(|v| v.as_str()).unwrap_or(""); let kind = match kind_str { "function" => ToolKind::Function { - parameters: value - .get("parameters") - .map(|v| Self::load_parameters(v, ctx)) - .unwrap_or_default(), + parameters: value.get("parameters").map(|v| Self::load_parameters(v, ctx)).unwrap_or_default(), strict: value.get("strict").and_then(|v| v.as_bool()), }, "mcp" => ToolKind::Mcp { - connection: value - .get("connection") - .cloned() - .unwrap_or(serde_json::Value::Null), - server_name: value - .get("serverName") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - server_description: value - .get("serverDescription") - .and_then(|v| v.as_str()) - .map(|s| s.to_string()), - approval_mode: value - .get("approvalMode") - .filter(|v| v.is_object() || v.is_array() || v.is_string()) - .map(|v| McpApprovalMode::load_from_value(v, ctx)) - .unwrap_or_default(), - allowed_tools: value - .get("allowedTools") - .and_then(|v| v.as_array()) - .map(|arr| { - arr.iter() - .filter_map(|v| v.as_str().map(|s| s.to_string())) - .collect() - }), + connection: value.get("connection").cloned().unwrap_or(serde_json::Value::Null), + server_name: value.get("serverName").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + server_description: value.get("serverDescription").and_then(|v| v.as_str()).map(|s| s.to_string()), + approval_mode: value.get("approvalMode").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| McpApprovalMode::load_from_value(v, ctx)).unwrap_or_default(), + allowed_tools: value.get("allowedTools").and_then(|v| v.as_array()).map(|arr| arr.iter().filter_map(|v| v.as_str().map(|s| s.to_string())).collect()), }, "openapi" => ToolKind::OpenApi { - connection: value - .get("connection") - .cloned() - .unwrap_or(serde_json::Value::Null), - specification: value - .get("specification") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), + connection: value.get("connection").cloned().unwrap_or(serde_json::Value::Null), + specification: value.get("specification").and_then(|v| v.as_str()).unwrap_or_default().to_string(), }, "prompty" => ToolKind::Prompty { - path: value - .get("path") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - mode: value - .get("mode") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), + path: value.get("path").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + mode: value.get("mode").and_then(|v| v.as_str()).unwrap_or_default().to_string(), }, _ => ToolKind::Custom { - connection: value - .get("connection") - .cloned() - .unwrap_or(serde_json::Value::Null), - options: value - .get("options") - .cloned() - .unwrap_or(serde_json::Value::Null), + connection: value.get("connection").cloned().unwrap_or(serde_json::Value::Null), + options: value.get("options").cloned().unwrap_or(serde_json::Value::Null), kind_name: kind_str.to_string(), }, }; Self { - name: value - .get("name") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - description: value - .get("description") - .and_then(|v| v.as_str()) - .map(|s| s.to_string()), - bindings: value - .get("bindings") - .map(|v| Self::load_bindings(v, ctx)) - .unwrap_or_default(), + name: value.get("name").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + description: value.get("description").and_then(|v| v.as_str()).map(|s| s.to_string()), + bindings: value.get("bindings").map(|v| Self::load_bindings(v, ctx)).unwrap_or_default(), kind: kind, } } @@ -218,68 +158,36 @@ impl Tool { pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { let mut result = serde_json::Map::new(); // Write the discriminator - result.insert( - "kind".to_string(), - serde_json::Value::String(self.kind_str().to_string()), - ); + result.insert("kind".to_string(), serde_json::Value::String(self.kind_str().to_string())); // Write base fields if !self.name.is_empty() { - result.insert( - "name".to_string(), - serde_json::Value::String(self.name.clone()), - ); + result.insert("name".to_string(), serde_json::Value::String(self.name.clone())); } if let Some(ref val) = self.description { - result.insert( - "description".to_string(), - serde_json::Value::String(val.clone()), - ); + result.insert("description".to_string(), serde_json::Value::String(val.clone())); } if !self.bindings.is_empty() { - result.insert( - "bindings".to_string(), - Self::save_bindings(&self.bindings, ctx), - ); + result.insert("bindings".to_string(), Self::save_bindings(&self.bindings, ctx)); } // Write variant-specific fields match &self.kind { - ToolKind::Function { - parameters, strict, .. - } => { + ToolKind::Function { parameters, strict, .. } => { if !parameters.is_empty() { - result.insert( - "parameters".to_string(), - serde_json::Value::Array( - parameters.iter().map(|item| item.to_value(ctx)).collect(), - ), - ); + result.insert("parameters".to_string(), serde_json::Value::Array(parameters.iter().map(|item| item.to_value(ctx)).collect())); } if let Some(val) = strict { result.insert("strict".to_string(), serde_json::Value::Bool(*val)); } } - ToolKind::Mcp { - connection, - server_name, - server_description, - approval_mode, - allowed_tools, - .. - } => { + ToolKind::Mcp { connection, server_name, server_description, approval_mode, allowed_tools, .. } => { if !connection.is_null() { result.insert("connection".to_string(), connection.clone()); } if !server_name.is_empty() { - result.insert( - "serverName".to_string(), - serde_json::Value::String(server_name.clone()), - ); + result.insert("serverName".to_string(), serde_json::Value::String(server_name.clone())); } if let Some(val) = server_description { - result.insert( - "serverDescription".to_string(), - serde_json::Value::String(val.clone()), - ); + result.insert("serverDescription".to_string(), serde_json::Value::String(val.clone())); } { let nested = approval_mode.to_value(ctx); @@ -288,28 +196,18 @@ impl Tool { } } if let Some(items) = allowed_tools { - result.insert( - "allowedTools".to_string(), - serde_json::to_value(items).unwrap_or(serde_json::Value::Null), - ); + result.insert("allowedTools".to_string(), serde_json::to_value(items).unwrap_or(serde_json::Value::Null)); } } - ToolKind::OpenApi { - connection, - specification, - .. - } => { + ToolKind::OpenApi { connection, specification, .. } => { if !connection.is_null() { result.insert("connection".to_string(), connection.clone()); } if !specification.is_empty() { - result.insert( - "specification".to_string(), - serde_json::Value::String(specification.clone()), - ); + result.insert("specification".to_string(), serde_json::Value::String(specification.clone())); } } - ToolKind::Prompty { path, mode, .. } => { + ToolKind::Prompty { path, mode, .. } => { if !path.is_empty() { result.insert("path".to_string(), serde_json::Value::String(path.clone())); } @@ -317,12 +215,7 @@ impl Tool { result.insert("mode".to_string(), serde_json::Value::String(mode.clone())); } } - ToolKind::Custom { - connection, - options, - kind_name: _, - .. - } => { + ToolKind::Custom { connection, options, kind_name: _, .. } => { if !connection.is_null() { result.insert("connection".to_string(), connection.clone()); } @@ -348,81 +241,71 @@ impl Tool { /// Handles both array format `[{...}]` and dict format `{"name": {...}}`. fn load_bindings(data: &serde_json::Value, ctx: &LoadContext) -> Vec { match data { - serde_json::Value::Array(arr) => arr - .iter() - .map(|v| Binding::load_from_value(v, ctx)) - .collect(), + serde_json::Value::Array(arr) => { + arr.iter().map(|v| Binding::load_from_value(v, ctx)).collect() + } - serde_json::Value::Object(obj) => obj - .iter() - .filter_map(|(name, value)| { - if value.is_array() { - return None; - } - let mut v = if value.is_object() { - value.clone() - } else { - serde_json::json!({ "input": value }) - }; - if let serde_json::Value::Object(ref mut m) = v { - m.entry("name".to_string()) - .or_insert_with(|| serde_json::Value::String(name.clone())); - } - Some(Binding::load_from_value(&v, ctx)) - }) - .collect(), + serde_json::Value::Object(obj) => { + obj.iter() + .filter_map(|(name, value)| { + if value.is_array() { + return None; + } + let mut v = if value.is_object() { + value.clone() + } else { + serde_json::json!({ "input": value }) + }; + if let serde_json::Value::Object(ref mut m) = v { + m.entry("name".to_string()).or_insert_with(|| serde_json::Value::String(name.clone())); + } + Some(Binding::load_from_value(&v, ctx)) + }) + .collect() + } _ => Vec::new(), + } } /// Save a collection of Binding to a JSON value. fn save_bindings(items: &[Binding], ctx: &SaveContext) -> serde_json::Value { + if ctx.collection_format == "array" { - return serde_json::Value::Array( - items - .iter() - .map(|item| item.to_value(ctx)) - .collect::>(), - ); + return serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()); } // Object format: use name as key let mut result = serde_json::Map::new(); for item in items { let mut item_data = match item.to_value(ctx) { serde_json::Value::Object(m) => m, - other => { - let mut m = serde_json::Map::new(); - m.insert("value".to_string(), other); - m - } + other => { let mut m = serde_json::Map::new(); m.insert("value".to_string(), other); m }, }; if let Some(serde_json::Value::String(name)) = item_data.remove("name") { result.insert(name, serde_json::Value::Object(item_data)); } } serde_json::Value::Object(result) + } /// Load a collection of Property from a JSON value. /// Handles both array format `[{...}]`. fn load_parameters(data: &serde_json::Value, ctx: &LoadContext) -> Vec { match data { - serde_json::Value::Array(arr) => arr - .iter() - .map(|v| Property::load_from_value(v, ctx)) - .collect(), + serde_json::Value::Array(arr) => { + arr.iter().map(|v| Property::load_from_value(v, ctx)).collect() + } _ => Vec::new(), + } } /// Save a collection of Property to a JSON value. fn save_parameters(items: &[Property], ctx: &SaveContext) -> serde_json::Value { - serde_json::Value::Array( - items - .iter() - .map(|item| item.to_value(ctx)) - .collect::>(), - ) + + serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()) + } } diff --git a/runtime/rust/prompty/src/model/tools/tool_context.rs b/runtime/rust/prompty/src/model/tools/tool_context.rs index 7fcc5cb1..7338948b 100644 --- a/runtime/rust/prompty/src/model/tools/tool_context.rs +++ b/runtime/rust/prompty/src/model/tools/tool_context.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -45,14 +39,8 @@ impl ToolContext { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - messages: value - .get("messages") - .map(|v| Self::load_messages(v, ctx)) - .unwrap_or_default(), - metadata: value - .get("metadata") - .cloned() - .unwrap_or(serde_json::Value::Null), + messages: value.get("messages").map(|v| Self::load_messages(v, ctx)).unwrap_or_default(), + metadata: value.get("metadata").cloned().unwrap_or(serde_json::Value::Null), } } @@ -63,10 +51,7 @@ impl ToolContext { let mut result = serde_json::Map::new(); // Write base fields if !self.messages.is_empty() { - result.insert( - "messages".to_string(), - Self::save_messages(&self.messages, ctx), - ); + result.insert("messages".to_string(), Self::save_messages(&self.messages, ctx)); } if !self.metadata.is_null() { result.insert("metadata".to_string(), self.metadata.clone()); @@ -89,26 +74,24 @@ impl ToolContext { self.metadata.as_object() } + /// Load a collection of Message from a JSON value. /// Handles both array format `[{...}]`. fn load_messages(data: &serde_json::Value, ctx: &LoadContext) -> Vec { match data { - serde_json::Value::Array(arr) => arr - .iter() - .map(|v| Message::load_from_value(v, ctx)) - .collect(), + serde_json::Value::Array(arr) => { + arr.iter().map(|v| Message::load_from_value(v, ctx)).collect() + } _ => Vec::new(), + } } /// Save a collection of Message to a JSON value. fn save_messages(items: &[Message], ctx: &SaveContext) -> serde_json::Value { - serde_json::Value::Array( - items - .iter() - .map(|item| item.to_value(ctx)) - .collect::>(), - ) + + serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()) + } } diff --git a/runtime/rust/prompty/src/model/tools/tool_dispatch_result.rs b/runtime/rust/prompty/src/model/tools/tool_dispatch_result.rs index 802ed6b2..a7fa5d48 100644 --- a/runtime/rust/prompty/src/model/tools/tool_dispatch_result.rs +++ b/runtime/rust/prompty/src/model/tools/tool_dispatch_result.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -47,21 +41,9 @@ impl ToolDispatchResult { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - tool_call_id: value - .get("toolCallId") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - name: value - .get("name") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - result: value - .get("result") - .filter(|v| v.is_object() || v.is_array() || v.is_string()) - .map(|v| ToolResult::load_from_value(v, ctx)) - .unwrap_or_default(), + tool_call_id: value.get("toolCallId").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + name: value.get("name").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + result: value.get("result").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| ToolResult::load_from_value(v, ctx)).unwrap_or_default(), } } @@ -72,16 +54,10 @@ impl ToolDispatchResult { let mut result = serde_json::Map::new(); // Write base fields if !self.tool_call_id.is_empty() { - result.insert( - "toolCallId".to_string(), - serde_json::Value::String(self.tool_call_id.clone()), - ); + result.insert("toolCallId".to_string(), serde_json::Value::String(self.tool_call_id.clone())); } if !self.name.is_empty() { - result.insert( - "name".to_string(), - serde_json::Value::String(self.name.clone()), - ); + result.insert("name".to_string(), serde_json::Value::String(self.name.clone())); } { let nested = self.result.to_value(ctx); diff --git a/runtime/rust/prompty/src/model/tracing/mod.rs b/runtime/rust/prompty/src/model/tracing/mod.rs index 37608078..501ff5cc 100644 --- a/runtime/rust/prompty/src/model/tracing/mod.rs +++ b/runtime/rust/prompty/src/model/tracing/mod.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] pub mod trace_time; pub use trace_time::*; diff --git a/runtime/rust/prompty/src/model/tracing/trace_file.rs b/runtime/rust/prompty/src/model/tracing/trace_file.rs index 896db469..e5416b63 100644 --- a/runtime/rust/prompty/src/model/tracing/trace_file.rs +++ b/runtime/rust/prompty/src/model/tracing/trace_file.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -47,21 +41,9 @@ impl TraceFile { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - runtime: value - .get("runtime") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - version: value - .get("version") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - trace: value - .get("trace") - .filter(|v| v.is_object() || v.is_array() || v.is_string()) - .map(|v| TraceSpan::load_from_value(v, ctx)) - .unwrap_or_default(), + runtime: value.get("runtime").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + version: value.get("version").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + trace: value.get("trace").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| TraceSpan::load_from_value(v, ctx)).unwrap_or_default(), } } @@ -72,16 +54,10 @@ impl TraceFile { let mut result = serde_json::Map::new(); // Write base fields if !self.runtime.is_empty() { - result.insert( - "runtime".to_string(), - serde_json::Value::String(self.runtime.clone()), - ); + result.insert("runtime".to_string(), serde_json::Value::String(self.runtime.clone())); } if !self.version.is_empty() { - result.insert( - "version".to_string(), - serde_json::Value::String(self.version.clone()), - ); + result.insert("version".to_string(), serde_json::Value::String(self.version.clone())); } { let nested = self.trace.to_value(ctx); diff --git a/runtime/rust/prompty/src/model/tracing/trace_span.rs b/runtime/rust/prompty/src/model/tracing/trace_span.rs index b6411d79..d79153ef 100644 --- a/runtime/rust/prompty/src/model/tracing/trace_span.rs +++ b/runtime/rust/prompty/src/model/tracing/trace_span.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -61,41 +55,15 @@ impl TraceSpan { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - name: value - .get("name") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - __time: value - .get("__time") - .filter(|v| v.is_object() || v.is_array() || v.is_string()) - .map(|v| TraceTime::load_from_value(v, ctx)) - .unwrap_or_default(), - signature: value - .get("signature") - .and_then(|v| v.as_str()) - .map(|s| s.to_string()), - inputs: value - .get("inputs") - .cloned() - .unwrap_or(serde_json::Value::Null), + name: value.get("name").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + __time: value.get("__time").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| TraceTime::load_from_value(v, ctx)).unwrap_or_default(), + signature: value.get("signature").and_then(|v| v.as_str()).map(|s| s.to_string()), + inputs: value.get("inputs").cloned().unwrap_or(serde_json::Value::Null), output: value.get("output").cloned(), - error: value - .get("error") - .and_then(|v| v.as_str()) - .map(|s| s.to_string()), - __usage: value - .get("__usage") - .filter(|v| v.is_object() || v.is_array() || v.is_string()) - .map(|v| TokenUsage::load_from_value(v, ctx)), - attributes: value - .get("attributes") - .cloned() - .unwrap_or(serde_json::Value::Null), - __frames: value - .get("__frames") - .and_then(|v| v.as_array()) - .map(|arr| arr.to_vec()), + error: value.get("error").and_then(|v| v.as_str()).map(|s| s.to_string()), + __usage: value.get("__usage").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| TokenUsage::load_from_value(v, ctx)), + attributes: value.get("attributes").cloned().unwrap_or(serde_json::Value::Null), + __frames: value.get("__frames").and_then(|v| v.as_array()).map(|arr| arr.to_vec()), } } @@ -106,10 +74,7 @@ impl TraceSpan { let mut result = serde_json::Map::new(); // Write base fields if !self.name.is_empty() { - result.insert( - "name".to_string(), - serde_json::Value::String(self.name.clone()), - ); + result.insert("name".to_string(), serde_json::Value::String(self.name.clone())); } { let nested = self.__time.to_value(ctx); @@ -118,10 +83,7 @@ impl TraceSpan { } } if let Some(ref val) = self.signature { - result.insert( - "signature".to_string(), - serde_json::Value::String(val.clone()), - ); + result.insert("signature".to_string(), serde_json::Value::String(val.clone())); } if !self.inputs.is_null() { result.insert("inputs".to_string(), self.inputs.clone()); @@ -142,10 +104,7 @@ impl TraceSpan { result.insert("attributes".to_string(), self.attributes.clone()); } if let Some(ref items) = self.__frames { - result.insert( - "__frames".to_string(), - serde_json::to_value(items).unwrap_or(serde_json::Value::Null), - ); + result.insert("__frames".to_string(), serde_json::to_value(items).unwrap_or(serde_json::Value::Null)); } ctx.process_dict(serde_json::Value::Object(result)) } @@ -170,4 +129,5 @@ impl TraceSpan { pub fn as_attributes_dict(&self) -> Option<&serde_json::Map> { self.attributes.as_object() } + } diff --git a/runtime/rust/prompty/src/model/tracing/trace_time.rs b/runtime/rust/prompty/src/model/tracing/trace_time.rs index 587b7e88..e982402c 100644 --- a/runtime/rust/prompty/src/model/tracing/trace_time.rs +++ b/runtime/rust/prompty/src/model/tracing/trace_time.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -45,20 +39,9 @@ impl TraceTime { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - start: value - .get("start") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - end: value - .get("end") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - duration: value - .get("duration") - .and_then(|v| v.as_f64()) - .unwrap_or(0.0), + start: value.get("start").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + end: value.get("end").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + duration: value.get("duration").and_then(|v| v.as_f64()).unwrap_or(0.0), } } @@ -69,24 +52,13 @@ impl TraceTime { let mut result = serde_json::Map::new(); // Write base fields if !self.start.is_empty() { - result.insert( - "start".to_string(), - serde_json::Value::String(self.start.clone()), - ); + result.insert("start".to_string(), serde_json::Value::String(self.start.clone())); } if !self.end.is_empty() { - result.insert( - "end".to_string(), - serde_json::Value::String(self.end.clone()), - ); + result.insert("end".to_string(), serde_json::Value::String(self.end.clone())); } if self.duration != 0.0 { - result.insert( - "duration".to_string(), - serde_json::Number::from_f64(self.duration as f64) - .map(serde_json::Value::Number) - .unwrap_or(serde_json::Value::Null), - ); + result.insert("duration".to_string(), serde_json::Number::from_f64(self.duration as f64).map(serde_json::Value::Number).unwrap_or(serde_json::Value::Null)); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/wire/anthropic_image_block.rs b/runtime/rust/prompty/src/model/wire/anthropic_image_block.rs index 9786ea16..9a3fa68c 100644 --- a/runtime/rust/prompty/src/model/wire/anthropic_image_block.rs +++ b/runtime/rust/prompty/src/model/wire/anthropic_image_block.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -45,16 +39,8 @@ impl AnthropicImageBlock { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - r#type: value - .get("type") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - source: value - .get("source") - .filter(|v| v.is_object() || v.is_array() || v.is_string()) - .map(|v| AnthropicImageSource::load_from_value(v, ctx)) - .unwrap_or_default(), + r#type: value.get("type").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + source: value.get("source").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| AnthropicImageSource::load_from_value(v, ctx)).unwrap_or_default(), } } @@ -65,10 +51,7 @@ impl AnthropicImageBlock { let mut result = serde_json::Map::new(); // Write base fields if !self.r#type.is_empty() { - result.insert( - "type".to_string(), - serde_json::Value::String(self.r#type.clone()), - ); + result.insert("type".to_string(), serde_json::Value::String(self.r#type.clone())); } { let nested = self.source.to_value(ctx); diff --git a/runtime/rust/prompty/src/model/wire/anthropic_image_source.rs b/runtime/rust/prompty/src/model/wire/anthropic_image_source.rs index 7f5b2166..6b5140ca 100644 --- a/runtime/rust/prompty/src/model/wire/anthropic_image_source.rs +++ b/runtime/rust/prompty/src/model/wire/anthropic_image_source.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -45,21 +39,9 @@ impl AnthropicImageSource { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - r#type: value - .get("type") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - media_type: value - .get("media_type") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - data: value - .get("data") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), + r#type: value.get("type").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + media_type: value.get("media_type").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + data: value.get("data").and_then(|v| v.as_str()).unwrap_or_default().to_string(), } } @@ -70,22 +52,13 @@ impl AnthropicImageSource { let mut result = serde_json::Map::new(); // Write base fields if !self.r#type.is_empty() { - result.insert( - "type".to_string(), - serde_json::Value::String(self.r#type.clone()), - ); + result.insert("type".to_string(), serde_json::Value::String(self.r#type.clone())); } if !self.media_type.is_empty() { - result.insert( - "media_type".to_string(), - serde_json::Value::String(self.media_type.clone()), - ); + result.insert("media_type".to_string(), serde_json::Value::String(self.media_type.clone())); } if !self.data.is_empty() { - result.insert( - "data".to_string(), - serde_json::Value::String(self.data.clone()), - ); + result.insert("data".to_string(), serde_json::Value::String(self.data.clone())); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/wire/anthropic_messages_request.rs b/runtime/rust/prompty/src/model/wire/anthropic_messages_request.rs index 87d2f98d..75ebfa54 100644 --- a/runtime/rust/prompty/src/model/wire/anthropic_messages_request.rs +++ b/runtime/rust/prompty/src/model/wire/anthropic_messages_request.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -61,47 +55,15 @@ impl AnthropicMessagesRequest { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - model: value - .get("model") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - messages: value - .get("messages") - .map(|v| Self::load_messages(v, ctx)) - .unwrap_or_default(), - max_tokens: value - .get("max_tokens") - .and_then(|v| v.as_i64()) - .unwrap_or(0) as i32, - system: value - .get("system") - .and_then(|v| v.as_str()) - .map(|s| s.to_string()), - temperature: value - .get("temperature") - .and_then(|v| v.as_f64()) - .map(|v| v as f32), - top_p: value - .get("top_p") - .and_then(|v| v.as_f64()) - .map(|v| v as f32), - top_k: value - .get("top_k") - .and_then(|v| v.as_i64()) - .map(|v| v as i32), - stop_sequences: value - .get("stop_sequences") - .and_then(|v| v.as_array()) - .map(|arr| { - arr.iter() - .filter_map(|v| v.as_str().map(|s| s.to_string())) - .collect() - }), - tools: value - .get("tools") - .map(|v| Self::load_tools(v, ctx)) - .unwrap_or_default(), + model: value.get("model").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + messages: value.get("messages").map(|v| Self::load_messages(v, ctx)).unwrap_or_default(), + max_tokens: value.get("max_tokens").and_then(|v| v.as_i64()).unwrap_or(0) as i32, + system: value.get("system").and_then(|v| v.as_str()).map(|s| s.to_string()), + temperature: value.get("temperature").and_then(|v| v.as_f64()).map(|v| v as f32), + top_p: value.get("top_p").and_then(|v| v.as_f64()).map(|v| v as f32), + top_k: value.get("top_k").and_then(|v| v.as_i64()).map(|v| v as i32), + stop_sequences: value.get("stop_sequences").and_then(|v| v.as_array()).map(|arr| arr.iter().filter_map(|v| v.as_str().map(|s| s.to_string())).collect()), + tools: value.get("tools").map(|v| Self::load_tools(v, ctx)).unwrap_or_default(), } } @@ -112,53 +74,28 @@ impl AnthropicMessagesRequest { let mut result = serde_json::Map::new(); // Write base fields if !self.model.is_empty() { - result.insert( - "model".to_string(), - serde_json::Value::String(self.model.clone()), - ); + result.insert("model".to_string(), serde_json::Value::String(self.model.clone())); } if !self.messages.is_empty() { - result.insert( - "messages".to_string(), - Self::save_messages(&self.messages, ctx), - ); + result.insert("messages".to_string(), Self::save_messages(&self.messages, ctx)); } if self.max_tokens != 0 { - result.insert( - "max_tokens".to_string(), - serde_json::Value::Number(serde_json::Number::from(self.max_tokens)), - ); + result.insert("max_tokens".to_string(), serde_json::Value::Number(serde_json::Number::from(self.max_tokens))); } if let Some(ref val) = self.system { result.insert("system".to_string(), serde_json::Value::String(val.clone())); } if let Some(val) = self.temperature { - result.insert( - "temperature".to_string(), - serde_json::Number::from_f64(val as f64) - .map(serde_json::Value::Number) - .unwrap_or(serde_json::Value::Null), - ); + result.insert("temperature".to_string(), serde_json::Number::from_f64(val as f64).map(serde_json::Value::Number).unwrap_or(serde_json::Value::Null)); } if let Some(val) = self.top_p { - result.insert( - "top_p".to_string(), - serde_json::Number::from_f64(val as f64) - .map(serde_json::Value::Number) - .unwrap_or(serde_json::Value::Null), - ); + result.insert("top_p".to_string(), serde_json::Number::from_f64(val as f64).map(serde_json::Value::Number).unwrap_or(serde_json::Value::Null)); } if let Some(val) = self.top_k { - result.insert( - "top_k".to_string(), - serde_json::Value::Number(serde_json::Number::from(val)), - ); + result.insert("top_k".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); } if let Some(ref items) = self.stop_sequences { - result.insert( - "stop_sequences".to_string(), - serde_json::to_value(items).unwrap_or(serde_json::Value::Null), - ); + result.insert("stop_sequences".to_string(), serde_json::to_value(items).unwrap_or(serde_json::Value::Null)); } if !self.tools.is_empty() { result.insert("tools".to_string(), Self::save_tools(&self.tools, ctx)); @@ -180,81 +117,71 @@ impl AnthropicMessagesRequest { /// Handles both array format `[{...}]`. fn load_messages(data: &serde_json::Value, ctx: &LoadContext) -> Vec { match data { - serde_json::Value::Array(arr) => arr - .iter() - .map(|v| AnthropicWireMessage::load_from_value(v, ctx)) - .collect(), + serde_json::Value::Array(arr) => { + arr.iter().map(|v| AnthropicWireMessage::load_from_value(v, ctx)).collect() + } _ => Vec::new(), + } } /// Save a collection of AnthropicWireMessage to a JSON value. fn save_messages(items: &[AnthropicWireMessage], ctx: &SaveContext) -> serde_json::Value { - serde_json::Value::Array( - items - .iter() - .map(|item| item.to_value(ctx)) - .collect::>(), - ) + + serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()) + } /// Load a collection of AnthropicToolDefinition from a JSON value. /// Handles both array format `[{...}]` and dict format `{"name": {...}}`. fn load_tools(data: &serde_json::Value, ctx: &LoadContext) -> Vec { match data { - serde_json::Value::Array(arr) => arr - .iter() - .map(|v| AnthropicToolDefinition::load_from_value(v, ctx)) - .collect(), + serde_json::Value::Array(arr) => { + arr.iter().map(|v| AnthropicToolDefinition::load_from_value(v, ctx)).collect() + } - serde_json::Value::Object(obj) => obj - .iter() - .filter_map(|(name, value)| { - if value.is_array() { - return None; - } - let mut v = if value.is_object() { - value.clone() - } else { - serde_json::json!({ "description": value }) - }; - if let serde_json::Value::Object(ref mut m) = v { - m.entry("name".to_string()) - .or_insert_with(|| serde_json::Value::String(name.clone())); - } - Some(AnthropicToolDefinition::load_from_value(&v, ctx)) - }) - .collect(), + serde_json::Value::Object(obj) => { + obj.iter() + .filter_map(|(name, value)| { + if value.is_array() { + return None; + } + let mut v = if value.is_object() { + value.clone() + } else { + serde_json::json!({ "description": value }) + }; + if let serde_json::Value::Object(ref mut m) = v { + m.entry("name".to_string()).or_insert_with(|| serde_json::Value::String(name.clone())); + } + Some(AnthropicToolDefinition::load_from_value(&v, ctx)) + }) + .collect() + } _ => Vec::new(), + } } /// Save a collection of AnthropicToolDefinition to a JSON value. fn save_tools(items: &[AnthropicToolDefinition], ctx: &SaveContext) -> serde_json::Value { + if ctx.collection_format == "array" { - return serde_json::Value::Array( - items - .iter() - .map(|item| item.to_value(ctx)) - .collect::>(), - ); + return serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()); } // Object format: use name as key let mut result = serde_json::Map::new(); for item in items { let mut item_data = match item.to_value(ctx) { serde_json::Value::Object(m) => m, - other => { - let mut m = serde_json::Map::new(); - m.insert("value".to_string(), other); - m - } + other => { let mut m = serde_json::Map::new(); m.insert("value".to_string(), other); m }, }; if let Some(serde_json::Value::String(name)) = item_data.remove("name") { result.insert(name, serde_json::Value::Object(item_data)); } } serde_json::Value::Object(result) + } } diff --git a/runtime/rust/prompty/src/model/wire/anthropic_messages_response.rs b/runtime/rust/prompty/src/model/wire/anthropic_messages_response.rs index abb816ce..fd665d05 100644 --- a/runtime/rust/prompty/src/model/wire/anthropic_messages_response.rs +++ b/runtime/rust/prompty/src/model/wire/anthropic_messages_response.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -55,41 +49,13 @@ impl AnthropicMessagesResponse { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - id: value - .get("id") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - r#type: value - .get("type") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - role: value - .get("role") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - content: value - .get("content") - .and_then(|v| v.as_array()) - .map(|arr| arr.to_vec()) - .unwrap_or_default(), - model: value - .get("model") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - stop_reason: value - .get("stop_reason") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - usage: value - .get("usage") - .filter(|v| v.is_object() || v.is_array() || v.is_string()) - .map(|v| AnthropicUsage::load_from_value(v, ctx)) - .unwrap_or_default(), + id: value.get("id").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + r#type: value.get("type").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + role: value.get("role").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + content: value.get("content").and_then(|v| v.as_array()).map(|arr| arr.to_vec()).unwrap_or_default(), + model: value.get("model").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + stop_reason: value.get("stop_reason").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + usage: value.get("usage").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| AnthropicUsage::load_from_value(v, ctx)).unwrap_or_default(), } } @@ -103,34 +69,19 @@ impl AnthropicMessagesResponse { result.insert("id".to_string(), serde_json::Value::String(self.id.clone())); } if !self.r#type.is_empty() { - result.insert( - "type".to_string(), - serde_json::Value::String(self.r#type.clone()), - ); + result.insert("type".to_string(), serde_json::Value::String(self.r#type.clone())); } if !self.role.is_empty() { - result.insert( - "role".to_string(), - serde_json::Value::String(self.role.clone()), - ); + result.insert("role".to_string(), serde_json::Value::String(self.role.clone())); } if !self.content.is_empty() { - result.insert( - "content".to_string(), - serde_json::to_value(&self.content).unwrap_or(serde_json::Value::Null), - ); + result.insert("content".to_string(), serde_json::to_value(&self.content).unwrap_or(serde_json::Value::Null)); } if !self.model.is_empty() { - result.insert( - "model".to_string(), - serde_json::Value::String(self.model.clone()), - ); + result.insert("model".to_string(), serde_json::Value::String(self.model.clone())); } if !self.stop_reason.is_empty() { - result.insert( - "stop_reason".to_string(), - serde_json::Value::String(self.stop_reason.clone()), - ); + result.insert("stop_reason".to_string(), serde_json::Value::String(self.stop_reason.clone())); } { let nested = self.usage.to_value(ctx); diff --git a/runtime/rust/prompty/src/model/wire/anthropic_text_block.rs b/runtime/rust/prompty/src/model/wire/anthropic_text_block.rs index a89e661f..7d0d779c 100644 --- a/runtime/rust/prompty/src/model/wire/anthropic_text_block.rs +++ b/runtime/rust/prompty/src/model/wire/anthropic_text_block.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -43,16 +37,8 @@ impl AnthropicTextBlock { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - r#type: value - .get("type") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - text: value - .get("text") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), + r#type: value.get("type").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + text: value.get("text").and_then(|v| v.as_str()).unwrap_or_default().to_string(), } } @@ -63,16 +49,10 @@ impl AnthropicTextBlock { let mut result = serde_json::Map::new(); // Write base fields if !self.r#type.is_empty() { - result.insert( - "type".to_string(), - serde_json::Value::String(self.r#type.clone()), - ); + result.insert("type".to_string(), serde_json::Value::String(self.r#type.clone())); } if !self.text.is_empty() { - result.insert( - "text".to_string(), - serde_json::Value::String(self.text.clone()), - ); + result.insert("text".to_string(), serde_json::Value::String(self.text.clone())); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/wire/anthropic_tool_definition.rs b/runtime/rust/prompty/src/model/wire/anthropic_tool_definition.rs index 2499be2b..88554614 100644 --- a/runtime/rust/prompty/src/model/wire/anthropic_tool_definition.rs +++ b/runtime/rust/prompty/src/model/wire/anthropic_tool_definition.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -45,19 +39,9 @@ impl AnthropicToolDefinition { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - name: value - .get("name") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - description: value - .get("description") - .and_then(|v| v.as_str()) - .map(|s| s.to_string()), - input_schema: value - .get("input_schema") - .cloned() - .unwrap_or(serde_json::Value::Null), + name: value.get("name").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + description: value.get("description").and_then(|v| v.as_str()).map(|s| s.to_string()), + input_schema: value.get("input_schema").cloned().unwrap_or(serde_json::Value::Null), } } @@ -68,16 +52,10 @@ impl AnthropicToolDefinition { let mut result = serde_json::Map::new(); // Write base fields if !self.name.is_empty() { - result.insert( - "name".to_string(), - serde_json::Value::String(self.name.clone()), - ); + result.insert("name".to_string(), serde_json::Value::String(self.name.clone())); } if let Some(ref val) = self.description { - result.insert( - "description".to_string(), - serde_json::Value::String(val.clone()), - ); + result.insert("description".to_string(), serde_json::Value::String(val.clone())); } if !self.input_schema.is_null() { result.insert("input_schema".to_string(), self.input_schema.clone()); @@ -99,4 +77,5 @@ impl AnthropicToolDefinition { pub fn as_input_schema_dict(&self) -> Option<&serde_json::Map> { self.input_schema.as_object() } + } diff --git a/runtime/rust/prompty/src/model/wire/anthropic_tool_result_block.rs b/runtime/rust/prompty/src/model/wire/anthropic_tool_result_block.rs index 99d0535e..7cb82dba 100644 --- a/runtime/rust/prompty/src/model/wire/anthropic_tool_result_block.rs +++ b/runtime/rust/prompty/src/model/wire/anthropic_tool_result_block.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -45,21 +39,9 @@ impl AnthropicToolResultBlock { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - r#type: value - .get("type") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - tool_use_id: value - .get("tool_use_id") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - content: value - .get("content") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), + r#type: value.get("type").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + tool_use_id: value.get("tool_use_id").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + content: value.get("content").and_then(|v| v.as_str()).unwrap_or_default().to_string(), } } @@ -70,22 +52,13 @@ impl AnthropicToolResultBlock { let mut result = serde_json::Map::new(); // Write base fields if !self.r#type.is_empty() { - result.insert( - "type".to_string(), - serde_json::Value::String(self.r#type.clone()), - ); + result.insert("type".to_string(), serde_json::Value::String(self.r#type.clone())); } if !self.tool_use_id.is_empty() { - result.insert( - "tool_use_id".to_string(), - serde_json::Value::String(self.tool_use_id.clone()), - ); + result.insert("tool_use_id".to_string(), serde_json::Value::String(self.tool_use_id.clone())); } if !self.content.is_empty() { - result.insert( - "content".to_string(), - serde_json::Value::String(self.content.clone()), - ); + result.insert("content".to_string(), serde_json::Value::String(self.content.clone())); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/wire/anthropic_tool_use_block.rs b/runtime/rust/prompty/src/model/wire/anthropic_tool_use_block.rs index 504d3808..86d26cb8 100644 --- a/runtime/rust/prompty/src/model/wire/anthropic_tool_use_block.rs +++ b/runtime/rust/prompty/src/model/wire/anthropic_tool_use_block.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -47,25 +41,10 @@ impl AnthropicToolUseBlock { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - r#type: value - .get("type") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - id: value - .get("id") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - name: value - .get("name") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - input: value - .get("input") - .cloned() - .unwrap_or(serde_json::Value::Null), + r#type: value.get("type").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + id: value.get("id").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + name: value.get("name").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + input: value.get("input").cloned().unwrap_or(serde_json::Value::Null), } } @@ -76,19 +55,13 @@ impl AnthropicToolUseBlock { let mut result = serde_json::Map::new(); // Write base fields if !self.r#type.is_empty() { - result.insert( - "type".to_string(), - serde_json::Value::String(self.r#type.clone()), - ); + result.insert("type".to_string(), serde_json::Value::String(self.r#type.clone())); } if !self.id.is_empty() { result.insert("id".to_string(), serde_json::Value::String(self.id.clone())); } if !self.name.is_empty() { - result.insert( - "name".to_string(), - serde_json::Value::String(self.name.clone()), - ); + result.insert("name".to_string(), serde_json::Value::String(self.name.clone())); } if !self.input.is_null() { result.insert("input".to_string(), self.input.clone()); @@ -110,4 +83,5 @@ impl AnthropicToolUseBlock { pub fn as_input_dict(&self) -> Option<&serde_json::Map> { self.input.as_object() } + } diff --git a/runtime/rust/prompty/src/model/wire/anthropic_usage.rs b/runtime/rust/prompty/src/model/wire/anthropic_usage.rs index 4f8279f5..42109577 100644 --- a/runtime/rust/prompty/src/model/wire/anthropic_usage.rs +++ b/runtime/rust/prompty/src/model/wire/anthropic_usage.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -43,14 +37,8 @@ impl AnthropicUsage { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - input_tokens: value - .get("input_tokens") - .and_then(|v| v.as_i64()) - .unwrap_or(0) as i32, - output_tokens: value - .get("output_tokens") - .and_then(|v| v.as_i64()) - .unwrap_or(0) as i32, + input_tokens: value.get("input_tokens").and_then(|v| v.as_i64()).unwrap_or(0) as i32, + output_tokens: value.get("output_tokens").and_then(|v| v.as_i64()).unwrap_or(0) as i32, } } @@ -61,16 +49,10 @@ impl AnthropicUsage { let mut result = serde_json::Map::new(); // Write base fields if self.input_tokens != 0 { - result.insert( - "input_tokens".to_string(), - serde_json::Value::Number(serde_json::Number::from(self.input_tokens)), - ); + result.insert("input_tokens".to_string(), serde_json::Value::Number(serde_json::Number::from(self.input_tokens))); } if self.output_tokens != 0 { - result.insert( - "output_tokens".to_string(), - serde_json::Value::Number(serde_json::Number::from(self.output_tokens)), - ); + result.insert("output_tokens".to_string(), serde_json::Value::Number(serde_json::Number::from(self.output_tokens))); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/wire/anthropic_wire_message.rs b/runtime/rust/prompty/src/model/wire/anthropic_wire_message.rs index 46d24ca0..9e16d3fd 100644 --- a/runtime/rust/prompty/src/model/wire/anthropic_wire_message.rs +++ b/runtime/rust/prompty/src/model/wire/anthropic_wire_message.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use super::super::context::{LoadContext, SaveContext}; @@ -43,16 +37,8 @@ impl AnthropicWireMessage { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - role: value - .get("role") - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(), - content: value - .get("content") - .and_then(|v| v.as_array()) - .map(|arr| arr.to_vec()) - .unwrap_or_default(), + role: value.get("role").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + content: value.get("content").and_then(|v| v.as_array()).map(|arr| arr.to_vec()).unwrap_or_default(), } } @@ -63,16 +49,10 @@ impl AnthropicWireMessage { let mut result = serde_json::Map::new(); // Write base fields if !self.role.is_empty() { - result.insert( - "role".to_string(), - serde_json::Value::String(self.role.clone()), - ); + result.insert("role".to_string(), serde_json::Value::String(self.role.clone())); } if !self.content.is_empty() { - result.insert( - "content".to_string(), - serde_json::to_value(&self.content).unwrap_or(serde_json::Value::Null), - ); + result.insert("content".to_string(), serde_json::to_value(&self.content).unwrap_or(serde_json::Value::Null)); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/wire/mod.rs b/runtime/rust/prompty/src/model/wire/mod.rs index 8daca807..db9e6906 100644 --- a/runtime/rust/prompty/src/model/wire/mod.rs +++ b/runtime/rust/prompty/src/model/wire/mod.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] pub mod anthropic_text_block; pub use anthropic_text_block::*; diff --git a/runtime/rust/prompty/src/pipeline.rs b/runtime/rust/prompty/src/pipeline.rs index 86f42eb8..7b6c9356 100644 --- a/runtime/rust/prompty/src/pipeline.rs +++ b/runtime/rust/prompty/src/pipeline.rs @@ -558,6 +558,33 @@ pub async fn invoke_from_path( /// Events emitted during the agent loop in `turn()`. #[derive(Debug, Clone)] pub enum AgentEvent { + /// The turn has started. + TurnStart { + agent: Option, + max_iterations: usize, + }, + /// The turn has ended. + TurnEnd { + status: String, + iterations: usize, + response: serde_json::Value, + }, + /// An LLM request is starting. + LlmStart { + provider: String, + model_id: Option, + message_count: usize, + iteration: usize, + }, + /// An LLM request completed. + LlmComplete { iteration: usize }, + /// A transient operation will be retried. + Retry { + operation: String, + attempt: usize, + max_attempts: usize, + reason: String, + }, /// A streaming token from the LLM. Token(String), /// A thinking/reasoning token from the LLM. @@ -566,6 +593,13 @@ pub enum AgentEvent { ToolCallStart { name: String, arguments: String }, /// A tool call has completed with a result. ToolResult { name: String, result: String }, + /// A tool dispatch has completed with normalized success metadata. + ToolCallComplete { + name: String, + success: bool, + result: String, + error_kind: Option, + }, /// Status update from the agent loop. Status(String), /// The message list was updated (e.g., tool results appended). @@ -718,6 +752,14 @@ impl TurnOptions { } } + fn emit_failed_turn_end(&self, status: &str, iterations: usize) { + self.emit(AgentEvent::TurnEnd { + status: status.to_string(), + iterations, + response: serde_json::Value::Null, + }); + } + fn is_cancelled(&self) -> bool { self.cancelled .as_ref() @@ -915,8 +957,27 @@ pub async fn turn( span.emit("description", &json!("Simple turn (no tools)")); let empty = serde_json::json!({}); span.emit("inputs", inputs.unwrap_or(&empty)); + opts.emit(AgentEvent::TurnStart { + agent: Some(agent.name.clone()), + max_iterations: opts.max_iterations, + }); + + if opts.is_cancelled() { + opts.emit(AgentEvent::Cancelled); + opts.emit_failed_turn_end("cancelled", 0); + span.emit("error", &json!("Operation cancelled")); + span.end(); + return Err(InvokerError::Cancelled("Operation cancelled".to_string())); + } - let mut messages = prepare(agent, inputs).await?; + let mut messages = match prepare(agent, inputs).await { + Ok(messages) => messages, + Err(err) => { + opts.emit_failed_turn_end("error", 0); + span.end(); + return Err(err); + } + }; let provider = resolve_provider(agent); // Drain steering @@ -944,6 +1005,7 @@ pub async fn turn( let gr = guardrails.check_input(&messages, agent).await; if !gr.allowed { let reason = gr.reason.unwrap_or_else(|| "Input denied".into()); + opts.emit_failed_turn_end("error", 0); span.emit("error", &json!(format!("Input guardrail: {reason}"))); span.end(); return Err(InvokerError::Execute( @@ -953,13 +1015,35 @@ pub async fn turn( } // Execute (streaming-aware) + if opts.is_cancelled() { + opts.emit(AgentEvent::Cancelled); + opts.emit_failed_turn_end("cancelled", 0); + span.emit("error", &json!("Operation cancelled")); + span.end(); + return Err(InvokerError::Cancelled("Operation cancelled".to_string())); + } let streaming = is_streaming(agent); let processed = if streaming { + opts.emit(AgentEvent::LlmStart { + provider: provider.clone(), + model_id: (!agent.model.id.is_empty()).then(|| agent.model.id.clone()), + message_count: messages.len(), + iteration: 0, + }); match registry::invoke_executor_stream(&provider, agent, &messages).await { Ok(sse_stream) => { + opts.emit(AgentEvent::LlmComplete { iteration: 0 }); let prompty_stream = PromptyStream::from_stream("PromptyStream", sse_stream); - let chunk_stream = - registry::invoke_processor_stream(&provider, Box::pin(prompty_stream))?; + let chunk_stream = match registry::invoke_processor_stream( + &provider, + Box::pin(prompty_stream), + ) { + Ok(stream) => stream, + Err(err) => { + opts.emit_failed_turn_end("error", 0); + return Err(err); + } + }; use futures::StreamExt; let mut text_parts = Vec::new(); @@ -974,6 +1058,7 @@ pub async fn turn( opts.emit(AgentEvent::Thinking(t)); } StreamChunk::Error(e) => { + opts.emit_failed_turn_end("error", 0); span.emit("error", &json!(e)); span.end(); return Err(InvokerError::Execute(e.into())); @@ -986,26 +1071,76 @@ pub async fn turn( Err(_) => { // Fallback to non-streaming let raw_response = - registry::invoke_executor(&provider, agent, &messages).await?; + match registry::invoke_executor(&provider, agent, &messages).await { + Ok(response) => response, + Err(err) => { + opts.emit_failed_turn_end("error", 0); + return Err(err); + } + }; + opts.emit(AgentEvent::LlmComplete { iteration: 0 }); if opts.raw { span.emit("result", &json!("(raw)")); span.end(); + opts.emit(AgentEvent::Done { + response: raw_response.clone(), + messages: messages.clone(), + }); + opts.emit(AgentEvent::TurnEnd { + status: "success".to_string(), + iterations: 0, + response: raw_response.clone(), + }); return Ok(raw_response); } - process(agent, raw_response).await? + match process(agent, raw_response.clone()).await { + Ok(result) => result, + Err(err) => { + opts.emit_failed_turn_end("error", 0); + return Err(err); + } + } } } } else { - let raw_response = registry::invoke_executor(&provider, agent, &messages).await?; + opts.emit(AgentEvent::LlmStart { + provider: provider.clone(), + model_id: (!agent.model.id.is_empty()).then(|| agent.model.id.clone()), + message_count: messages.len(), + iteration: 0, + }); + let raw_response = match registry::invoke_executor(&provider, agent, &messages).await { + Ok(response) => response, + Err(err) => { + opts.emit_failed_turn_end("error", 0); + return Err(err); + } + }; + opts.emit(AgentEvent::LlmComplete { iteration: 0 }); if opts.raw { span.emit("result", &json!("(raw)")); span.end(); + opts.emit(AgentEvent::Done { + response: raw_response.clone(), + messages: messages.clone(), + }); + opts.emit(AgentEvent::TurnEnd { + status: "success".to_string(), + iterations: 0, + response: raw_response.clone(), + }); return Ok(raw_response); } - process(agent, raw_response).await? + match process(agent, raw_response.clone()).await { + Ok(result) => result, + Err(err) => { + opts.emit_failed_turn_end("error", 0); + return Err(err); + } + } }; // Output guardrail @@ -1013,6 +1148,7 @@ pub async fn turn( let gr = guardrails.check_output(&processed, agent).await; if !gr.allowed { let reason = gr.reason.unwrap_or_else(|| "Output denied".into()); + opts.emit_failed_turn_end("error", 0); span.emit("error", &json!(format!("Output guardrail: {reason}"))); span.end(); return Err(InvokerError::Execute( @@ -1022,12 +1158,30 @@ pub async fn turn( if let Some(rewrite) = gr.rewrite { span.emit("result", &rewrite); span.end(); + opts.emit(AgentEvent::Done { + response: rewrite.clone(), + messages: messages.clone(), + }); + opts.emit(AgentEvent::TurnEnd { + status: "success".to_string(), + iterations: 0, + response: rewrite.clone(), + }); return Ok(rewrite); } } span.emit("result", &processed); span.end(); + opts.emit(AgentEvent::Done { + response: processed.clone(), + messages: messages.clone(), + }); + opts.emit(AgentEvent::TurnEnd { + status: "success".to_string(), + iterations: 0, + response: processed.clone(), + }); return Ok(processed); } @@ -1037,23 +1191,36 @@ pub async fn turn( span.emit("description", &json!("Agent turn (tool-calling loop)")); let empty = serde_json::json!({}); span.emit("inputs", inputs.unwrap_or(&empty)); + opts.emit(AgentEvent::TurnStart { + agent: Some(agent.name.clone()), + max_iterations: opts.max_iterations, + }); // Check cancellation at start if opts.is_cancelled() { opts.emit(AgentEvent::Cancelled); + opts.emit_failed_turn_end("cancelled", 0); span.emit("error", &json!("Operation cancelled")); span.end(); return Err(InvokerError::Cancelled("Operation cancelled".to_string())); } // Prepare messages - let mut messages = prepare(agent, inputs).await?; + let mut messages = match prepare(agent, inputs).await { + Ok(messages) => messages, + Err(err) => { + opts.emit_failed_turn_end("error", 0); + span.end(); + return Err(err); + } + }; let provider = resolve_provider(agent); for iteration in 0..opts.max_iterations { // Check cancellation before each LLM call if opts.is_cancelled() { opts.emit(AgentEvent::Cancelled); + opts.emit_failed_turn_end("cancelled", iteration); span.emit("error", &json!("Operation cancelled")); span.end(); return Err(InvokerError::Cancelled("Operation cancelled".to_string())); @@ -1102,6 +1269,7 @@ pub async fn turn( if !gr.allowed { let reason = gr.reason.unwrap_or_else(|| "Input denied".into()); iter_span.end(); + opts.emit_failed_turn_end("error", iteration); span.emit("error", &json!(format!("Input guardrail: {reason}"))); span.end(); return Err(InvokerError::Execute( @@ -1118,17 +1286,28 @@ pub async fn turn( if opts.is_cancelled() { iter_span.end(); opts.emit(AgentEvent::Cancelled); + opts.emit_failed_turn_end("cancelled", iteration); span.emit("error", &json!("Operation cancelled")); span.end(); return Err(InvokerError::Cancelled("Operation cancelled".to_string())); } + opts.emit(AgentEvent::LlmStart { + provider: provider.clone(), + model_id: (!agent.model.id.is_empty()).then(|| agent.model.id.clone()), + message_count: messages.len(), + iteration, + }); match execute_llm_attempt(&provider, agent, &messages, streaming, &opts).await { - Ok(result) => break result, + Ok(result) => { + opts.emit(AgentEvent::LlmComplete { iteration }); + break result; + } Err(e) => { llm_attempts += 1; if llm_attempts >= opts.max_llm_retries as u32 { iter_span.end(); + opts.emit_failed_turn_end("error", iteration); span.emit( "error", &json!(format!( @@ -1152,6 +1331,12 @@ pub async fn turn( llm_attempts + 1, opts.max_llm_retries ))); + opts.emit(AgentEvent::Retry { + operation: "llm".to_string(), + attempt: llm_attempts as usize + 1, + max_attempts: opts.max_llm_retries, + reason: e.clone(), + }); // Exponential backoff with jitter, capped at 60s // Formula: min(2^attempts + jitter, 60) per spec §9.10 let backoff_secs = { @@ -1175,6 +1360,7 @@ pub async fn turn( } } => { opts.emit(AgentEvent::Cancelled); + opts.emit_failed_turn_end("cancelled", iteration); span.emit("error", &json!("Operation cancelled during retry backoff")); span.end(); return Err(InvokerError::Cancelled( @@ -1198,6 +1384,7 @@ pub async fn turn( if !gr.allowed { let reason = gr.reason.unwrap_or_else(|| "Output denied".into()); iter_span.end(); + opts.emit_failed_turn_end("error", iteration + 1); span.emit("error", &json!(format!("Output guardrail: {reason}"))); span.end(); return Err(InvokerError::Execute( @@ -1211,6 +1398,11 @@ pub async fn turn( response: rewrite.clone(), messages: messages.clone(), }); + opts.emit(AgentEvent::TurnEnd { + status: "success".to_string(), + iterations: iteration + 1, + response: rewrite.clone(), + }); span.emit("result", &rewrite); span.emit("iterations", &json!(iteration + 1)); span.end(); @@ -1225,6 +1417,11 @@ pub async fn turn( response: final_result.clone(), messages: messages.clone(), }); + opts.emit(AgentEvent::TurnEnd { + status: "success".to_string(), + iterations: iteration + 1, + response: final_result.clone(), + }); span.emit("result", &final_result); span.emit("iterations", &json!(iteration + 1)); span.end(); @@ -1249,7 +1446,18 @@ pub async fn turn( let tool_results = if opts.parallel_tool_calls { dispatch_tools_parallel(&tool_calls, &opts, agent, inputs).await } else { - dispatch_tools_sequential(&tool_calls, &opts, agent, inputs).await? + match dispatch_tools_sequential(&tool_calls, &opts, agent, inputs).await { + Ok(results) => results, + Err(err) => { + let status = if matches!(err, InvokerError::Cancelled(_)) { + "cancelled" + } else { + "error" + }; + opts.emit_failed_turn_end(status, iteration + 1); + return Err(err); + } + } }; tool_span.emit("result", &json!(tool_results)); @@ -1259,13 +1467,19 @@ pub async fn turn( let text_content = extract_text_from_processed(&processed); // Format tool results into messages using provider-specific formatting - let tool_messages = registry::invoke_format_tool_messages( + let tool_messages = match registry::invoke_format_tool_messages( &provider, &raw_response, &tool_calls, &tool_results, text_content.as_deref(), - )?; + ) { + Ok(messages) => messages, + Err(err) => { + opts.emit_failed_turn_end("error", iteration + 1); + return Err(err); + } + }; messages.extend(tool_messages); opts.emit(AgentEvent::MessagesUpdated { @@ -1290,6 +1504,7 @@ pub async fn turn( opts.max_iterations ); opts.emit(AgentEvent::Error(msg.clone())); + opts.emit_failed_turn_end("error", iteration + 1); span.emit("error", &json!(msg)); span.end(); return Err(InvokerError::Execute(msg.into())); @@ -1302,6 +1517,7 @@ pub async fn turn( opts.max_iterations ); opts.emit(AgentEvent::Error(msg.clone())); + opts.emit_failed_turn_end("error", opts.max_iterations); span.emit("error", &json!(msg)); span.end(); Err(InvokerError::Execute(msg.into())) @@ -1420,6 +1636,12 @@ async fn dispatch_tools_sequential( name: tc.name.clone(), result: format!("Error: Tool guardrail denied: {reason}"), }); + opts.emit(AgentEvent::ToolCallComplete { + name: tc.name.clone(), + success: false, + result: format!("Error: Tool guardrail denied: {reason}"), + error_kind: Some("guardrail_denied".to_string()), + }); tool_results.push(format!("Error: Tool guardrail denied: {reason}")); continue; } @@ -1461,6 +1683,14 @@ async fn dispatch_tools_sequential( name: tc.name.clone(), result: result.clone(), }); + opts.emit(AgentEvent::ToolCallComplete { + name: tc.name.clone(), + success: !result.starts_with("Error:"), + result: result.clone(), + error_kind: result + .starts_with("Error:") + .then(|| "tool_error".to_string()), + }); tool_results.push(result); } Ok(tool_results) @@ -1532,6 +1762,14 @@ async fn dispatch_tools_parallel( name: tc.name.clone(), result: result.clone(), }); + opts.emit(AgentEvent::ToolCallComplete { + name: tc.name.clone(), + success: !result.starts_with("Error:"), + result: result.clone(), + error_kind: result + .starts_with("Error:") + .then(|| "tool_error".to_string()), + }); } results @@ -1972,7 +2210,7 @@ mod tests { // and exercise the full turn() function. use std::sync::Arc; - use std::sync::atomic::{AtomicUsize, Ordering}; + use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; /// Mock executor that returns tool calls on first call, then a final response. struct ToolCallThenDoneExecutor { @@ -2133,6 +2371,52 @@ mod tests { Prompty::load_from_value(&data, &LoadContext::default()) } + fn capture_events() -> (Arc>>, EventCallback) { + let events = Arc::new(std::sync::Mutex::new(Vec::new())); + let events_clone = events.clone(); + let on_event: EventCallback = Box::new(move |event| { + events_clone.lock().unwrap().push(event); + }); + (events, on_event) + } + + fn assert_turn_lifecycle(events: &[AgentEvent], expected_status: &str) { + let start_indices: Vec<_> = events + .iter() + .enumerate() + .filter_map(|(index, event)| { + matches!(event, AgentEvent::TurnStart { .. }).then_some(index) + }) + .collect(); + let end_indices: Vec<_> = events + .iter() + .enumerate() + .filter_map(|(index, event)| { + matches!(event, AgentEvent::TurnEnd { .. }).then_some(index) + }) + .collect(); + + assert_eq!( + start_indices.len(), + 1, + "expected exactly one TurnStart, got {events:?}" + ); + assert_eq!( + end_indices.len(), + 1, + "expected exactly one TurnEnd, got {events:?}" + ); + assert!( + start_indices[0] < end_indices[0], + "TurnStart should precede TurnEnd, got {events:?}" + ); + + match &events[end_indices[0]] { + AgentEvent::TurnEnd { status, .. } => assert_eq!(status, expected_status), + other => panic!("expected TurnEnd, got {other:?}"), + } + } + #[tokio::test] #[serial] async fn test_turn_without_tools_invokes_directly() { @@ -2372,15 +2656,208 @@ mod tests { let _result = turn(&agent, None, Some(opts)).await.unwrap(); let captured = events.lock().unwrap(); - // Should see: ToolCallStart → ToolResult → Done + // Should see lifecycle events plus ToolCallStart → ToolResult → Done. assert!( captured.len() >= 3, "Expected at least 3 events, got {:?}", captured ); - assert!(captured[0].contains("ToolCallStart")); - assert!(captured[1].contains("ToolResult")); - assert!(captured.last().unwrap().contains("Done")); + let tool_start_index = captured + .iter() + .position(|event| event.contains("ToolCallStart")) + .expect("expected ToolCallStart event"); + let tool_result_index = captured + .iter() + .position(|event| event.contains("ToolResult")) + .expect("expected ToolResult event"); + assert!(tool_start_index < tool_result_index); + let done_index = captured + .iter() + .position(|event| event.contains("Done")) + .expect("expected Done event"); + let turn_end_index = captured + .iter() + .position(|event| event.contains("TurnEnd")) + .expect("expected TurnEnd event"); + assert!(done_index < turn_end_index); + } + + #[tokio::test] + #[serial] + async fn test_turn_lifecycle_success_simple_path() { + ensure_defaults(); + let key = "turn_lifecycle_simple_success"; + registry::register_executor( + key, + ToolCallThenDoneExecutor { + call_count: Arc::new(AtomicUsize::new(1)), + }, + ); + registry::register_processor(key, MockProcessor); + + let agent = make_simple_agent(key); + let (events, on_event) = capture_events(); + let opts = TurnOptions { + on_event: Some(on_event), + ..Default::default() + }; + + let result = turn(&agent, None, Some(opts)).await.unwrap(); + assert_eq!(result, "The weather in Seattle is 72°F."); + assert_turn_lifecycle(&events.lock().unwrap(), "success"); + } + + #[tokio::test] + #[serial] + async fn test_turn_lifecycle_success_tool_loop() { + ensure_defaults(); + let key = "turn_lifecycle_tool_success"; + registry::register_executor( + key, + ToolCallThenDoneExecutor { + call_count: Arc::new(AtomicUsize::new(0)), + }, + ); + registry::register_processor(key, MockProcessor); + + let agent = make_simple_agent(key); + let mut tools = HashMap::new(); + tools.insert( + "get_weather".to_string(), + ToolHandler::Sync(Box::new(|_| Ok("72°F and sunny".to_string()))), + ); + let (events, on_event) = capture_events(); + let opts = TurnOptions { + tools, + on_event: Some(on_event), + ..Default::default() + }; + + let result = turn(&agent, None, Some(opts)).await.unwrap(); + assert_eq!(result, "The weather in Seattle is 72°F."); + assert_turn_lifecycle(&events.lock().unwrap(), "success"); + } + + #[tokio::test] + #[serial] + async fn test_turn_lifecycle_input_guardrail_error() { + ensure_defaults(); + let key = "turn_lifecycle_guardrail_error"; + registry::register_executor( + key, + ToolCallThenDoneExecutor { + call_count: Arc::new(AtomicUsize::new(1)), + }, + ); + registry::register_processor(key, MockProcessor); + + let agent = make_simple_agent(key); + let (events, on_event) = capture_events(); + let guardrails = crate::guardrails::Guardrails { + input: Some(Box::new(|_, _| { + Box::pin(async { crate::guardrails::GuardrailResult::deny("blocked") }) + })), + ..Default::default() + }; + let opts = TurnOptions { + on_event: Some(on_event), + guardrails: Some(guardrails), + ..Default::default() + }; + + let result = turn(&agent, None, Some(opts)).await; + assert!(result.is_err()); + assert_turn_lifecycle(&events.lock().unwrap(), "error"); + } + + #[tokio::test] + #[serial] + async fn test_turn_lifecycle_retry_exhausted_error() { + ensure_defaults(); + let key = "turn_lifecycle_retry_error"; + registry::register_executor(key, AlwaysFailExecutor); + registry::register_processor(key, MockProcessor); + + let agent = make_simple_agent(key); + let mut tools = HashMap::new(); + tools.insert( + "dummy".to_string(), + ToolHandler::Sync(Box::new(|_| Ok("ok".to_string()))), + ); + let (events, on_event) = capture_events(); + let opts = TurnOptions { + tools, + on_event: Some(on_event), + max_llm_retries: 1, + ..Default::default() + }; + + let result = turn(&agent, None, Some(opts)).await; + assert!(result.is_err()); + assert_turn_lifecycle(&events.lock().unwrap(), "error"); + } + + #[tokio::test] + #[serial] + async fn test_turn_lifecycle_cancelled_simple_path() { + ensure_defaults(); + let key = "turn_lifecycle_simple_cancelled"; + registry::register_executor( + key, + ToolCallThenDoneExecutor { + call_count: Arc::new(AtomicUsize::new(1)), + }, + ); + registry::register_processor(key, MockProcessor); + + let agent = make_simple_agent(key); + let (events, on_event) = capture_events(); + let opts = TurnOptions { + on_event: Some(on_event), + cancelled: Some(Arc::new(AtomicBool::new(true))), + ..Default::default() + }; + + let result = turn(&agent, None, Some(opts)).await; + assert!(result.is_err()); + assert_turn_lifecycle(&events.lock().unwrap(), "cancelled"); + } + + #[tokio::test] + #[serial] + async fn test_turn_lifecycle_cancelled_during_tool_dispatch() { + ensure_defaults(); + let key = "turn_lifecycle_tool_cancelled"; + registry::register_executor( + key, + ToolCallThenDoneExecutor { + call_count: Arc::new(AtomicUsize::new(0)), + }, + ); + registry::register_processor(key, MockProcessor); + + let agent = make_simple_agent(key); + let cancel = Arc::new(AtomicBool::new(false)); + let cancel_in_tool = cancel.clone(); + let mut tools = HashMap::new(); + tools.insert( + "get_weather".to_string(), + ToolHandler::Sync(Box::new(move |_| { + cancel_in_tool.store(true, Ordering::Relaxed); + Ok("72°F and sunny".to_string()) + })), + ); + let (events, on_event) = capture_events(); + let opts = TurnOptions { + tools, + on_event: Some(on_event), + cancelled: Some(cancel), + ..Default::default() + }; + + let result = turn(&agent, None, Some(opts)).await; + assert!(result.is_err()); + assert_turn_lifecycle(&events.lock().unwrap(), "cancelled"); } #[tokio::test] diff --git a/runtime/rust/prompty/tests/agent_vectors.rs b/runtime/rust/prompty/tests/agent_vectors.rs index 17365801..61c942c8 100644 --- a/runtime/rust/prompty/tests/agent_vectors.rs +++ b/runtime/rust/prompty/tests/agent_vectors.rs @@ -547,9 +547,15 @@ async fn run_vector_with_events( let events_clone = events.clone(); let on_event: EventCallback = Box::new(move |event: AgentEvent| { let event_type = match &event { + AgentEvent::TurnStart { .. } => "turn_start", + AgentEvent::TurnEnd { .. } => "turn_end", + AgentEvent::LlmStart { .. } => "llm_start", + AgentEvent::LlmComplete { .. } => "llm_complete", + AgentEvent::Retry { .. } => "retry", AgentEvent::Token(_) => "token", AgentEvent::Thinking(_) => "thinking", AgentEvent::ToolCallStart { .. } => "tool_call_start", + AgentEvent::ToolCallComplete { .. } => "tool_call_complete", AgentEvent::ToolResult { .. } => "tool_result", AgentEvent::Status(_) => "status", AgentEvent::MessagesUpdated { .. } => "messages_updated", @@ -591,9 +597,17 @@ async fn test_events_basic_tool_loop() { events.contains(&"tool_result".to_string()), "missing tool_result event in {events:?}" ); + let done_index = events + .iter() + .position(|event| event == "done") + .expect("missing done event"); + let turn_end_index = events + .iter() + .position(|event| event == "turn_end") + .expect("missing turn_end event"); assert!( - events.last() == Some(&"done".to_string()), - "last event should be 'done', got {events:?}" + done_index < turn_end_index, + "done should be emitted before turn_end, got {events:?}" ); } @@ -716,9 +730,15 @@ async fn test_cancellation_between_iterations() { let events_clone = events.clone(); let on_event: EventCallback = Box::new(move |event: AgentEvent| { let event_type = match &event { + AgentEvent::TurnStart { .. } => "turn_start", + AgentEvent::TurnEnd { .. } => "turn_end", + AgentEvent::LlmStart { .. } => "llm_start", + AgentEvent::LlmComplete { .. } => "llm_complete", + AgentEvent::Retry { .. } => "retry", AgentEvent::Token(_) => "token", AgentEvent::Thinking(_) => "thinking", AgentEvent::ToolCallStart { .. } => "tool_call_start", + AgentEvent::ToolCallComplete { .. } => "tool_call_complete", AgentEvent::ToolResult { .. } => "tool_result", AgentEvent::Status(_) => "status", AgentEvent::MessagesUpdated { .. } => "messages_updated", @@ -988,7 +1008,7 @@ fn build_extension_opts( // Steering let steering = input.get("steering").map(|s| { - let mut steering = prompty::steering::Steering::new(); + let steering = prompty::steering::Steering::new(); if let Some(msgs) = s.get("messages").and_then(|m| m.as_array()) { for msg in msgs { let text = msg.get("text").and_then(|t| t.as_str()).unwrap_or(""); diff --git a/runtime/rust/prompty/tests/model/agent/guardrail_result_test.rs b/runtime/rust/prompty/tests/model/agent/guardrail_result_test.rs index 462e70dc..356762a9 100644 --- a/runtime/rust/prompty/tests/model/agent/guardrail_result_test.rs +++ b/runtime/rust/prompty/tests/model/agent/guardrail_result_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::GuardrailResult; use prompty::model::context::{LoadContext, SaveContext}; @@ -21,11 +15,7 @@ fn test_guardrail_result_load_json() { "####; let ctx = LoadContext::default(); let result = GuardrailResult::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.allowed, true); assert!(instance.reason.is_some(), "Expected reason to be Some"); @@ -41,11 +31,7 @@ reason: Content is safe "####; let ctx = LoadContext::default(); let result = GuardrailResult::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.allowed, true); assert!(instance.reason.is_some(), "Expected reason to be Some"); @@ -65,11 +51,7 @@ fn test_guardrail_result_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } #[test] diff --git a/runtime/rust/prompty/tests/model/agent/mod.rs b/runtime/rust/prompty/tests/model/agent/mod.rs index 26b1866e..b08de0af 100644 --- a/runtime/rust/prompty/tests/model/agent/mod.rs +++ b/runtime/rust/prompty/tests/model/agent/mod.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] -mod guardrail_result_test; mod prompty_test; +mod guardrail_result_test; diff --git a/runtime/rust/prompty/tests/model/agent/prompty_test.rs b/runtime/rust/prompty/tests/model/agent/prompty_test.rs index 5b85c643..f60e1409 100644 --- a/runtime/rust/prompty/tests/model/agent/prompty_test.rs +++ b/runtime/rust/prompty/tests/model/agent/prompty_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::Prompty; use prompty::model::context::{LoadContext, SaveContext}; @@ -82,34 +76,15 @@ fn test_prompty_load_json() { "####; let ctx = LoadContext::default(); let result = Prompty::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.name, "basic-prompt"); - assert!( - instance.display_name.is_some(), - "Expected display_name to be Some" - ); + assert!(instance.display_name.is_some(), "Expected display_name to be Some"); assert_eq!(instance.display_name.as_ref().unwrap(), &"Basic Prompt"); - assert!( - instance.description.is_some(), - "Expected description to be Some" - ); - assert_eq!( - instance.description.as_ref().unwrap(), - &"A basic prompt that uses the GPT-3 chat API to answer questions" - ); - assert!( - instance.instructions.is_some(), - "Expected instructions to be Some" - ); - assert_eq!( - instance.instructions.as_ref().unwrap(), - &"system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" - ); + assert!(instance.description.is_some(), "Expected description to be Some"); + assert_eq!(instance.description.as_ref().unwrap(), &"A basic prompt that uses the GPT-3 chat API to answer questions"); + assert!(instance.instructions.is_some(), "Expected instructions to be Some"); + assert_eq!(instance.instructions.as_ref().unwrap(), &"system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}"); } #[test] @@ -183,25 +158,12 @@ instructions: "system: "####; let ctx = LoadContext::default(); let result = Prompty::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.name, "basic-prompt"); - assert!( - instance.display_name.is_some(), - "Expected display_name to be Some" - ); - assert!( - instance.description.is_some(), - "Expected description to be Some" - ); - assert!( - instance.instructions.is_some(), - "Expected instructions to be Some" - ); + assert!(instance.display_name.is_some(), "Expected display_name to be Some"); + assert!(instance.description.is_some(), "Expected description to be Some"); + assert!(instance.instructions.is_some(), "Expected instructions to be Some"); } #[test] @@ -279,11 +241,7 @@ fn test_prompty_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } #[test] @@ -356,34 +314,15 @@ fn test_prompty_load_json_1() { "####; let ctx = LoadContext::default(); let result = Prompty::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.name, "basic-prompt"); - assert!( - instance.display_name.is_some(), - "Expected display_name to be Some" - ); + assert!(instance.display_name.is_some(), "Expected display_name to be Some"); assert_eq!(instance.display_name.as_ref().unwrap(), &"Basic Prompt"); - assert!( - instance.description.is_some(), - "Expected description to be Some" - ); - assert_eq!( - instance.description.as_ref().unwrap(), - &"A basic prompt that uses the GPT-3 chat API to answer questions" - ); - assert!( - instance.instructions.is_some(), - "Expected instructions to be Some" - ); - assert_eq!( - instance.instructions.as_ref().unwrap(), - &"system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" - ); + assert!(instance.description.is_some(), "Expected description to be Some"); + assert_eq!(instance.description.as_ref().unwrap(), &"A basic prompt that uses the GPT-3 chat API to answer questions"); + assert!(instance.instructions.is_some(), "Expected instructions to be Some"); + assert_eq!(instance.instructions.as_ref().unwrap(), &"system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}"); } #[test] @@ -457,25 +396,12 @@ instructions: "system: "####; let ctx = LoadContext::default(); let result = Prompty::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.name, "basic-prompt"); - assert!( - instance.display_name.is_some(), - "Expected display_name to be Some" - ); - assert!( - instance.description.is_some(), - "Expected description to be Some" - ); - assert!( - instance.instructions.is_some(), - "Expected instructions to be Some" - ); + assert!(instance.display_name.is_some(), "Expected display_name to be Some"); + assert!(instance.description.is_some(), "Expected description to be Some"); + assert!(instance.instructions.is_some(), "Expected instructions to be Some"); } #[test] @@ -552,11 +478,7 @@ fn test_prompty_roundtrip_1() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } #[test] @@ -631,34 +553,15 @@ fn test_prompty_load_json_2() { "####; let ctx = LoadContext::default(); let result = Prompty::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.name, "basic-prompt"); - assert!( - instance.display_name.is_some(), - "Expected display_name to be Some" - ); + assert!(instance.display_name.is_some(), "Expected display_name to be Some"); assert_eq!(instance.display_name.as_ref().unwrap(), &"Basic Prompt"); - assert!( - instance.description.is_some(), - "Expected description to be Some" - ); - assert_eq!( - instance.description.as_ref().unwrap(), - &"A basic prompt that uses the GPT-3 chat API to answer questions" - ); - assert!( - instance.instructions.is_some(), - "Expected instructions to be Some" - ); - assert_eq!( - instance.instructions.as_ref().unwrap(), - &"system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" - ); + assert!(instance.description.is_some(), "Expected description to be Some"); + assert_eq!(instance.description.as_ref().unwrap(), &"A basic prompt that uses the GPT-3 chat API to answer questions"); + assert!(instance.instructions.is_some(), "Expected instructions to be Some"); + assert_eq!(instance.instructions.as_ref().unwrap(), &"system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}"); } #[test] @@ -732,25 +635,12 @@ instructions: "system: "####; let ctx = LoadContext::default(); let result = Prompty::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.name, "basic-prompt"); - assert!( - instance.display_name.is_some(), - "Expected display_name to be Some" - ); - assert!( - instance.description.is_some(), - "Expected description to be Some" - ); - assert!( - instance.instructions.is_some(), - "Expected instructions to be Some" - ); + assert!(instance.display_name.is_some(), "Expected display_name to be Some"); + assert!(instance.description.is_some(), "Expected description to be Some"); + assert!(instance.instructions.is_some(), "Expected instructions to be Some"); } #[test] @@ -829,11 +719,7 @@ fn test_prompty_roundtrip_2() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } #[test] @@ -907,34 +793,15 @@ fn test_prompty_load_json_3() { "####; let ctx = LoadContext::default(); let result = Prompty::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.name, "basic-prompt"); - assert!( - instance.display_name.is_some(), - "Expected display_name to be Some" - ); + assert!(instance.display_name.is_some(), "Expected display_name to be Some"); assert_eq!(instance.display_name.as_ref().unwrap(), &"Basic Prompt"); - assert!( - instance.description.is_some(), - "Expected description to be Some" - ); - assert_eq!( - instance.description.as_ref().unwrap(), - &"A basic prompt that uses the GPT-3 chat API to answer questions" - ); - assert!( - instance.instructions.is_some(), - "Expected instructions to be Some" - ); - assert_eq!( - instance.instructions.as_ref().unwrap(), - &"system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" - ); + assert!(instance.description.is_some(), "Expected description to be Some"); + assert_eq!(instance.description.as_ref().unwrap(), &"A basic prompt that uses the GPT-3 chat API to answer questions"); + assert!(instance.instructions.is_some(), "Expected instructions to be Some"); + assert_eq!(instance.instructions.as_ref().unwrap(), &"system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}"); } #[test] @@ -1008,25 +875,12 @@ instructions: "system: "####; let ctx = LoadContext::default(); let result = Prompty::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.name, "basic-prompt"); - assert!( - instance.display_name.is_some(), - "Expected display_name to be Some" - ); - assert!( - instance.description.is_some(), - "Expected description to be Some" - ); - assert!( - instance.instructions.is_some(), - "Expected instructions to be Some" - ); + assert!(instance.display_name.is_some(), "Expected display_name to be Some"); + assert!(instance.description.is_some(), "Expected description to be Some"); + assert!(instance.instructions.is_some(), "Expected instructions to be Some"); } #[test] @@ -1104,11 +958,7 @@ fn test_prompty_roundtrip_3() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } #[test] @@ -1185,34 +1035,15 @@ fn test_prompty_load_json_4() { "####; let ctx = LoadContext::default(); let result = Prompty::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.name, "basic-prompt"); - assert!( - instance.display_name.is_some(), - "Expected display_name to be Some" - ); + assert!(instance.display_name.is_some(), "Expected display_name to be Some"); assert_eq!(instance.display_name.as_ref().unwrap(), &"Basic Prompt"); - assert!( - instance.description.is_some(), - "Expected description to be Some" - ); - assert_eq!( - instance.description.as_ref().unwrap(), - &"A basic prompt that uses the GPT-3 chat API to answer questions" - ); - assert!( - instance.instructions.is_some(), - "Expected instructions to be Some" - ); - assert_eq!( - instance.instructions.as_ref().unwrap(), - &"system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" - ); + assert!(instance.description.is_some(), "Expected description to be Some"); + assert_eq!(instance.description.as_ref().unwrap(), &"A basic prompt that uses the GPT-3 chat API to answer questions"); + assert!(instance.instructions.is_some(), "Expected instructions to be Some"); + assert_eq!(instance.instructions.as_ref().unwrap(), &"system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}"); } #[test] @@ -1286,25 +1117,12 @@ instructions: "system: "####; let ctx = LoadContext::default(); let result = Prompty::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.name, "basic-prompt"); - assert!( - instance.display_name.is_some(), - "Expected display_name to be Some" - ); - assert!( - instance.description.is_some(), - "Expected description to be Some" - ); - assert!( - instance.instructions.is_some(), - "Expected instructions to be Some" - ); + assert!(instance.display_name.is_some(), "Expected display_name to be Some"); + assert!(instance.description.is_some(), "Expected description to be Some"); + assert!(instance.instructions.is_some(), "Expected instructions to be Some"); } #[test] @@ -1385,11 +1203,7 @@ fn test_prompty_roundtrip_4() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } #[test] @@ -1465,34 +1279,15 @@ fn test_prompty_load_json_5() { "####; let ctx = LoadContext::default(); let result = Prompty::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.name, "basic-prompt"); - assert!( - instance.display_name.is_some(), - "Expected display_name to be Some" - ); + assert!(instance.display_name.is_some(), "Expected display_name to be Some"); assert_eq!(instance.display_name.as_ref().unwrap(), &"Basic Prompt"); - assert!( - instance.description.is_some(), - "Expected description to be Some" - ); - assert_eq!( - instance.description.as_ref().unwrap(), - &"A basic prompt that uses the GPT-3 chat API to answer questions" - ); - assert!( - instance.instructions.is_some(), - "Expected instructions to be Some" - ); - assert_eq!( - instance.instructions.as_ref().unwrap(), - &"system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" - ); + assert!(instance.description.is_some(), "Expected description to be Some"); + assert_eq!(instance.description.as_ref().unwrap(), &"A basic prompt that uses the GPT-3 chat API to answer questions"); + assert!(instance.instructions.is_some(), "Expected instructions to be Some"); + assert_eq!(instance.instructions.as_ref().unwrap(), &"system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}"); } #[test] @@ -1566,25 +1361,12 @@ instructions: "system: "####; let ctx = LoadContext::default(); let result = Prompty::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.name, "basic-prompt"); - assert!( - instance.display_name.is_some(), - "Expected display_name to be Some" - ); - assert!( - instance.description.is_some(), - "Expected description to be Some" - ); - assert!( - instance.instructions.is_some(), - "Expected instructions to be Some" - ); + assert!(instance.display_name.is_some(), "Expected display_name to be Some"); + assert!(instance.description.is_some(), "Expected description to be Some"); + assert!(instance.instructions.is_some(), "Expected instructions to be Some"); } #[test] @@ -1664,11 +1446,7 @@ fn test_prompty_roundtrip_5() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } #[test] @@ -1746,34 +1524,15 @@ fn test_prompty_load_json_6() { "####; let ctx = LoadContext::default(); let result = Prompty::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.name, "basic-prompt"); - assert!( - instance.display_name.is_some(), - "Expected display_name to be Some" - ); + assert!(instance.display_name.is_some(), "Expected display_name to be Some"); assert_eq!(instance.display_name.as_ref().unwrap(), &"Basic Prompt"); - assert!( - instance.description.is_some(), - "Expected description to be Some" - ); - assert_eq!( - instance.description.as_ref().unwrap(), - &"A basic prompt that uses the GPT-3 chat API to answer questions" - ); - assert!( - instance.instructions.is_some(), - "Expected instructions to be Some" - ); - assert_eq!( - instance.instructions.as_ref().unwrap(), - &"system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" - ); + assert!(instance.description.is_some(), "Expected description to be Some"); + assert_eq!(instance.description.as_ref().unwrap(), &"A basic prompt that uses the GPT-3 chat API to answer questions"); + assert!(instance.instructions.is_some(), "Expected instructions to be Some"); + assert_eq!(instance.instructions.as_ref().unwrap(), &"system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}"); } #[test] @@ -1847,25 +1606,12 @@ instructions: "system: "####; let ctx = LoadContext::default(); let result = Prompty::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.name, "basic-prompt"); - assert!( - instance.display_name.is_some(), - "Expected display_name to be Some" - ); - assert!( - instance.description.is_some(), - "Expected description to be Some" - ); - assert!( - instance.instructions.is_some(), - "Expected instructions to be Some" - ); + assert!(instance.display_name.is_some(), "Expected display_name to be Some"); + assert!(instance.description.is_some(), "Expected description to be Some"); + assert!(instance.instructions.is_some(), "Expected instructions to be Some"); } #[test] @@ -1947,11 +1693,7 @@ fn test_prompty_roundtrip_6() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } #[test] @@ -2028,34 +1770,15 @@ fn test_prompty_load_json_7() { "####; let ctx = LoadContext::default(); let result = Prompty::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.name, "basic-prompt"); - assert!( - instance.display_name.is_some(), - "Expected display_name to be Some" - ); + assert!(instance.display_name.is_some(), "Expected display_name to be Some"); assert_eq!(instance.display_name.as_ref().unwrap(), &"Basic Prompt"); - assert!( - instance.description.is_some(), - "Expected description to be Some" - ); - assert_eq!( - instance.description.as_ref().unwrap(), - &"A basic prompt that uses the GPT-3 chat API to answer questions" - ); - assert!( - instance.instructions.is_some(), - "Expected instructions to be Some" - ); - assert_eq!( - instance.instructions.as_ref().unwrap(), - &"system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" - ); + assert!(instance.description.is_some(), "Expected description to be Some"); + assert_eq!(instance.description.as_ref().unwrap(), &"A basic prompt that uses the GPT-3 chat API to answer questions"); + assert!(instance.instructions.is_some(), "Expected instructions to be Some"); + assert_eq!(instance.instructions.as_ref().unwrap(), &"system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}"); } #[test] @@ -2129,25 +1852,12 @@ instructions: "system: "####; let ctx = LoadContext::default(); let result = Prompty::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.name, "basic-prompt"); - assert!( - instance.display_name.is_some(), - "Expected display_name to be Some" - ); - assert!( - instance.description.is_some(), - "Expected description to be Some" - ); - assert!( - instance.instructions.is_some(), - "Expected instructions to be Some" - ); + assert!(instance.display_name.is_some(), "Expected display_name to be Some"); + assert!(instance.description.is_some(), "Expected description to be Some"); + assert!(instance.instructions.is_some(), "Expected instructions to be Some"); } #[test] @@ -2228,9 +1938,5 @@ fn test_prompty_roundtrip_7() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } diff --git a/runtime/rust/prompty/tests/model/connection/connection_test.rs b/runtime/rust/prompty/tests/model/connection/connection_test.rs index c2c2c2bf..761b394c 100644 --- a/runtime/rust/prompty/tests/model/connection/connection_test.rs +++ b/runtime/rust/prompty/tests/model/connection/connection_test.rs @@ -1,15 +1,9 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] -use prompty::model::AuthenticationMode; use prompty::model::Connection; +use prompty::model::AuthenticationMode; use prompty::model::context::{LoadContext, SaveContext}; #[test] @@ -23,11 +17,7 @@ fn test_connection_load_json() { "####; let ctx = LoadContext::default(); let result = Connection::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); } #[test] @@ -40,11 +30,7 @@ usageDescription: This will allow the agent to respond to an email on your behal "####; let ctx = LoadContext::default(); let result = Connection::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); } #[test] diff --git a/runtime/rust/prompty/tests/model/connection/mod.rs b/runtime/rust/prompty/tests/model/connection/mod.rs index fd60e9df..93848f6f 100644 --- a/runtime/rust/prompty/tests/model/connection/mod.rs +++ b/runtime/rust/prompty/tests/model/connection/mod.rs @@ -1,11 +1,5 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] mod connection_test; diff --git a/runtime/rust/prompty/tests/model/conversation/content_part_test.rs b/runtime/rust/prompty/tests/model/conversation/content_part_test.rs index 74221529..c0b31726 100644 --- a/runtime/rust/prompty/tests/model/conversation/content_part_test.rs +++ b/runtime/rust/prompty/tests/model/conversation/content_part_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::ContentPart; use prompty::model::context::{LoadContext, SaveContext}; diff --git a/runtime/rust/prompty/tests/model/conversation/message_test.rs b/runtime/rust/prompty/tests/model/conversation/message_test.rs index 293b666a..1f6d48e7 100644 --- a/runtime/rust/prompty/tests/model/conversation/message_test.rs +++ b/runtime/rust/prompty/tests/model/conversation/message_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::Message; use prompty::model::Role; @@ -30,11 +24,7 @@ fn test_message_load_json() { "####; let ctx = LoadContext::default(); let result = Message::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.role, Role::User); } @@ -52,11 +42,7 @@ metadata: "####; let ctx = LoadContext::default(); let result = Message::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.role, Role::User); } @@ -83,11 +69,7 @@ fn test_message_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } #[test] diff --git a/runtime/rust/prompty/tests/model/conversation/mod.rs b/runtime/rust/prompty/tests/model/conversation/mod.rs index 467f9b60..d53dcc22 100644 --- a/runtime/rust/prompty/tests/model/conversation/mod.rs +++ b/runtime/rust/prompty/tests/model/conversation/mod.rs @@ -1,15 +1,9 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] mod content_part_test; mod message_test; -mod thread_marker_test; -mod tool_call_test; mod tool_result_test; +mod tool_call_test; +mod thread_marker_test; diff --git a/runtime/rust/prompty/tests/model/conversation/thread_marker_test.rs b/runtime/rust/prompty/tests/model/conversation/thread_marker_test.rs index 30c3b0b9..172951e7 100644 --- a/runtime/rust/prompty/tests/model/conversation/thread_marker_test.rs +++ b/runtime/rust/prompty/tests/model/conversation/thread_marker_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::ThreadMarker; use prompty::model::context::{LoadContext, SaveContext}; @@ -21,11 +15,7 @@ fn test_thread_marker_load_json() { "####; let ctx = LoadContext::default(); let result = ThreadMarker::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.name, "thread"); assert_eq!(instance.kind, "thread"); @@ -40,11 +30,7 @@ kind: thread "####; let ctx = LoadContext::default(); let result = ThreadMarker::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.name, "thread"); assert_eq!(instance.kind, "thread"); @@ -64,9 +50,5 @@ fn test_thread_marker_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } diff --git a/runtime/rust/prompty/tests/model/conversation/tool_call_test.rs b/runtime/rust/prompty/tests/model/conversation/tool_call_test.rs index 5f95a39e..e7496125 100644 --- a/runtime/rust/prompty/tests/model/conversation/tool_call_test.rs +++ b/runtime/rust/prompty/tests/model/conversation/tool_call_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::ToolCall; use prompty::model::context::{LoadContext, SaveContext}; @@ -22,11 +16,7 @@ fn test_tool_call_load_json() { "####; let ctx = LoadContext::default(); let result = ToolCall::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.id, "call_abc123"); assert_eq!(instance.name, "get_weather"); @@ -43,11 +33,7 @@ arguments: "{\"city\": \"Paris\"}" "####; let ctx = LoadContext::default(); let result = ToolCall::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.id, "call_abc123"); assert_eq!(instance.name, "get_weather"); @@ -69,9 +55,5 @@ fn test_tool_call_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } diff --git a/runtime/rust/prompty/tests/model/conversation/tool_result_test.rs b/runtime/rust/prompty/tests/model/conversation/tool_result_test.rs index fb3d8779..8ecb3460 100644 --- a/runtime/rust/prompty/tests/model/conversation/tool_result_test.rs +++ b/runtime/rust/prompty/tests/model/conversation/tool_result_test.rs @@ -1,14 +1,9 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::ToolResult; +use prompty::model::ToolResultStatus; use prompty::model::context::{LoadContext, SaveContext}; #[test] @@ -20,18 +15,22 @@ fn test_tool_result_load_json() { "kind": "text", "value": "72°F and sunny" } - ] + ], + "errorKind": "missing_tool", + "errorMessage": "Tool 'get_weather' is not registered", + "durationMs": 42 } "####; let ctx = LoadContext::default(); let result = ToolResult::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); - let _ = instance; // load succeeded, no scalar properties to validate + assert!(instance.error_kind.is_some(), "Expected error_kind to be Some"); + assert_eq!(instance.error_kind.as_ref().unwrap(), &"missing_tool"); + assert!(instance.error_message.is_some(), "Expected error_message to be Some"); + assert_eq!(instance.error_message.as_ref().unwrap(), &"Tool 'get_weather' is not registered"); + assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); + assert_eq!(instance.duration_ms.as_ref().unwrap(), &42.0); } #[test] @@ -40,17 +39,18 @@ fn test_tool_result_load_yaml() { parts: - kind: text value: 72°F and sunny +errorKind: missing_tool +errorMessage: Tool 'get_weather' is not registered +durationMs: 42 "####; let ctx = LoadContext::default(); let result = ToolResult::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); - let _ = instance; // load succeeded, no scalar properties to validate + assert!(instance.error_kind.is_some(), "Expected error_kind to be Some"); + assert!(instance.error_message.is_some(), "Expected error_message to be Some"); + assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); } #[test] @@ -62,7 +62,10 @@ fn test_tool_result_roundtrip() { "kind": "text", "value": "72°F and sunny" } - ] + ], + "errorKind": "missing_tool", + "errorMessage": "Tool 'get_weather' is not registered", + "durationMs": 42 } "####; let load_ctx = LoadContext::default(); @@ -71,11 +74,7 @@ fn test_tool_result_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } #[test] diff --git a/runtime/rust/prompty/tests/model/core/file_not_found_error_test.rs b/runtime/rust/prompty/tests/model/core/file_not_found_error_test.rs index b0c3ac2b..0feaca97 100644 --- a/runtime/rust/prompty/tests/model/core/file_not_found_error_test.rs +++ b/runtime/rust/prompty/tests/model/core/file_not_found_error_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::FileNotFoundError; use prompty::model::context::{LoadContext, SaveContext}; @@ -21,11 +15,7 @@ fn test_file_not_found_error_load_json() { "####; let ctx = LoadContext::default(); let result = FileNotFoundError::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.message, "Prompty file not found: ./chat.prompty"); assert_eq!(instance.path, "./chat.prompty"); @@ -40,11 +30,7 @@ path: ./chat.prompty "####; let ctx = LoadContext::default(); let result = FileNotFoundError::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.message, "Prompty file not found: ./chat.prompty"); assert_eq!(instance.path, "./chat.prompty"); @@ -64,9 +50,5 @@ fn test_file_not_found_error_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } diff --git a/runtime/rust/prompty/tests/model/core/invoker_error_test.rs b/runtime/rust/prompty/tests/model/core/invoker_error_test.rs index bd9317e8..3c77c610 100644 --- a/runtime/rust/prompty/tests/model/core/invoker_error_test.rs +++ b/runtime/rust/prompty/tests/model/core/invoker_error_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::InvokerError; use prompty::model::context::{LoadContext, SaveContext}; @@ -22,11 +16,7 @@ fn test_invoker_error_load_json() { "####; let ctx = LoadContext::default(); let result = InvokerError::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.message, "No renderer registered for key: jinja2"); assert_eq!(instance.component, "renderer"); @@ -43,11 +33,7 @@ key: jinja2 "####; let ctx = LoadContext::default(); let result = InvokerError::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.message, "No renderer registered for key: jinja2"); assert_eq!(instance.component, "renderer"); @@ -69,9 +55,5 @@ fn test_invoker_error_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } diff --git a/runtime/rust/prompty/tests/model/core/mod.rs b/runtime/rust/prompty/tests/model/core/mod.rs index 57c0ebca..8bebb9b8 100644 --- a/runtime/rust/prompty/tests/model/core/mod.rs +++ b/runtime/rust/prompty/tests/model/core/mod.rs @@ -1,15 +1,9 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] -mod file_not_found_error_test; -mod invoker_error_test; mod property_test; +mod invoker_error_test; mod validation_error_test; +mod file_not_found_error_test; mod validation_result_test; diff --git a/runtime/rust/prompty/tests/model/core/property_test.rs b/runtime/rust/prompty/tests/model/core/property_test.rs index 865f37fb..c7d50165 100644 --- a/runtime/rust/prompty/tests/model/core/property_test.rs +++ b/runtime/rust/prompty/tests/model/core/property_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::Property; use prompty::model::context::{LoadContext, SaveContext}; @@ -30,11 +24,7 @@ fn test_property_load_json() { "####; let ctx = LoadContext::default(); let result = Property::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); } #[test] @@ -54,11 +44,7 @@ enumValues: "####; let ctx = LoadContext::default(); let result = Property::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); } #[test] diff --git a/runtime/rust/prompty/tests/model/core/validation_error_test.rs b/runtime/rust/prompty/tests/model/core/validation_error_test.rs index 7d787508..453f5968 100644 --- a/runtime/rust/prompty/tests/model/core/validation_error_test.rs +++ b/runtime/rust/prompty/tests/model/core/validation_error_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::ValidationError; use prompty::model::context::{LoadContext, SaveContext}; @@ -22,11 +16,7 @@ fn test_validation_error_load_json() { "####; let ctx = LoadContext::default(); let result = ValidationError::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.message, "Missing required input: firstName"); assert_eq!(instance.property, "firstName"); @@ -43,11 +33,7 @@ constraint: required "####; let ctx = LoadContext::default(); let result = ValidationError::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.message, "Missing required input: firstName"); assert_eq!(instance.property, "firstName"); @@ -69,9 +55,5 @@ fn test_validation_error_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } diff --git a/runtime/rust/prompty/tests/model/core/validation_result_test.rs b/runtime/rust/prompty/tests/model/core/validation_result_test.rs index 2dbcf748..bcb1444a 100644 --- a/runtime/rust/prompty/tests/model/core/validation_result_test.rs +++ b/runtime/rust/prompty/tests/model/core/validation_result_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::ValidationResult; use prompty::model::context::{LoadContext, SaveContext}; @@ -21,11 +15,7 @@ fn test_validation_result_load_json() { "####; let ctx = LoadContext::default(); let result = ValidationResult::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.valid, true); } @@ -39,11 +29,7 @@ errors: [] "####; let ctx = LoadContext::default(); let result = ValidationResult::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.valid, true); } @@ -62,9 +48,5 @@ fn test_validation_result_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } diff --git a/runtime/rust/prompty/tests/model/events/compaction_complete_payload_test.rs b/runtime/rust/prompty/tests/model/events/compaction_complete_payload_test.rs index a867689c..7ad67317 100644 --- a/runtime/rust/prompty/tests/model/events/compaction_complete_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/compaction_complete_payload_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::CompactionCompletePayload; use prompty::model::context::{LoadContext, SaveContext}; @@ -16,19 +10,18 @@ fn test_compaction_complete_payload_load_json() { let json = r####" { "removed": 5, - "remaining": 3 + "remaining": 3, + "summaryLength": 1200 } "####; let ctx = LoadContext::default(); let result = CompactionCompletePayload::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.removed, 5); assert_eq!(instance.remaining, 3); + assert!(instance.summary_length.is_some(), "Expected summary_length to be Some"); + assert_eq!(instance.summary_length.as_ref().unwrap(), &1200); } #[test] @@ -36,18 +29,16 @@ fn test_compaction_complete_payload_load_yaml() { let yaml = r####" removed: 5 remaining: 3 +summaryLength: 1200 "####; let ctx = LoadContext::default(); let result = CompactionCompletePayload::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.removed, 5); assert_eq!(instance.remaining, 3); + assert!(instance.summary_length.is_some(), "Expected summary_length to be Some"); } #[test] @@ -55,7 +46,8 @@ fn test_compaction_complete_payload_roundtrip() { let json = r####" { "removed": 5, - "remaining": 3 + "remaining": 3, + "summaryLength": 1200 } "####; let load_ctx = LoadContext::default(); @@ -64,9 +56,5 @@ fn test_compaction_complete_payload_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } diff --git a/runtime/rust/prompty/tests/model/events/compaction_failed_payload_test.rs b/runtime/rust/prompty/tests/model/events/compaction_failed_payload_test.rs index 98236839..058cf2a5 100644 --- a/runtime/rust/prompty/tests/model/events/compaction_failed_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/compaction_failed_payload_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::CompactionFailedPayload; use prompty::model::context::{LoadContext, SaveContext}; @@ -20,16 +14,9 @@ fn test_compaction_failed_payload_load_json() { "####; let ctx = LoadContext::default(); let result = CompactionFailedPayload::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); - assert_eq!( - instance.message, - "Summarization prompt exceeded context window" - ); + assert_eq!(instance.message, "Summarization prompt exceeded context window"); } #[test] @@ -40,16 +27,9 @@ message: Summarization prompt exceeded context window "####; let ctx = LoadContext::default(); let result = CompactionFailedPayload::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); - assert_eq!( - instance.message, - "Summarization prompt exceeded context window" - ); + assert_eq!(instance.message, "Summarization prompt exceeded context window"); } #[test] @@ -65,9 +45,5 @@ fn test_compaction_failed_payload_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } diff --git a/runtime/rust/prompty/tests/model/events/compaction_start_payload_test.rs b/runtime/rust/prompty/tests/model/events/compaction_start_payload_test.rs new file mode 100644 index 00000000..1bd83c40 --- /dev/null +++ b/runtime/rust/prompty/tests/model/events/compaction_start_payload_test.rs @@ -0,0 +1,49 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use prompty::model::CompactionStartPayload; +use prompty::model::context::{LoadContext, SaveContext}; + +#[test] +fn test_compaction_start_payload_load_json() { + let json = r####" +{ + "droppedCount": 5 +} +"####; + let ctx = LoadContext::default(); + let result = CompactionStartPayload::from_json(json, &ctx); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + let instance = result.unwrap(); + assert_eq!(instance.dropped_count, 5); +} + +#[test] +fn test_compaction_start_payload_load_yaml() { + let yaml = r####" +droppedCount: 5 + +"####; + let ctx = LoadContext::default(); + let result = CompactionStartPayload::from_yaml(yaml, &ctx); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + let instance = result.unwrap(); + assert_eq!(instance.dropped_count, 5); +} + +#[test] +fn test_compaction_start_payload_roundtrip() { + let json = r####" +{ + "droppedCount": 5 +} +"####; + let load_ctx = LoadContext::default(); + let result = CompactionStartPayload::from_json(json, &load_ctx); + assert!(result.is_ok(), "Failed to load: {:?}", result.err()); + let instance = result.unwrap(); + let save_ctx = SaveContext::default(); + let json_output = instance.to_json(&save_ctx); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); +} diff --git a/runtime/rust/prompty/tests/model/events/done_event_payload_test.rs b/runtime/rust/prompty/tests/model/events/done_event_payload_test.rs index 23a08864..709546f2 100644 --- a/runtime/rust/prompty/tests/model/events/done_event_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/done_event_payload_test.rs @@ -1,67 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::DoneEventPayload; use prompty::model::context::{LoadContext, SaveContext}; - -#[test] -fn test_done_event_payload_load_json() { - let json = r####" -{ - "response": "The weather in Paris is 72°F and sunny." -} -"####; - let ctx = LoadContext::default(); - let result = DoneEventPayload::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); - let instance = result.unwrap(); - assert_eq!(instance.response, "The weather in Paris is 72°F and sunny."); -} - -#[test] -fn test_done_event_payload_load_yaml() { - let yaml = r####" -response: The weather in Paris is 72°F and sunny. - -"####; - let ctx = LoadContext::default(); - let result = DoneEventPayload::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); - let instance = result.unwrap(); - assert_eq!(instance.response, "The weather in Paris is 72°F and sunny."); -} - -#[test] -fn test_done_event_payload_roundtrip() { - let json = r####" -{ - "response": "The weather in Paris is 72°F and sunny." -} -"####; - let load_ctx = LoadContext::default(); - let result = DoneEventPayload::from_json(json, &load_ctx); - assert!(result.is_ok(), "Failed to load: {:?}", result.err()); - let instance = result.unwrap(); - let save_ctx = SaveContext::default(); - let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); -} diff --git a/runtime/rust/prompty/tests/model/events/error_event_payload_test.rs b/runtime/rust/prompty/tests/model/events/error_event_payload_test.rs index 12420089..ad6c1a09 100644 --- a/runtime/rust/prompty/tests/model/events/error_event_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/error_event_payload_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::ErrorEventPayload; use prompty::model::context::{LoadContext, SaveContext}; @@ -15,42 +9,46 @@ use prompty::model::context::{LoadContext, SaveContext}; fn test_error_event_payload_load_json() { let json = r####" { - "message": "Rate limit exceeded" + "message": "Rate limit exceeded", + "errorKind": "rate_limit", + "phase": "llm" } "####; let ctx = LoadContext::default(); let result = ErrorEventPayload::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.message, "Rate limit exceeded"); + assert!(instance.error_kind.is_some(), "Expected error_kind to be Some"); + assert_eq!(instance.error_kind.as_ref().unwrap(), &"rate_limit"); + assert!(instance.phase.is_some(), "Expected phase to be Some"); + assert_eq!(instance.phase.as_ref().unwrap(), &"llm"); } #[test] fn test_error_event_payload_load_yaml() { let yaml = r####" message: Rate limit exceeded +errorKind: rate_limit +phase: llm "####; let ctx = LoadContext::default(); let result = ErrorEventPayload::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.message, "Rate limit exceeded"); + assert!(instance.error_kind.is_some(), "Expected error_kind to be Some"); + assert!(instance.phase.is_some(), "Expected phase to be Some"); } #[test] fn test_error_event_payload_roundtrip() { let json = r####" { - "message": "Rate limit exceeded" + "message": "Rate limit exceeded", + "errorKind": "rate_limit", + "phase": "llm" } "####; let load_ctx = LoadContext::default(); @@ -59,9 +57,5 @@ fn test_error_event_payload_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } diff --git a/runtime/rust/prompty/tests/model/events/llm_complete_payload_test.rs b/runtime/rust/prompty/tests/model/events/llm_complete_payload_test.rs new file mode 100644 index 00000000..986a82f1 --- /dev/null +++ b/runtime/rust/prompty/tests/model/events/llm_complete_payload_test.rs @@ -0,0 +1,62 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use prompty::model::LlmCompletePayload; +use prompty::model::context::{LoadContext, SaveContext}; + +#[test] +fn test_llm_complete_payload_load_json() { + let json = r####" +{ + "requestId": "req_abc123", + "serviceRequestId": "srv_abc123", + "durationMs": 820 +} +"####; + let ctx = LoadContext::default(); + let result = LlmCompletePayload::from_json(json, &ctx); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + let instance = result.unwrap(); + assert!(instance.request_id.is_some(), "Expected request_id to be Some"); + assert_eq!(instance.request_id.as_ref().unwrap(), &"req_abc123"); + assert!(instance.service_request_id.is_some(), "Expected service_request_id to be Some"); + assert_eq!(instance.service_request_id.as_ref().unwrap(), &"srv_abc123"); + assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); + assert_eq!(instance.duration_ms.as_ref().unwrap(), &820.0); +} + +#[test] +fn test_llm_complete_payload_load_yaml() { + let yaml = r####" +requestId: req_abc123 +serviceRequestId: srv_abc123 +durationMs: 820 + +"####; + let ctx = LoadContext::default(); + let result = LlmCompletePayload::from_yaml(yaml, &ctx); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + let instance = result.unwrap(); + assert!(instance.request_id.is_some(), "Expected request_id to be Some"); + assert!(instance.service_request_id.is_some(), "Expected service_request_id to be Some"); + assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); +} + +#[test] +fn test_llm_complete_payload_roundtrip() { + let json = r####" +{ + "requestId": "req_abc123", + "serviceRequestId": "srv_abc123", + "durationMs": 820 +} +"####; + let load_ctx = LoadContext::default(); + let result = LlmCompletePayload::from_json(json, &load_ctx); + assert!(result.is_ok(), "Failed to load: {:?}", result.err()); + let instance = result.unwrap(); + let save_ctx = SaveContext::default(); + let json_output = instance.to_json(&save_ctx); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); +} diff --git a/runtime/rust/prompty/tests/model/events/llm_start_payload_test.rs b/runtime/rust/prompty/tests/model/events/llm_start_payload_test.rs new file mode 100644 index 00000000..04668742 --- /dev/null +++ b/runtime/rust/prompty/tests/model/events/llm_start_payload_test.rs @@ -0,0 +1,68 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use prompty::model::LlmStartPayload; +use prompty::model::context::{LoadContext, SaveContext}; + +#[test] +fn test_llm_start_payload_load_json() { + let json = r####" +{ + "provider": "openai", + "modelId": "gpt-4o-mini", + "messageCount": 4, + "attempt": 0 +} +"####; + let ctx = LoadContext::default(); + let result = LlmStartPayload::from_json(json, &ctx); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + let instance = result.unwrap(); + assert!(instance.provider.is_some(), "Expected provider to be Some"); + assert_eq!(instance.provider.as_ref().unwrap(), &"openai"); + assert!(instance.model_id.is_some(), "Expected model_id to be Some"); + assert_eq!(instance.model_id.as_ref().unwrap(), &"gpt-4o-mini"); + assert!(instance.message_count.is_some(), "Expected message_count to be Some"); + assert_eq!(instance.message_count.as_ref().unwrap(), &4); + assert!(instance.attempt.is_some(), "Expected attempt to be Some"); + assert_eq!(instance.attempt.as_ref().unwrap(), &0); +} + +#[test] +fn test_llm_start_payload_load_yaml() { + let yaml = r####" +provider: openai +modelId: gpt-4o-mini +messageCount: 4 +attempt: 0 + +"####; + let ctx = LoadContext::default(); + let result = LlmStartPayload::from_yaml(yaml, &ctx); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + let instance = result.unwrap(); + assert!(instance.provider.is_some(), "Expected provider to be Some"); + assert!(instance.model_id.is_some(), "Expected model_id to be Some"); + assert!(instance.message_count.is_some(), "Expected message_count to be Some"); + assert!(instance.attempt.is_some(), "Expected attempt to be Some"); +} + +#[test] +fn test_llm_start_payload_roundtrip() { + let json = r####" +{ + "provider": "openai", + "modelId": "gpt-4o-mini", + "messageCount": 4, + "attempt": 0 +} +"####; + let load_ctx = LoadContext::default(); + let result = LlmStartPayload::from_json(json, &load_ctx); + assert!(result.is_ok(), "Failed to load: {:?}", result.err()); + let instance = result.unwrap(); + let save_ctx = SaveContext::default(); + let json_output = instance.to_json(&save_ctx); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); +} diff --git a/runtime/rust/prompty/tests/model/events/messages_updated_payload_test.rs b/runtime/rust/prompty/tests/model/events/messages_updated_payload_test.rs index 5709537b..a8610e58 100644 --- a/runtime/rust/prompty/tests/model/events/messages_updated_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/messages_updated_payload_test.rs @@ -1,12 +1,56 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::MessagesUpdatedPayload; use prompty::model::context::{LoadContext, SaveContext}; + +#[test] +fn test_messages_updated_payload_load_json() { + let json = r####" +{ + "reason": "tool_results", + "removed": 2 +} +"####; + let ctx = LoadContext::default(); + let result = MessagesUpdatedPayload::from_json(json, &ctx); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + let instance = result.unwrap(); + assert!(instance.reason.is_some(), "Expected reason to be Some"); + assert_eq!(instance.reason.as_ref().unwrap(), &"tool_results"); + assert!(instance.removed.is_some(), "Expected removed to be Some"); + assert_eq!(instance.removed.as_ref().unwrap(), &2); +} + +#[test] +fn test_messages_updated_payload_load_yaml() { + let yaml = r####" +reason: tool_results +removed: 2 + +"####; + let ctx = LoadContext::default(); + let result = MessagesUpdatedPayload::from_yaml(yaml, &ctx); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + let instance = result.unwrap(); + assert!(instance.reason.is_some(), "Expected reason to be Some"); + assert!(instance.removed.is_some(), "Expected removed to be Some"); +} + +#[test] +fn test_messages_updated_payload_roundtrip() { + let json = r####" +{ + "reason": "tool_results", + "removed": 2 +} +"####; + let load_ctx = LoadContext::default(); + let result = MessagesUpdatedPayload::from_json(json, &load_ctx); + assert!(result.is_ok(), "Failed to load: {:?}", result.err()); + let instance = result.unwrap(); + let save_ctx = SaveContext::default(); + let json_output = instance.to_json(&save_ctx); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); +} diff --git a/runtime/rust/prompty/tests/model/events/mod.rs b/runtime/rust/prompty/tests/model/events/mod.rs index 0cb7b90e..41ed2c8c 100644 --- a/runtime/rust/prompty/tests/model/events/mod.rs +++ b/runtime/rust/prompty/tests/model/events/mod.rs @@ -1,21 +1,27 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] -mod compaction_complete_payload_test; -mod compaction_failed_payload_test; -mod done_event_payload_test; -mod error_event_payload_test; -mod messages_updated_payload_test; -mod status_event_payload_test; -mod stream_chunk_test; -mod thinking_event_payload_test; +mod turn_event_test; +mod turn_start_payload_test; +mod turn_end_payload_test; +mod llm_start_payload_test; +mod llm_complete_payload_test; +mod retry_payload_test; +mod permission_requested_payload_test; +mod permission_completed_payload_test; mod token_event_payload_test; +mod thinking_event_payload_test; mod tool_call_start_payload_test; +mod tool_call_complete_payload_test; mod tool_result_payload_test; +mod status_event_payload_test; +mod messages_updated_payload_test; +mod done_event_payload_test; +mod error_event_payload_test; +mod compaction_start_payload_test; +mod compaction_complete_payload_test; +mod compaction_failed_payload_test; +mod turn_summary_test; +mod turn_trace_test; +mod stream_chunk_test; diff --git a/runtime/rust/prompty/tests/model/events/permission_completed_payload_test.rs b/runtime/rust/prompty/tests/model/events/permission_completed_payload_test.rs new file mode 100644 index 00000000..9bf890c0 --- /dev/null +++ b/runtime/rust/prompty/tests/model/events/permission_completed_payload_test.rs @@ -0,0 +1,60 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use prompty::model::PermissionCompletedPayload; +use prompty::model::context::{LoadContext, SaveContext}; + +#[test] +fn test_permission_completed_payload_load_json() { + let json = r####" +{ + "permission": "tool.execute", + "approved": true, + "reason": "user_approved" +} +"####; + let ctx = LoadContext::default(); + let result = PermissionCompletedPayload::from_json(json, &ctx); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + let instance = result.unwrap(); + assert_eq!(instance.permission, "tool.execute"); + assert_eq!(instance.approved, true); + assert!(instance.reason.is_some(), "Expected reason to be Some"); + assert_eq!(instance.reason.as_ref().unwrap(), &"user_approved"); +} + +#[test] +fn test_permission_completed_payload_load_yaml() { + let yaml = r####" +permission: tool.execute +approved: true +reason: user_approved + +"####; + let ctx = LoadContext::default(); + let result = PermissionCompletedPayload::from_yaml(yaml, &ctx); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + let instance = result.unwrap(); + assert_eq!(instance.permission, "tool.execute"); + assert_eq!(instance.approved, true); + assert!(instance.reason.is_some(), "Expected reason to be Some"); +} + +#[test] +fn test_permission_completed_payload_roundtrip() { + let json = r####" +{ + "permission": "tool.execute", + "approved": true, + "reason": "user_approved" +} +"####; + let load_ctx = LoadContext::default(); + let result = PermissionCompletedPayload::from_json(json, &load_ctx); + assert!(result.is_ok(), "Failed to load: {:?}", result.err()); + let instance = result.unwrap(); + let save_ctx = SaveContext::default(); + let json_output = instance.to_json(&save_ctx); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); +} diff --git a/runtime/rust/prompty/tests/model/events/permission_requested_payload_test.rs b/runtime/rust/prompty/tests/model/events/permission_requested_payload_test.rs new file mode 100644 index 00000000..bb3b74a5 --- /dev/null +++ b/runtime/rust/prompty/tests/model/events/permission_requested_payload_test.rs @@ -0,0 +1,55 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use prompty::model::PermissionRequestedPayload; +use prompty::model::context::{LoadContext, SaveContext}; + +#[test] +fn test_permission_requested_payload_load_json() { + let json = r####" +{ + "permission": "tool.execute", + "target": "shell" +} +"####; + let ctx = LoadContext::default(); + let result = PermissionRequestedPayload::from_json(json, &ctx); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + let instance = result.unwrap(); + assert_eq!(instance.permission, "tool.execute"); + assert!(instance.target.is_some(), "Expected target to be Some"); + assert_eq!(instance.target.as_ref().unwrap(), &"shell"); +} + +#[test] +fn test_permission_requested_payload_load_yaml() { + let yaml = r####" +permission: tool.execute +target: shell + +"####; + let ctx = LoadContext::default(); + let result = PermissionRequestedPayload::from_yaml(yaml, &ctx); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + let instance = result.unwrap(); + assert_eq!(instance.permission, "tool.execute"); + assert!(instance.target.is_some(), "Expected target to be Some"); +} + +#[test] +fn test_permission_requested_payload_roundtrip() { + let json = r####" +{ + "permission": "tool.execute", + "target": "shell" +} +"####; + let load_ctx = LoadContext::default(); + let result = PermissionRequestedPayload::from_json(json, &load_ctx); + assert!(result.is_ok(), "Failed to load: {:?}", result.err()); + let instance = result.unwrap(); + let save_ctx = SaveContext::default(); + let json_output = instance.to_json(&save_ctx); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); +} diff --git a/runtime/rust/prompty/tests/model/events/retry_payload_test.rs b/runtime/rust/prompty/tests/model/events/retry_payload_test.rs new file mode 100644 index 00000000..bf34585b --- /dev/null +++ b/runtime/rust/prompty/tests/model/events/retry_payload_test.rs @@ -0,0 +1,72 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use prompty::model::RetryPayload; +use prompty::model::context::{LoadContext, SaveContext}; + +#[test] +fn test_retry_payload_load_json() { + let json = r####" +{ + "operation": "llm", + "attempt": 2, + "maxAttempts": 3, + "delayMs": 1250, + "reason": "rate_limit" +} +"####; + let ctx = LoadContext::default(); + let result = RetryPayload::from_json(json, &ctx); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + let instance = result.unwrap(); + assert_eq!(instance.operation, "llm"); + assert_eq!(instance.attempt, 2); + assert!(instance.max_attempts.is_some(), "Expected max_attempts to be Some"); + assert_eq!(instance.max_attempts.as_ref().unwrap(), &3); + assert!(instance.delay_ms.is_some(), "Expected delay_ms to be Some"); + assert_eq!(instance.delay_ms.as_ref().unwrap(), &1250.0); + assert!(instance.reason.is_some(), "Expected reason to be Some"); + assert_eq!(instance.reason.as_ref().unwrap(), &"rate_limit"); +} + +#[test] +fn test_retry_payload_load_yaml() { + let yaml = r####" +operation: llm +attempt: 2 +maxAttempts: 3 +delayMs: 1250 +reason: rate_limit + +"####; + let ctx = LoadContext::default(); + let result = RetryPayload::from_yaml(yaml, &ctx); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + let instance = result.unwrap(); + assert_eq!(instance.operation, "llm"); + assert_eq!(instance.attempt, 2); + assert!(instance.max_attempts.is_some(), "Expected max_attempts to be Some"); + assert!(instance.delay_ms.is_some(), "Expected delay_ms to be Some"); + assert!(instance.reason.is_some(), "Expected reason to be Some"); +} + +#[test] +fn test_retry_payload_roundtrip() { + let json = r####" +{ + "operation": "llm", + "attempt": 2, + "maxAttempts": 3, + "delayMs": 1250, + "reason": "rate_limit" +} +"####; + let load_ctx = LoadContext::default(); + let result = RetryPayload::from_json(json, &load_ctx); + assert!(result.is_ok(), "Failed to load: {:?}", result.err()); + let instance = result.unwrap(); + let save_ctx = SaveContext::default(); + let json_output = instance.to_json(&save_ctx); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); +} diff --git a/runtime/rust/prompty/tests/model/events/status_event_payload_test.rs b/runtime/rust/prompty/tests/model/events/status_event_payload_test.rs index 7bc141ec..1b320341 100644 --- a/runtime/rust/prompty/tests/model/events/status_event_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/status_event_payload_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::StatusEventPayload; use prompty::model::context::{LoadContext, SaveContext}; @@ -20,11 +14,7 @@ fn test_status_event_payload_load_json() { "####; let ctx = LoadContext::default(); let result = StatusEventPayload::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.message, "Starting iteration 3"); } @@ -37,11 +27,7 @@ message: Starting iteration 3 "####; let ctx = LoadContext::default(); let result = StatusEventPayload::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.message, "Starting iteration 3"); } @@ -59,9 +45,5 @@ fn test_status_event_payload_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } diff --git a/runtime/rust/prompty/tests/model/events/stream_chunk_test.rs b/runtime/rust/prompty/tests/model/events/stream_chunk_test.rs index 084d6b29..efbdd847 100644 --- a/runtime/rust/prompty/tests/model/events/stream_chunk_test.rs +++ b/runtime/rust/prompty/tests/model/events/stream_chunk_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::StreamChunk; use prompty::model::context::{LoadContext, SaveContext}; diff --git a/runtime/rust/prompty/tests/model/events/thinking_event_payload_test.rs b/runtime/rust/prompty/tests/model/events/thinking_event_payload_test.rs index d2e7161e..9f257dbd 100644 --- a/runtime/rust/prompty/tests/model/events/thinking_event_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/thinking_event_payload_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::ThinkingEventPayload; use prompty::model::context::{LoadContext, SaveContext}; @@ -20,11 +14,7 @@ fn test_thinking_event_payload_load_json() { "####; let ctx = LoadContext::default(); let result = ThinkingEventPayload::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.token, "Let me consider..."); } @@ -37,11 +27,7 @@ token: Let me consider... "####; let ctx = LoadContext::default(); let result = ThinkingEventPayload::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.token, "Let me consider..."); } @@ -59,9 +45,5 @@ fn test_thinking_event_payload_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } diff --git a/runtime/rust/prompty/tests/model/events/token_event_payload_test.rs b/runtime/rust/prompty/tests/model/events/token_event_payload_test.rs index ef56b977..b9b18c7a 100644 --- a/runtime/rust/prompty/tests/model/events/token_event_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/token_event_payload_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::TokenEventPayload; use prompty::model::context::{LoadContext, SaveContext}; @@ -20,11 +14,7 @@ fn test_token_event_payload_load_json() { "####; let ctx = LoadContext::default(); let result = TokenEventPayload::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.token, "Hello"); } @@ -37,11 +27,7 @@ token: Hello "####; let ctx = LoadContext::default(); let result = TokenEventPayload::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.token, "Hello"); } @@ -59,9 +45,5 @@ fn test_token_event_payload_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } diff --git a/runtime/rust/prompty/tests/model/events/tool_call_complete_payload_test.rs b/runtime/rust/prompty/tests/model/events/tool_call_complete_payload_test.rs new file mode 100644 index 00000000..a63161a6 --- /dev/null +++ b/runtime/rust/prompty/tests/model/events/tool_call_complete_payload_test.rs @@ -0,0 +1,72 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use prompty::model::ToolCallCompletePayload; +use prompty::model::context::{LoadContext, SaveContext}; + +#[test] +fn test_tool_call_complete_payload_load_json() { + let json = r####" +{ + "id": "call_abc123", + "name": "get_weather", + "success": true, + "durationMs": 42, + "errorKind": "timeout" +} +"####; + let ctx = LoadContext::default(); + let result = ToolCallCompletePayload::from_json(json, &ctx); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + let instance = result.unwrap(); + assert!(instance.id.is_some(), "Expected id to be Some"); + assert_eq!(instance.id.as_ref().unwrap(), &"call_abc123"); + assert_eq!(instance.name, "get_weather"); + assert_eq!(instance.success, true); + assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); + assert_eq!(instance.duration_ms.as_ref().unwrap(), &42.0); + assert!(instance.error_kind.is_some(), "Expected error_kind to be Some"); + assert_eq!(instance.error_kind.as_ref().unwrap(), &"timeout"); +} + +#[test] +fn test_tool_call_complete_payload_load_yaml() { + let yaml = r####" +id: call_abc123 +name: get_weather +success: true +durationMs: 42 +errorKind: timeout + +"####; + let ctx = LoadContext::default(); + let result = ToolCallCompletePayload::from_yaml(yaml, &ctx); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + let instance = result.unwrap(); + assert!(instance.id.is_some(), "Expected id to be Some"); + assert_eq!(instance.name, "get_weather"); + assert_eq!(instance.success, true); + assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); + assert!(instance.error_kind.is_some(), "Expected error_kind to be Some"); +} + +#[test] +fn test_tool_call_complete_payload_roundtrip() { + let json = r####" +{ + "id": "call_abc123", + "name": "get_weather", + "success": true, + "durationMs": 42, + "errorKind": "timeout" +} +"####; + let load_ctx = LoadContext::default(); + let result = ToolCallCompletePayload::from_json(json, &load_ctx); + assert!(result.is_ok(), "Failed to load: {:?}", result.err()); + let instance = result.unwrap(); + let save_ctx = SaveContext::default(); + let json_output = instance.to_json(&save_ctx); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); +} diff --git a/runtime/rust/prompty/tests/model/events/tool_call_start_payload_test.rs b/runtime/rust/prompty/tests/model/events/tool_call_start_payload_test.rs index 84cf792a..0230af03 100644 --- a/runtime/rust/prompty/tests/model/events/tool_call_start_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/tool_call_start_payload_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::ToolCallStartPayload; use prompty::model::context::{LoadContext, SaveContext}; @@ -15,18 +9,17 @@ use prompty::model::context::{LoadContext, SaveContext}; fn test_tool_call_start_payload_load_json() { let json = r####" { + "id": "call_abc123", "name": "get_weather", "arguments": "{\"city\": \"Paris\"}" } "####; let ctx = LoadContext::default(); let result = ToolCallStartPayload::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); + assert!(instance.id.is_some(), "Expected id to be Some"); + assert_eq!(instance.id.as_ref().unwrap(), &"call_abc123"); assert_eq!(instance.name, "get_weather"); assert_eq!(instance.arguments, "{\"city\": \"Paris\"}"); } @@ -34,18 +27,16 @@ fn test_tool_call_start_payload_load_json() { #[test] fn test_tool_call_start_payload_load_yaml() { let yaml = r####" +id: call_abc123 name: get_weather arguments: "{\"city\": \"Paris\"}" "####; let ctx = LoadContext::default(); let result = ToolCallStartPayload::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); + assert!(instance.id.is_some(), "Expected id to be Some"); assert_eq!(instance.name, "get_weather"); assert_eq!(instance.arguments, "{\"city\": \"Paris\"}"); } @@ -54,6 +45,7 @@ arguments: "{\"city\": \"Paris\"}" fn test_tool_call_start_payload_roundtrip() { let json = r####" { + "id": "call_abc123", "name": "get_weather", "arguments": "{\"city\": \"Paris\"}" } @@ -64,9 +56,5 @@ fn test_tool_call_start_payload_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } diff --git a/runtime/rust/prompty/tests/model/events/tool_result_payload_test.rs b/runtime/rust/prompty/tests/model/events/tool_result_payload_test.rs index 43de3468..41b23d24 100644 --- a/runtime/rust/prompty/tests/model/events/tool_result_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/tool_result_payload_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::ToolResultPayload; use prompty::model::context::{LoadContext, SaveContext}; @@ -28,11 +22,7 @@ fn test_tool_result_payload_load_json() { "####; let ctx = LoadContext::default(); let result = ToolResultPayload::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.name, "get_weather"); } @@ -49,11 +39,7 @@ result: "####; let ctx = LoadContext::default(); let result = ToolResultPayload::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.name, "get_weather"); } @@ -79,9 +65,5 @@ fn test_tool_result_payload_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } diff --git a/runtime/rust/prompty/tests/model/events/turn_end_payload_test.rs b/runtime/rust/prompty/tests/model/events/turn_end_payload_test.rs new file mode 100644 index 00000000..76c884b0 --- /dev/null +++ b/runtime/rust/prompty/tests/model/events/turn_end_payload_test.rs @@ -0,0 +1,57 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use prompty::model::TurnEndPayload; +use prompty::model::TurnStatus; +use prompty::model::context::{LoadContext, SaveContext}; + +#[test] +fn test_turn_end_payload_load_json() { + let json = r####" +{ + "iterations": 2, + "durationMs": 1500 +} +"####; + let ctx = LoadContext::default(); + let result = TurnEndPayload::from_json(json, &ctx); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + let instance = result.unwrap(); + assert!(instance.iterations.is_some(), "Expected iterations to be Some"); + assert_eq!(instance.iterations.as_ref().unwrap(), &2); + assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); + assert_eq!(instance.duration_ms.as_ref().unwrap(), &1500.0); +} + +#[test] +fn test_turn_end_payload_load_yaml() { + let yaml = r####" +iterations: 2 +durationMs: 1500 + +"####; + let ctx = LoadContext::default(); + let result = TurnEndPayload::from_yaml(yaml, &ctx); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + let instance = result.unwrap(); + assert!(instance.iterations.is_some(), "Expected iterations to be Some"); + assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); +} + +#[test] +fn test_turn_end_payload_roundtrip() { + let json = r####" +{ + "iterations": 2, + "durationMs": 1500 +} +"####; + let load_ctx = LoadContext::default(); + let result = TurnEndPayload::from_json(json, &load_ctx); + assert!(result.is_ok(), "Failed to load: {:?}", result.err()); + let instance = result.unwrap(); + let save_ctx = SaveContext::default(); + let json_output = instance.to_json(&save_ctx); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); +} diff --git a/runtime/rust/prompty/tests/model/events/turn_event_test.rs b/runtime/rust/prompty/tests/model/events/turn_event_test.rs new file mode 100644 index 00000000..723d99ac --- /dev/null +++ b/runtime/rust/prompty/tests/model/events/turn_event_test.rs @@ -0,0 +1,79 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use prompty::model::TurnEvent; +use prompty::model::TurnEventType; +use prompty::model::context::{LoadContext, SaveContext}; + +#[test] +fn test_turn_event_load_json() { + let json = r####" +{ + "id": "evt_abc123", + "timestamp": "2026-06-09T20:00:00Z", + "turnId": "turn_001", + "iteration": 0, + "parentId": "evt_parent", + "spanId": "span_tool_001" +} +"####; + let ctx = LoadContext::default(); + let result = TurnEvent::from_json(json, &ctx); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + let instance = result.unwrap(); + assert_eq!(instance.id, "evt_abc123"); + assert_eq!(instance.timestamp, "2026-06-09T20:00:00Z"); + assert!(instance.turn_id.is_some(), "Expected turn_id to be Some"); + assert_eq!(instance.turn_id.as_ref().unwrap(), &"turn_001"); + assert!(instance.iteration.is_some(), "Expected iteration to be Some"); + assert_eq!(instance.iteration.as_ref().unwrap(), &0); + assert!(instance.parent_id.is_some(), "Expected parent_id to be Some"); + assert_eq!(instance.parent_id.as_ref().unwrap(), &"evt_parent"); + assert!(instance.span_id.is_some(), "Expected span_id to be Some"); + assert_eq!(instance.span_id.as_ref().unwrap(), &"span_tool_001"); +} + +#[test] +fn test_turn_event_load_yaml() { + let yaml = r####" +id: evt_abc123 +timestamp: "2026-06-09T20:00:00Z" +turnId: turn_001 +iteration: 0 +parentId: evt_parent +spanId: span_tool_001 + +"####; + let ctx = LoadContext::default(); + let result = TurnEvent::from_yaml(yaml, &ctx); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + let instance = result.unwrap(); + assert_eq!(instance.id, "evt_abc123"); + assert_eq!(instance.timestamp, "2026-06-09T20:00:00Z"); + assert!(instance.turn_id.is_some(), "Expected turn_id to be Some"); + assert!(instance.iteration.is_some(), "Expected iteration to be Some"); + assert!(instance.parent_id.is_some(), "Expected parent_id to be Some"); + assert!(instance.span_id.is_some(), "Expected span_id to be Some"); +} + +#[test] +fn test_turn_event_roundtrip() { + let json = r####" +{ + "id": "evt_abc123", + "timestamp": "2026-06-09T20:00:00Z", + "turnId": "turn_001", + "iteration": 0, + "parentId": "evt_parent", + "spanId": "span_tool_001" +} +"####; + let load_ctx = LoadContext::default(); + let result = TurnEvent::from_json(json, &load_ctx); + assert!(result.is_ok(), "Failed to load: {:?}", result.err()); + let instance = result.unwrap(); + let save_ctx = SaveContext::default(); + let json_output = instance.to_json(&save_ctx); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); +} diff --git a/runtime/rust/prompty/tests/model/events/turn_start_payload_test.rs b/runtime/rust/prompty/tests/model/events/turn_start_payload_test.rs new file mode 100644 index 00000000..7b93d282 --- /dev/null +++ b/runtime/rust/prompty/tests/model/events/turn_start_payload_test.rs @@ -0,0 +1,56 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use prompty::model::TurnStartPayload; +use prompty::model::context::{LoadContext, SaveContext}; + +#[test] +fn test_turn_start_payload_load_json() { + let json = r####" +{ + "agent": "weather-agent", + "maxIterations": 10 +} +"####; + let ctx = LoadContext::default(); + let result = TurnStartPayload::from_json(json, &ctx); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + let instance = result.unwrap(); + assert!(instance.agent.is_some(), "Expected agent to be Some"); + assert_eq!(instance.agent.as_ref().unwrap(), &"weather-agent"); + assert!(instance.max_iterations.is_some(), "Expected max_iterations to be Some"); + assert_eq!(instance.max_iterations.as_ref().unwrap(), &10); +} + +#[test] +fn test_turn_start_payload_load_yaml() { + let yaml = r####" +agent: weather-agent +maxIterations: 10 + +"####; + let ctx = LoadContext::default(); + let result = TurnStartPayload::from_yaml(yaml, &ctx); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + let instance = result.unwrap(); + assert!(instance.agent.is_some(), "Expected agent to be Some"); + assert!(instance.max_iterations.is_some(), "Expected max_iterations to be Some"); +} + +#[test] +fn test_turn_start_payload_roundtrip() { + let json = r####" +{ + "agent": "weather-agent", + "maxIterations": 10 +} +"####; + let load_ctx = LoadContext::default(); + let result = TurnStartPayload::from_json(json, &load_ctx); + assert!(result.is_ok(), "Failed to load: {:?}", result.err()); + let instance = result.unwrap(); + let save_ctx = SaveContext::default(); + let json_output = instance.to_json(&save_ctx); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); +} diff --git a/runtime/rust/prompty/tests/model/events/turn_summary_test.rs b/runtime/rust/prompty/tests/model/events/turn_summary_test.rs new file mode 100644 index 00000000..d807b04a --- /dev/null +++ b/runtime/rust/prompty/tests/model/events/turn_summary_test.rs @@ -0,0 +1,83 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use prompty::model::TurnSummary; +use prompty::model::context::{LoadContext, SaveContext}; + +#[test] +fn test_turn_summary_load_json() { + let json = r####" +{ + "turnId": "turn_001", + "status": "success", + "iterations": 2, + "llmCalls": 3, + "toolCalls": 2, + "retries": 1, + "durationMs": 2500 +} +"####; + let ctx = LoadContext::default(); + let result = TurnSummary::from_json(json, &ctx); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + let instance = result.unwrap(); + assert_eq!(instance.turn_id, "turn_001"); + assert_eq!(instance.status, "success"); + assert_eq!(instance.iterations, 2); + assert!(instance.llm_calls.is_some(), "Expected llm_calls to be Some"); + assert_eq!(instance.llm_calls.as_ref().unwrap(), &3); + assert!(instance.tool_calls.is_some(), "Expected tool_calls to be Some"); + assert_eq!(instance.tool_calls.as_ref().unwrap(), &2); + assert!(instance.retries.is_some(), "Expected retries to be Some"); + assert_eq!(instance.retries.as_ref().unwrap(), &1); + assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); + assert_eq!(instance.duration_ms.as_ref().unwrap(), &2500.0); +} + +#[test] +fn test_turn_summary_load_yaml() { + let yaml = r####" +turnId: turn_001 +status: success +iterations: 2 +llmCalls: 3 +toolCalls: 2 +retries: 1 +durationMs: 2500 + +"####; + let ctx = LoadContext::default(); + let result = TurnSummary::from_yaml(yaml, &ctx); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + let instance = result.unwrap(); + assert_eq!(instance.turn_id, "turn_001"); + assert_eq!(instance.status, "success"); + assert_eq!(instance.iterations, 2); + assert!(instance.llm_calls.is_some(), "Expected llm_calls to be Some"); + assert!(instance.tool_calls.is_some(), "Expected tool_calls to be Some"); + assert!(instance.retries.is_some(), "Expected retries to be Some"); + assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); +} + +#[test] +fn test_turn_summary_roundtrip() { + let json = r####" +{ + "turnId": "turn_001", + "status": "success", + "iterations": 2, + "llmCalls": 3, + "toolCalls": 2, + "retries": 1, + "durationMs": 2500 +} +"####; + let load_ctx = LoadContext::default(); + let result = TurnSummary::from_json(json, &load_ctx); + assert!(result.is_ok(), "Failed to load: {:?}", result.err()); + let instance = result.unwrap(); + let save_ctx = SaveContext::default(); + let json_output = instance.to_json(&save_ctx); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); +} diff --git a/runtime/rust/prompty/tests/model/events/turn_trace_test.rs b/runtime/rust/prompty/tests/model/events/turn_trace_test.rs new file mode 100644 index 00000000..21bceeda --- /dev/null +++ b/runtime/rust/prompty/tests/model/events/turn_trace_test.rs @@ -0,0 +1,61 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use prompty::model::TurnTrace; +use prompty::model::context::{LoadContext, SaveContext}; + +#[test] +fn test_turn_trace_load_json() { + let json = r####" +{ + "version": "1", + "runtime": "typescript", + "promptyVersion": "2.0.0" +} +"####; + let ctx = LoadContext::default(); + let result = TurnTrace::from_json(json, &ctx); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + let instance = result.unwrap(); + assert_eq!(instance.version, "1"); + assert!(instance.runtime.is_some(), "Expected runtime to be Some"); + assert_eq!(instance.runtime.as_ref().unwrap(), &"typescript"); + assert!(instance.prompty_version.is_some(), "Expected prompty_version to be Some"); + assert_eq!(instance.prompty_version.as_ref().unwrap(), &"2.0.0"); +} + +#[test] +fn test_turn_trace_load_yaml() { + let yaml = r####" +version: "1" +runtime: typescript +promptyVersion: 2.0.0 + +"####; + let ctx = LoadContext::default(); + let result = TurnTrace::from_yaml(yaml, &ctx); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + let instance = result.unwrap(); + assert_eq!(instance.version, "1"); + assert!(instance.runtime.is_some(), "Expected runtime to be Some"); + assert!(instance.prompty_version.is_some(), "Expected prompty_version to be Some"); +} + +#[test] +fn test_turn_trace_roundtrip() { + let json = r####" +{ + "version": "1", + "runtime": "typescript", + "promptyVersion": "2.0.0" +} +"####; + let load_ctx = LoadContext::default(); + let result = TurnTrace::from_json(json, &load_ctx); + assert!(result.is_ok(), "Failed to load: {:?}", result.err()); + let instance = result.unwrap(); + let save_ctx = SaveContext::default(); + let json_output = instance.to_json(&save_ctx); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); +} diff --git a/runtime/rust/prompty/tests/model/main.rs b/runtime/rust/prompty/tests/model/main.rs index 9f5d7fc9..fb66f889 100644 --- a/runtime/rust/prompty/tests/model/main.rs +++ b/runtime/rust/prompty/tests/model/main.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] mod agent; mod connection; diff --git a/runtime/rust/prompty/tests/model/model/mod.rs b/runtime/rust/prompty/tests/model/model/mod.rs index 9f75a36a..e677e15a 100644 --- a/runtime/rust/prompty/tests/model/model/mod.rs +++ b/runtime/rust/prompty/tests/model/model/mod.rs @@ -1,14 +1,8 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] -mod model_info_test; mod model_options_test; mod model_test; mod token_usage_test; +mod model_info_test; diff --git a/runtime/rust/prompty/tests/model/model/model_info_test.rs b/runtime/rust/prompty/tests/model/model/model_info_test.rs index 14d636fc..411a8cca 100644 --- a/runtime/rust/prompty/tests/model/model/model_info_test.rs +++ b/runtime/rust/prompty/tests/model/model/model_info_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::ModelInfo; use prompty::model::context::{LoadContext, SaveContext}; @@ -33,24 +27,14 @@ fn test_model_info_load_json() { "####; let ctx = LoadContext::default(); let result = ModelInfo::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.id, "gpt-4o"); - assert!( - instance.display_name.is_some(), - "Expected display_name to be Some" - ); + assert!(instance.display_name.is_some(), "Expected display_name to be Some"); assert_eq!(instance.display_name.as_ref().unwrap(), &"GPT-4o"); assert!(instance.owned_by.is_some(), "Expected owned_by to be Some"); assert_eq!(instance.owned_by.as_ref().unwrap(), &"openai"); - assert!( - instance.context_window.is_some(), - "Expected context_window to be Some" - ); + assert!(instance.context_window.is_some(), "Expected context_window to be Some"); assert_eq!(instance.context_window.as_ref().unwrap(), &128000); } @@ -72,22 +56,12 @@ additionalProperties: "####; let ctx = LoadContext::default(); let result = ModelInfo::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.id, "gpt-4o"); - assert!( - instance.display_name.is_some(), - "Expected display_name to be Some" - ); + assert!(instance.display_name.is_some(), "Expected display_name to be Some"); assert!(instance.owned_by.is_some(), "Expected owned_by to be Some"); - assert!( - instance.context_window.is_some(), - "Expected context_window to be Some" - ); + assert!(instance.context_window.is_some(), "Expected context_window to be Some"); } #[test] @@ -116,9 +90,5 @@ fn test_model_info_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } diff --git a/runtime/rust/prompty/tests/model/model/model_options_test.rs b/runtime/rust/prompty/tests/model/model/model_options_test.rs index fa80b2fc..677ef96f 100644 --- a/runtime/rust/prompty/tests/model/model/model_options_test.rs +++ b/runtime/rust/prompty/tests/model/model/model_options_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::ModelOptions; use prompty::model::context::{LoadContext, SaveContext}; @@ -35,42 +29,23 @@ fn test_model_options_load_json() { "####; let ctx = LoadContext::default(); let result = ModelOptions::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); - assert!( - instance.frequency_penalty.is_some(), - "Expected frequency_penalty to be Some" - ); + assert!(instance.frequency_penalty.is_some(), "Expected frequency_penalty to be Some"); assert_eq!(instance.frequency_penalty.as_ref().unwrap(), &0.5); - assert!( - instance.max_output_tokens.is_some(), - "Expected max_output_tokens to be Some" - ); + assert!(instance.max_output_tokens.is_some(), "Expected max_output_tokens to be Some"); assert_eq!(instance.max_output_tokens.as_ref().unwrap(), &2048); - assert!( - instance.presence_penalty.is_some(), - "Expected presence_penalty to be Some" - ); + assert!(instance.presence_penalty.is_some(), "Expected presence_penalty to be Some"); assert_eq!(instance.presence_penalty.as_ref().unwrap(), &0.3); assert!(instance.seed.is_some(), "Expected seed to be Some"); assert_eq!(instance.seed.as_ref().unwrap(), &42); - assert!( - instance.temperature.is_some(), - "Expected temperature to be Some" - ); + assert!(instance.temperature.is_some(), "Expected temperature to be Some"); assert_eq!(instance.temperature.as_ref().unwrap(), &0.7); assert!(instance.top_k.is_some(), "Expected top_k to be Some"); assert_eq!(instance.top_k.as_ref().unwrap(), &40); assert!(instance.top_p.is_some(), "Expected top_p to be Some"); assert_eq!(instance.top_p.as_ref().unwrap(), &0.9); - assert!( - instance.allow_multiple_tool_calls.is_some(), - "Expected allow_multiple_tool_calls to be Some" - ); + assert!(instance.allow_multiple_tool_calls.is_some(), "Expected allow_multiple_tool_calls to be Some"); assert_eq!(instance.allow_multiple_tool_calls.as_ref().unwrap(), &true); } @@ -95,35 +70,16 @@ additionalProperties: "####; let ctx = LoadContext::default(); let result = ModelOptions::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); - assert!( - instance.frequency_penalty.is_some(), - "Expected frequency_penalty to be Some" - ); - assert!( - instance.max_output_tokens.is_some(), - "Expected max_output_tokens to be Some" - ); - assert!( - instance.presence_penalty.is_some(), - "Expected presence_penalty to be Some" - ); + assert!(instance.frequency_penalty.is_some(), "Expected frequency_penalty to be Some"); + assert!(instance.max_output_tokens.is_some(), "Expected max_output_tokens to be Some"); + assert!(instance.presence_penalty.is_some(), "Expected presence_penalty to be Some"); assert!(instance.seed.is_some(), "Expected seed to be Some"); - assert!( - instance.temperature.is_some(), - "Expected temperature to be Some" - ); + assert!(instance.temperature.is_some(), "Expected temperature to be Some"); assert!(instance.top_k.is_some(), "Expected top_k to be Some"); assert!(instance.top_p.is_some(), "Expected top_p to be Some"); - assert!( - instance.allow_multiple_tool_calls.is_some(), - "Expected allow_multiple_tool_calls to be Some" - ); + assert!(instance.allow_multiple_tool_calls.is_some(), "Expected allow_multiple_tool_calls to be Some"); } #[test] @@ -154,9 +110,5 @@ fn test_model_options_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } diff --git a/runtime/rust/prompty/tests/model/model/model_test.rs b/runtime/rust/prompty/tests/model/model/model_test.rs index a6145c16..7c9d0722 100644 --- a/runtime/rust/prompty/tests/model/model/model_test.rs +++ b/runtime/rust/prompty/tests/model/model/model_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::Model; use prompty::model::apiType; @@ -33,11 +27,7 @@ fn test_model_load_json() { "####; let ctx = LoadContext::default(); let result = Model::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.id, "gpt-35-turbo"); assert!(instance.provider.is_some(), "Expected provider to be Some"); @@ -64,11 +54,7 @@ options: "####; let ctx = LoadContext::default(); let result = Model::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.id, "gpt-35-turbo"); assert!(instance.provider.is_some(), "Expected provider to be Some"); @@ -100,11 +86,7 @@ fn test_model_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } #[test] diff --git a/runtime/rust/prompty/tests/model/model/token_usage_test.rs b/runtime/rust/prompty/tests/model/model/token_usage_test.rs index 7478c864..1829a2b2 100644 --- a/runtime/rust/prompty/tests/model/model/token_usage_test.rs +++ b/runtime/rust/prompty/tests/model/model/token_usage_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::TokenUsage; use prompty::model::context::{LoadContext, SaveContext}; @@ -22,26 +16,13 @@ fn test_token_usage_load_json() { "####; let ctx = LoadContext::default(); let result = TokenUsage::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); - assert!( - instance.prompt_tokens.is_some(), - "Expected prompt_tokens to be Some" - ); + assert!(instance.prompt_tokens.is_some(), "Expected prompt_tokens to be Some"); assert_eq!(instance.prompt_tokens.as_ref().unwrap(), &150); - assert!( - instance.completion_tokens.is_some(), - "Expected completion_tokens to be Some" - ); + assert!(instance.completion_tokens.is_some(), "Expected completion_tokens to be Some"); assert_eq!(instance.completion_tokens.as_ref().unwrap(), &42); - assert!( - instance.total_tokens.is_some(), - "Expected total_tokens to be Some" - ); + assert!(instance.total_tokens.is_some(), "Expected total_tokens to be Some"); assert_eq!(instance.total_tokens.as_ref().unwrap(), &192); } @@ -55,24 +36,11 @@ totalTokens: 192 "####; let ctx = LoadContext::default(); let result = TokenUsage::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); - assert!( - instance.prompt_tokens.is_some(), - "Expected prompt_tokens to be Some" - ); - assert!( - instance.completion_tokens.is_some(), - "Expected completion_tokens to be Some" - ); - assert!( - instance.total_tokens.is_some(), - "Expected total_tokens to be Some" - ); + assert!(instance.prompt_tokens.is_some(), "Expected prompt_tokens to be Some"); + assert!(instance.completion_tokens.is_some(), "Expected completion_tokens to be Some"); + assert!(instance.total_tokens.is_some(), "Expected total_tokens to be Some"); } #[test] @@ -90,9 +58,5 @@ fn test_token_usage_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } diff --git a/runtime/rust/prompty/tests/model/pipeline/compaction_config_test.rs b/runtime/rust/prompty/tests/model/pipeline/compaction_config_test.rs index 45ea60b5..10edc28c 100644 --- a/runtime/rust/prompty/tests/model/pipeline/compaction_config_test.rs +++ b/runtime/rust/prompty/tests/model/pipeline/compaction_config_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::CompactionConfig; use prompty::model::context::{LoadContext, SaveContext}; @@ -24,11 +18,7 @@ fn test_compaction_config_load_json() { "####; let ctx = LoadContext::default(); let result = CompactionConfig::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert!(instance.strategy.is_some(), "Expected strategy to be Some"); assert_eq!(instance.strategy.as_ref().unwrap(), &"summarize"); @@ -47,11 +37,7 @@ options: "####; let ctx = LoadContext::default(); let result = CompactionConfig::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert!(instance.strategy.is_some(), "Expected strategy to be Some"); assert!(instance.budget.is_some(), "Expected budget to be Some"); @@ -74,9 +60,5 @@ fn test_compaction_config_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } diff --git a/runtime/rust/prompty/tests/model/pipeline/mod.rs b/runtime/rust/prompty/tests/model/pipeline/mod.rs index 2cf05067..5a3a85f7 100644 --- a/runtime/rust/prompty/tests/model/pipeline/mod.rs +++ b/runtime/rust/prompty/tests/model/pipeline/mod.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] mod compaction_config_test; mod turn_options_test; diff --git a/runtime/rust/prompty/tests/model/pipeline/turn_options_test.rs b/runtime/rust/prompty/tests/model/pipeline/turn_options_test.rs index 9edfd44b..b2b2383e 100644 --- a/runtime/rust/prompty/tests/model/pipeline/turn_options_test.rs +++ b/runtime/rust/prompty/tests/model/pipeline/turn_options_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::TurnOptions; use prompty::model::context::{LoadContext, SaveContext}; @@ -28,31 +22,15 @@ fn test_turn_options_load_json() { "####; let ctx = LoadContext::default(); let result = TurnOptions::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); - assert!( - instance.max_iterations.is_some(), - "Expected max_iterations to be Some" - ); + assert!(instance.max_iterations.is_some(), "Expected max_iterations to be Some"); assert_eq!(instance.max_iterations.as_ref().unwrap(), &10); - assert!( - instance.max_llm_retries.is_some(), - "Expected max_llm_retries to be Some" - ); + assert!(instance.max_llm_retries.is_some(), "Expected max_llm_retries to be Some"); assert_eq!(instance.max_llm_retries.as_ref().unwrap(), &3); - assert!( - instance.context_budget.is_some(), - "Expected context_budget to be Some" - ); + assert!(instance.context_budget.is_some(), "Expected context_budget to be Some"); assert_eq!(instance.context_budget.as_ref().unwrap(), &100000); - assert!( - instance.parallel_tool_calls.is_some(), - "Expected parallel_tool_calls to be Some" - ); + assert!(instance.parallel_tool_calls.is_some(), "Expected parallel_tool_calls to be Some"); assert_eq!(instance.parallel_tool_calls.as_ref().unwrap(), &true); assert!(instance.raw.is_some(), "Expected raw to be Some"); assert_eq!(instance.raw.as_ref().unwrap(), &false); @@ -75,28 +53,12 @@ compaction: "####; let ctx = LoadContext::default(); let result = TurnOptions::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); - assert!( - instance.max_iterations.is_some(), - "Expected max_iterations to be Some" - ); - assert!( - instance.max_llm_retries.is_some(), - "Expected max_llm_retries to be Some" - ); - assert!( - instance.context_budget.is_some(), - "Expected context_budget to be Some" - ); - assert!( - instance.parallel_tool_calls.is_some(), - "Expected parallel_tool_calls to be Some" - ); + assert!(instance.max_iterations.is_some(), "Expected max_iterations to be Some"); + assert!(instance.max_llm_retries.is_some(), "Expected max_llm_retries to be Some"); + assert!(instance.context_budget.is_some(), "Expected context_budget to be Some"); + assert!(instance.parallel_tool_calls.is_some(), "Expected parallel_tool_calls to be Some"); assert!(instance.raw.is_some(), "Expected raw to be Some"); assert!(instance.turn.is_some(), "Expected turn to be Some"); } @@ -122,9 +84,5 @@ fn test_turn_options_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } diff --git a/runtime/rust/prompty/tests/model/streaming/mod.rs b/runtime/rust/prompty/tests/model/streaming/mod.rs index a2f22085..e1d58e14 100644 --- a/runtime/rust/prompty/tests/model/streaming/mod.rs +++ b/runtime/rust/prompty/tests/model/streaming/mod.rs @@ -1,11 +1,5 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] mod stream_options_test; diff --git a/runtime/rust/prompty/tests/model/streaming/stream_options_test.rs b/runtime/rust/prompty/tests/model/streaming/stream_options_test.rs index 007c02d7..f5ff9962 100644 --- a/runtime/rust/prompty/tests/model/streaming/stream_options_test.rs +++ b/runtime/rust/prompty/tests/model/streaming/stream_options_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::StreamOptions; use prompty::model::context::{LoadContext, SaveContext}; @@ -20,16 +14,9 @@ fn test_stream_options_load_json() { "####; let ctx = LoadContext::default(); let result = StreamOptions::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); - assert!( - instance.include_usage.is_some(), - "Expected include_usage to be Some" - ); + assert!(instance.include_usage.is_some(), "Expected include_usage to be Some"); assert_eq!(instance.include_usage.as_ref().unwrap(), &true); } @@ -41,16 +28,9 @@ includeUsage: true "####; let ctx = LoadContext::default(); let result = StreamOptions::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); - assert!( - instance.include_usage.is_some(), - "Expected include_usage to be Some" - ); + assert!(instance.include_usage.is_some(), "Expected include_usage to be Some"); } #[test] @@ -66,9 +46,5 @@ fn test_stream_options_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } diff --git a/runtime/rust/prompty/tests/model/template/format_config_test.rs b/runtime/rust/prompty/tests/model/template/format_config_test.rs index a002170a..dcad8d7e 100644 --- a/runtime/rust/prompty/tests/model/template/format_config_test.rs +++ b/runtime/rust/prompty/tests/model/template/format_config_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::FormatConfig; use prompty::model::context::{LoadContext, SaveContext}; @@ -24,11 +18,7 @@ fn test_format_config_load_json() { "####; let ctx = LoadContext::default(); let result = FormatConfig::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); } #[test] @@ -42,11 +32,7 @@ options: "####; let ctx = LoadContext::default(); let result = FormatConfig::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); } #[test] diff --git a/runtime/rust/prompty/tests/model/template/mod.rs b/runtime/rust/prompty/tests/model/template/mod.rs index 1a954115..e6e3c445 100644 --- a/runtime/rust/prompty/tests/model/template/mod.rs +++ b/runtime/rust/prompty/tests/model/template/mod.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] mod format_config_test; mod parser_config_test; diff --git a/runtime/rust/prompty/tests/model/template/parser_config_test.rs b/runtime/rust/prompty/tests/model/template/parser_config_test.rs index 085f4e2b..a5b96df1 100644 --- a/runtime/rust/prompty/tests/model/template/parser_config_test.rs +++ b/runtime/rust/prompty/tests/model/template/parser_config_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::ParserConfig; use prompty::model::context::{LoadContext, SaveContext}; @@ -23,11 +17,7 @@ fn test_parser_config_load_json() { "####; let ctx = LoadContext::default(); let result = ParserConfig::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); } #[test] @@ -40,11 +30,7 @@ options: "####; let ctx = LoadContext::default(); let result = ParserConfig::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); } #[test] diff --git a/runtime/rust/prompty/tests/model/template/template_test.rs b/runtime/rust/prompty/tests/model/template/template_test.rs index 63793ad3..1da47b59 100644 --- a/runtime/rust/prompty/tests/model/template/template_test.rs +++ b/runtime/rust/prompty/tests/model/template/template_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::Template; use prompty::model::context::{LoadContext, SaveContext}; @@ -25,11 +19,7 @@ fn test_template_load_json() { "####; let ctx = LoadContext::default(); let result = Template::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); let _ = instance; // load succeeded, no scalar properties to validate } @@ -45,11 +35,7 @@ parser: "####; let ctx = LoadContext::default(); let result = Template::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); let _ = instance; // load succeeded, no scalar properties to validate } @@ -72,9 +58,5 @@ fn test_template_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } diff --git a/runtime/rust/prompty/tests/model/tools/binding_test.rs b/runtime/rust/prompty/tests/model/tools/binding_test.rs index 9258b5db..038b988d 100644 --- a/runtime/rust/prompty/tests/model/tools/binding_test.rs +++ b/runtime/rust/prompty/tests/model/tools/binding_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::Binding; use prompty::model::context::{LoadContext, SaveContext}; @@ -21,11 +15,7 @@ fn test_binding_load_json() { "####; let ctx = LoadContext::default(); let result = Binding::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.name, "my-tool"); assert_eq!(instance.input, "input-variable"); @@ -40,11 +30,7 @@ input: input-variable "####; let ctx = LoadContext::default(); let result = Binding::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.name, "my-tool"); assert_eq!(instance.input, "input-variable"); @@ -64,11 +50,7 @@ fn test_binding_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } #[test] diff --git a/runtime/rust/prompty/tests/model/tools/mcp_approval_mode_test.rs b/runtime/rust/prompty/tests/model/tools/mcp_approval_mode_test.rs index 945892ab..68a98a9a 100644 --- a/runtime/rust/prompty/tests/model/tools/mcp_approval_mode_test.rs +++ b/runtime/rust/prompty/tests/model/tools/mcp_approval_mode_test.rs @@ -1,16 +1,10 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::McpApprovalMode; -use prompty::model::context::{LoadContext, SaveContext}; use prompty::model::mcpApprovalModeKind; +use prompty::model::context::{LoadContext, SaveContext}; #[test] fn test_mcp_approval_mode_load_json() { @@ -27,11 +21,7 @@ fn test_mcp_approval_mode_load_json() { "####; let ctx = LoadContext::default(); let result = McpApprovalMode::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.kind, mcpApprovalModeKind::Never); } @@ -48,11 +38,7 @@ neverRequireApprovalTools: "####; let ctx = LoadContext::default(); let result = McpApprovalMode::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.kind, mcpApprovalModeKind::Never); } @@ -76,11 +62,7 @@ fn test_mcp_approval_mode_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } #[test] diff --git a/runtime/rust/prompty/tests/model/tools/mod.rs b/runtime/rust/prompty/tests/model/tools/mod.rs index 4142e779..fe5c4d63 100644 --- a/runtime/rust/prompty/tests/model/tools/mod.rs +++ b/runtime/rust/prompty/tests/model/tools/mod.rs @@ -1,15 +1,9 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] mod binding_test; +mod tool_test; mod mcp_approval_mode_test; mod tool_context_test; mod tool_dispatch_result_test; -mod tool_test; diff --git a/runtime/rust/prompty/tests/model/tools/tool_context_test.rs b/runtime/rust/prompty/tests/model/tools/tool_context_test.rs index 3fac90e7..5945bb6f 100644 --- a/runtime/rust/prompty/tests/model/tools/tool_context_test.rs +++ b/runtime/rust/prompty/tests/model/tools/tool_context_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::ToolContext; use prompty::model::context::{LoadContext, SaveContext}; @@ -22,11 +16,7 @@ fn test_tool_context_load_json() { "####; let ctx = LoadContext::default(); let result = ToolContext::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); let _ = instance; // load succeeded, no scalar properties to validate } @@ -40,11 +30,7 @@ metadata: "####; let ctx = LoadContext::default(); let result = ToolContext::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); let _ = instance; // load succeeded, no scalar properties to validate } @@ -64,9 +50,5 @@ fn test_tool_context_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } diff --git a/runtime/rust/prompty/tests/model/tools/tool_dispatch_result_test.rs b/runtime/rust/prompty/tests/model/tools/tool_dispatch_result_test.rs index 1d0844d1..afe14769 100644 --- a/runtime/rust/prompty/tests/model/tools/tool_dispatch_result_test.rs +++ b/runtime/rust/prompty/tests/model/tools/tool_dispatch_result_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::ToolDispatchResult; use prompty::model::context::{LoadContext, SaveContext}; @@ -29,11 +23,7 @@ fn test_tool_dispatch_result_load_json() { "####; let ctx = LoadContext::default(); let result = ToolDispatchResult::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.tool_call_id, "call_abc123"); assert_eq!(instance.name, "get_weather"); @@ -52,11 +42,7 @@ result: "####; let ctx = LoadContext::default(); let result = ToolDispatchResult::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.tool_call_id, "call_abc123"); assert_eq!(instance.name, "get_weather"); @@ -84,9 +70,5 @@ fn test_tool_dispatch_result_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } diff --git a/runtime/rust/prompty/tests/model/tools/tool_test.rs b/runtime/rust/prompty/tests/model/tools/tool_test.rs index d493601b..89aee4d4 100644 --- a/runtime/rust/prompty/tests/model/tools/tool_test.rs +++ b/runtime/rust/prompty/tests/model/tools/tool_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::Tool; use prompty::model::context::{LoadContext, SaveContext}; @@ -25,11 +19,7 @@ fn test_tool_load_json() { "####; let ctx = LoadContext::default(); let result = Tool::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); } #[test] @@ -44,11 +34,7 @@ bindings: "####; let ctx = LoadContext::default(); let result = Tool::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); } #[test] diff --git a/runtime/rust/prompty/tests/model/tracing/mod.rs b/runtime/rust/prompty/tests/model/tracing/mod.rs index bc7cf121..449c1ad4 100644 --- a/runtime/rust/prompty/tests/model/tracing/mod.rs +++ b/runtime/rust/prompty/tests/model/tracing/mod.rs @@ -1,13 +1,7 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] -mod trace_file_test; -mod trace_span_test; mod trace_time_test; +mod trace_span_test; +mod trace_file_test; diff --git a/runtime/rust/prompty/tests/model/tracing/trace_file_test.rs b/runtime/rust/prompty/tests/model/tracing/trace_file_test.rs index 27ad1a80..390b2ed6 100644 --- a/runtime/rust/prompty/tests/model/tracing/trace_file_test.rs +++ b/runtime/rust/prompty/tests/model/tracing/trace_file_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::TraceFile; use prompty::model::context::{LoadContext, SaveContext}; @@ -21,11 +15,7 @@ fn test_trace_file_load_json() { "####; let ctx = LoadContext::default(); let result = TraceFile::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.runtime, "python"); assert_eq!(instance.version, "2.0.0"); @@ -40,11 +30,7 @@ version: 2.0.0 "####; let ctx = LoadContext::default(); let result = TraceFile::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.runtime, "python"); assert_eq!(instance.version, "2.0.0"); @@ -64,9 +50,5 @@ fn test_trace_file_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } diff --git a/runtime/rust/prompty/tests/model/tracing/trace_span_test.rs b/runtime/rust/prompty/tests/model/tracing/trace_span_test.rs index fd445f20..2f9448b8 100644 --- a/runtime/rust/prompty/tests/model/tracing/trace_span_test.rs +++ b/runtime/rust/prompty/tests/model/tracing/trace_span_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::TraceSpan; use prompty::model::context::{LoadContext, SaveContext}; @@ -22,21 +16,11 @@ fn test_trace_span_load_json() { "####; let ctx = LoadContext::default(); let result = TraceSpan::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.name, "prompty.core.pipeline.run"); - assert!( - instance.signature.is_some(), - "Expected signature to be Some" - ); - assert_eq!( - instance.signature.as_ref().unwrap(), - &"prompty.core.pipeline.run" - ); + assert!(instance.signature.is_some(), "Expected signature to be Some"); + assert_eq!(instance.signature.as_ref().unwrap(), &"prompty.core.pipeline.run"); assert!(instance.error.is_some(), "Expected error to be Some"); assert_eq!(instance.error.as_ref().unwrap(), &"Connection refused"); } @@ -51,17 +35,10 @@ error: Connection refused "####; let ctx = LoadContext::default(); let result = TraceSpan::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.name, "prompty.core.pipeline.run"); - assert!( - instance.signature.is_some(), - "Expected signature to be Some" - ); + assert!(instance.signature.is_some(), "Expected signature to be Some"); assert!(instance.error.is_some(), "Expected error to be Some"); } @@ -80,9 +57,5 @@ fn test_trace_span_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } diff --git a/runtime/rust/prompty/tests/model/tracing/trace_time_test.rs b/runtime/rust/prompty/tests/model/tracing/trace_time_test.rs index 1bbd4ca2..fcee85be 100644 --- a/runtime/rust/prompty/tests/model/tracing/trace_time_test.rs +++ b/runtime/rust/prompty/tests/model/tracing/trace_time_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::TraceTime; use prompty::model::context::{LoadContext, SaveContext}; @@ -22,11 +16,7 @@ fn test_trace_time_load_json() { "####; let ctx = LoadContext::default(); let result = TraceTime::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.start, "2026-04-04T12:00:00Z"); assert_eq!(instance.end, "2026-04-04T12:00:01Z"); @@ -43,11 +33,7 @@ duration: 1000 "####; let ctx = LoadContext::default(); let result = TraceTime::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.start, "2026-04-04T12:00:00Z"); assert_eq!(instance.end, "2026-04-04T12:00:01Z"); @@ -69,9 +55,5 @@ fn test_trace_time_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } diff --git a/runtime/rust/prompty/tests/model/wire/anthropic_image_block_test.rs b/runtime/rust/prompty/tests/model/wire/anthropic_image_block_test.rs index ea02d7d4..95e5e90c 100644 --- a/runtime/rust/prompty/tests/model/wire/anthropic_image_block_test.rs +++ b/runtime/rust/prompty/tests/model/wire/anthropic_image_block_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::AnthropicImageBlock; use prompty::model::context::{LoadContext, SaveContext}; diff --git a/runtime/rust/prompty/tests/model/wire/anthropic_image_source_test.rs b/runtime/rust/prompty/tests/model/wire/anthropic_image_source_test.rs index c6e78973..0bbf018c 100644 --- a/runtime/rust/prompty/tests/model/wire/anthropic_image_source_test.rs +++ b/runtime/rust/prompty/tests/model/wire/anthropic_image_source_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::AnthropicImageSource; use prompty::model::context::{LoadContext, SaveContext}; @@ -21,11 +15,7 @@ fn test_anthropic_image_source_load_json() { "####; let ctx = LoadContext::default(); let result = AnthropicImageSource::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.media_type, "image/png"); assert_eq!(instance.data, "iVBORw0KGgo..."); @@ -40,11 +30,7 @@ data: iVBORw0KGgo... "####; let ctx = LoadContext::default(); let result = AnthropicImageSource::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.media_type, "image/png"); assert_eq!(instance.data, "iVBORw0KGgo..."); @@ -64,9 +50,5 @@ fn test_anthropic_image_source_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } diff --git a/runtime/rust/prompty/tests/model/wire/anthropic_messages_request_test.rs b/runtime/rust/prompty/tests/model/wire/anthropic_messages_request_test.rs index e07ab03e..99b35f90 100644 --- a/runtime/rust/prompty/tests/model/wire/anthropic_messages_request_test.rs +++ b/runtime/rust/prompty/tests/model/wire/anthropic_messages_request_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::AnthropicMessagesRequest; use prompty::model::context::{LoadContext, SaveContext}; @@ -28,23 +22,13 @@ fn test_anthropic_messages_request_load_json() { "####; let ctx = LoadContext::default(); let result = AnthropicMessagesRequest::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.model, "claude-sonnet-4-20250514"); assert_eq!(instance.max_tokens, 4096); assert!(instance.system.is_some(), "Expected system to be Some"); - assert_eq!( - instance.system.as_ref().unwrap(), - &"You are a helpful assistant." - ); - assert!( - instance.temperature.is_some(), - "Expected temperature to be Some" - ); + assert_eq!(instance.system.as_ref().unwrap(), &"You are a helpful assistant."); + assert!(instance.temperature.is_some(), "Expected temperature to be Some"); assert_eq!(instance.temperature.as_ref().unwrap(), &0.7); assert!(instance.top_p.is_some(), "Expected top_p to be Some"); assert_eq!(instance.top_p.as_ref().unwrap(), &0.9); @@ -67,19 +51,12 @@ stop_sequences: "####; let ctx = LoadContext::default(); let result = AnthropicMessagesRequest::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.model, "claude-sonnet-4-20250514"); assert_eq!(instance.max_tokens, 4096); assert!(instance.system.is_some(), "Expected system to be Some"); - assert!( - instance.temperature.is_some(), - "Expected temperature to be Some" - ); + assert!(instance.temperature.is_some(), "Expected temperature to be Some"); assert!(instance.top_p.is_some(), "Expected top_p to be Some"); assert!(instance.top_k.is_some(), "Expected top_k to be Some"); } @@ -105,9 +82,5 @@ fn test_anthropic_messages_request_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } diff --git a/runtime/rust/prompty/tests/model/wire/anthropic_messages_response_test.rs b/runtime/rust/prompty/tests/model/wire/anthropic_messages_response_test.rs index d1ef73b1..e5e3b93e 100644 --- a/runtime/rust/prompty/tests/model/wire/anthropic_messages_response_test.rs +++ b/runtime/rust/prompty/tests/model/wire/anthropic_messages_response_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::AnthropicMessagesResponse; use prompty::model::context::{LoadContext, SaveContext}; @@ -22,11 +16,7 @@ fn test_anthropic_messages_response_load_json() { "####; let ctx = LoadContext::default(); let result = AnthropicMessagesResponse::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.id, "msg_01XFDUDYJgAACzvnptvVoYEL"); assert_eq!(instance.model, "claude-sonnet-4-20250514"); @@ -43,11 +33,7 @@ stop_reason: end_turn "####; let ctx = LoadContext::default(); let result = AnthropicMessagesResponse::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.id, "msg_01XFDUDYJgAACzvnptvVoYEL"); assert_eq!(instance.model, "claude-sonnet-4-20250514"); @@ -69,9 +55,5 @@ fn test_anthropic_messages_response_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } diff --git a/runtime/rust/prompty/tests/model/wire/anthropic_text_block_test.rs b/runtime/rust/prompty/tests/model/wire/anthropic_text_block_test.rs index 2e0374dd..5b2ce62a 100644 --- a/runtime/rust/prompty/tests/model/wire/anthropic_text_block_test.rs +++ b/runtime/rust/prompty/tests/model/wire/anthropic_text_block_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::AnthropicTextBlock; use prompty::model::context::{LoadContext, SaveContext}; @@ -20,11 +14,7 @@ fn test_anthropic_text_block_load_json() { "####; let ctx = LoadContext::default(); let result = AnthropicTextBlock::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.text, "Hello, how can I help?"); } @@ -37,11 +27,7 @@ text: Hello, how can I help? "####; let ctx = LoadContext::default(); let result = AnthropicTextBlock::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.text, "Hello, how can I help?"); } @@ -59,9 +45,5 @@ fn test_anthropic_text_block_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } diff --git a/runtime/rust/prompty/tests/model/wire/anthropic_tool_definition_test.rs b/runtime/rust/prompty/tests/model/wire/anthropic_tool_definition_test.rs index 333ca534..054c297f 100644 --- a/runtime/rust/prompty/tests/model/wire/anthropic_tool_definition_test.rs +++ b/runtime/rust/prompty/tests/model/wire/anthropic_tool_definition_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::AnthropicToolDefinition; use prompty::model::context::{LoadContext, SaveContext}; @@ -21,21 +15,11 @@ fn test_anthropic_tool_definition_load_json() { "####; let ctx = LoadContext::default(); let result = AnthropicToolDefinition::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.name, "get_weather"); - assert!( - instance.description.is_some(), - "Expected description to be Some" - ); - assert_eq!( - instance.description.as_ref().unwrap(), - &"Get the current weather for a city" - ); + assert!(instance.description.is_some(), "Expected description to be Some"); + assert_eq!(instance.description.as_ref().unwrap(), &"Get the current weather for a city"); } #[test] @@ -47,17 +31,10 @@ description: Get the current weather for a city "####; let ctx = LoadContext::default(); let result = AnthropicToolDefinition::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.name, "get_weather"); - assert!( - instance.description.is_some(), - "Expected description to be Some" - ); + assert!(instance.description.is_some(), "Expected description to be Some"); } #[test] @@ -74,9 +51,5 @@ fn test_anthropic_tool_definition_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } diff --git a/runtime/rust/prompty/tests/model/wire/anthropic_tool_result_block_test.rs b/runtime/rust/prompty/tests/model/wire/anthropic_tool_result_block_test.rs index 6bbf2dbf..7f8a9bc3 100644 --- a/runtime/rust/prompty/tests/model/wire/anthropic_tool_result_block_test.rs +++ b/runtime/rust/prompty/tests/model/wire/anthropic_tool_result_block_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::AnthropicToolResultBlock; use prompty::model::context::{LoadContext, SaveContext}; @@ -21,11 +15,7 @@ fn test_anthropic_tool_result_block_load_json() { "####; let ctx = LoadContext::default(); let result = AnthropicToolResultBlock::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.tool_use_id, "toolu_01A09q90qw90lq917835lq9"); assert_eq!(instance.content, "72°F and sunny in Paris"); @@ -40,11 +30,7 @@ content: 72°F and sunny in Paris "####; let ctx = LoadContext::default(); let result = AnthropicToolResultBlock::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.tool_use_id, "toolu_01A09q90qw90lq917835lq9"); assert_eq!(instance.content, "72°F and sunny in Paris"); @@ -64,9 +50,5 @@ fn test_anthropic_tool_result_block_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } diff --git a/runtime/rust/prompty/tests/model/wire/anthropic_tool_use_block_test.rs b/runtime/rust/prompty/tests/model/wire/anthropic_tool_use_block_test.rs index bd0e410c..eec49a7c 100644 --- a/runtime/rust/prompty/tests/model/wire/anthropic_tool_use_block_test.rs +++ b/runtime/rust/prompty/tests/model/wire/anthropic_tool_use_block_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::AnthropicToolUseBlock; use prompty::model::context::{LoadContext, SaveContext}; @@ -24,11 +18,7 @@ fn test_anthropic_tool_use_block_load_json() { "####; let ctx = LoadContext::default(); let result = AnthropicToolUseBlock::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.id, "toolu_01A09q90qw90lq917835lq9"); assert_eq!(instance.name, "get_weather"); @@ -45,11 +35,7 @@ input: "####; let ctx = LoadContext::default(); let result = AnthropicToolUseBlock::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.id, "toolu_01A09q90qw90lq917835lq9"); assert_eq!(instance.name, "get_weather"); @@ -72,9 +58,5 @@ fn test_anthropic_tool_use_block_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } diff --git a/runtime/rust/prompty/tests/model/wire/anthropic_usage_test.rs b/runtime/rust/prompty/tests/model/wire/anthropic_usage_test.rs index 7772d548..a1e32542 100644 --- a/runtime/rust/prompty/tests/model/wire/anthropic_usage_test.rs +++ b/runtime/rust/prompty/tests/model/wire/anthropic_usage_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::AnthropicUsage; use prompty::model::context::{LoadContext, SaveContext}; @@ -21,11 +15,7 @@ fn test_anthropic_usage_load_json() { "####; let ctx = LoadContext::default(); let result = AnthropicUsage::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.input_tokens, 150); assert_eq!(instance.output_tokens, 42); @@ -40,11 +30,7 @@ output_tokens: 42 "####; let ctx = LoadContext::default(); let result = AnthropicUsage::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.input_tokens, 150); assert_eq!(instance.output_tokens, 42); @@ -64,9 +50,5 @@ fn test_anthropic_usage_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } diff --git a/runtime/rust/prompty/tests/model/wire/anthropic_wire_message_test.rs b/runtime/rust/prompty/tests/model/wire/anthropic_wire_message_test.rs index c121c4cd..e081b1a0 100644 --- a/runtime/rust/prompty/tests/model/wire/anthropic_wire_message_test.rs +++ b/runtime/rust/prompty/tests/model/wire/anthropic_wire_message_test.rs @@ -1,12 +1,6 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::AnthropicWireMessage; use prompty::model::context::{LoadContext, SaveContext}; @@ -20,11 +14,7 @@ fn test_anthropic_wire_message_load_json() { "####; let ctx = LoadContext::default(); let result = AnthropicWireMessage::from_json(json, &ctx); - assert!( - result.is_ok(), - "Failed to load from JSON: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.role, "user"); } @@ -37,11 +27,7 @@ role: user "####; let ctx = LoadContext::default(); let result = AnthropicWireMessage::from_yaml(yaml, &ctx); - assert!( - result.is_ok(), - "Failed to load from YAML: {:?}", - result.err() - ); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.role, "user"); } @@ -59,9 +45,5 @@ fn test_anthropic_wire_message_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!( - json_output.is_ok(), - "Failed to serialize to JSON: {:?}", - json_output.err() - ); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); } diff --git a/runtime/rust/prompty/tests/model/wire/mod.rs b/runtime/rust/prompty/tests/model/wire/mod.rs index 89b6ff98..0c6ed6dd 100644 --- a/runtime/rust/prompty/tests/model/wire/mod.rs +++ b/runtime/rust/prompty/tests/model/wire/mod.rs @@ -1,20 +1,14 @@ // Code generated by Prompty emitter; DO NOT EDIT. -#![allow( - unused_imports, - dead_code, - non_camel_case_types, - unused_variables, - clippy::all -)] +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] -mod anthropic_image_block_test; -mod anthropic_image_source_test; -mod anthropic_messages_request_test; -mod anthropic_messages_response_test; mod anthropic_text_block_test; -mod anthropic_tool_definition_test; -mod anthropic_tool_result_block_test; +mod anthropic_image_source_test; +mod anthropic_image_block_test; mod anthropic_tool_use_block_test; -mod anthropic_usage_test; +mod anthropic_tool_result_block_test; mod anthropic_wire_message_test; +mod anthropic_tool_definition_test; +mod anthropic_messages_request_test; +mod anthropic_usage_test; +mod anthropic_messages_response_test; diff --git a/runtime/rust/prompty/tests/parse_vectors.rs b/runtime/rust/prompty/tests/parse_vectors.rs index 7d95ef6a..55408422 100644 --- a/runtime/rust/prompty/tests/parse_vectors.rs +++ b/runtime/rust/prompty/tests/parse_vectors.rs @@ -7,7 +7,7 @@ use regex::Regex; use serde_json::Value; use prompty::parsers::parse_chat; -use prompty::types::{ContentPart, ContentPartKind, Message, Role}; +use prompty::types::{ContentPartKind, Message, Role}; /// Path to the parse vectors JSON file. fn vectors_path() -> PathBuf { diff --git a/runtime/typescript/packages/core/src/core/agent-events.ts b/runtime/typescript/packages/core/src/core/agent-events.ts index 9e57170a..cc44f030 100644 --- a/runtime/typescript/packages/core/src/core/agent-events.ts +++ b/runtime/typescript/packages/core/src/core/agent-events.ts @@ -5,9 +5,17 @@ /** Event types emitted during the agent loop. */ export type AgentEventType = + | "turn_start" + | "turn_end" + | "llm_start" + | "llm_complete" + | "retry" + | "permission_requested" + | "permission_completed" | "token" | "thinking" | "tool_call_start" + | "tool_call_complete" | "tool_result" | "status" | "messages_updated" @@ -32,7 +40,16 @@ export function emitEvent( ): void { if (!callback) return; try { - callback(eventType, data); + callback(eventType, { + ...data, + turnEvent: { + id: `evt_${globalThis.crypto?.randomUUID?.() ?? Math.random().toString(36).slice(2)}`, + type: eventType, + timestamp: new Date().toISOString(), + iteration: typeof data.iteration === "number" ? data.iteration : undefined, + payload: data, + }, + }); } catch (err) { // Swallow — event callbacks must not break the loop (§13.1) if (typeof globalThis.console?.debug === "function") { diff --git a/runtime/typescript/packages/core/src/core/pipeline.ts b/runtime/typescript/packages/core/src/core/pipeline.ts index 52206682..fec4e56d 100644 --- a/runtime/typescript/packages/core/src/core/pipeline.ts +++ b/runtime/typescript/packages/core/src/core/pipeline.ts @@ -61,6 +61,19 @@ const DEFAULT_PROVIDER = "openai"; const DEFAULT_MAX_ITERATIONS = 10; const DEFAULT_MAX_LLM_RETRIES = 3; +function emitFailedTurnEnd( + onEvent: EventCallback | undefined, + error: unknown, + iterations: number, + response?: unknown, +): void { + emitEvent(onEvent, "turn_end", { + iterations, + status: error instanceof CancelledError ? "cancelled" : "error", + ...(response !== undefined ? { response } : {}), + }); +} + // --------------------------------------------------------------------------- // ExecuteError (§9.10) // --------------------------------------------------------------------------- @@ -499,6 +512,12 @@ async function invokeWithRetry( emitEvent(onEvent, "status", { message: `LLM call failed, retrying (attempt ${attempts + 1}/${maxRetries})...`, }); + emitEvent(onEvent, "retry", { + operation: "llm", + attempt: attempts + 1, + maxAttempts: maxRetries, + reason: err instanceof Error ? err.message : String(err), + }); // Exponential backoff with jitter, capped at 60s (§9.10) // backoff = min(2^attempts + jitter(), 60) — values in seconds const backoffSecs = Math.min(Math.pow(2, attempts) + Math.random(), 60); @@ -666,11 +685,22 @@ export async function turn( const tools = options?.tools ?? {}; const hasTools = Object.keys(tools).length > 0; + const onEvent = options?.onEvent; + emitEvent(onEvent, "turn_start", { + agent: agent.name, + inputs, + maxIterations: options?.maxIterations ?? DEFAULT_MAX_ITERATIONS, + }); if (!hasTools) { // Simple mode: prepare → [extensions] → executor → [output guard] → process - let messages = await prepare(agent, inputs); - const onEvent = options?.onEvent; + let messages: Message[]; + try { + messages = await prepare(agent, inputs); + } catch (err) { + emitFailedTurnEnd(onEvent, err, 0); + throw err; + } // §13.5 — Drain steering messages if (options?.steering) { @@ -697,23 +727,50 @@ export async function turn( const result = options.guardrails.checkInput(messages); if (!result.allowed) { emitEvent(onEvent, "error", { message: `Input guardrail denied: ${result.reason}` }); + emitFailedTurnEnd(onEvent, new GuardrailError(result.reason ?? "Input guardrail denied"), 0); throw new GuardrailError(result.reason ?? "Input guardrail denied"); } if (result.rewrite) messages = result.rewrite; } // §13.2 — Check cancellation before LLM call - checkCancellation(options?.signal); + try { + checkCancellation(options?.signal); + } catch (err) { + emitEvent(onEvent, "cancelled", {}); + emitFailedTurnEnd(onEvent, err, 0); + throw err; + } const provider = resolveProvider(agent); const executor = getExecutor(provider); - const response = await executor.execute(agent, messages); + emitEvent(onEvent, "llm_start", { + provider, + modelId: agent.model?.id, + messageCount: messages.length, + attempt: 0, + }); + let response: unknown; + try { + response = await executor.execute(agent, messages); + } catch (err) { + emitFailedTurnEnd(onEvent, err, 0); + throw err; + } + emitEvent(onEvent, "llm_complete", {}); if (options?.raw) { emit("result", response); + emitEvent(onEvent, "turn_end", { iterations: 0, status: "success", response }); return response; } - const processed = await process(agent, response); + let processed: unknown; + try { + processed = await process(agent, response); + } catch (err) { + emitFailedTurnEnd(onEvent, err, 0, response); + throw err; + } // §13.4 — Output guardrail on final response if (options?.guardrails) { @@ -722,31 +779,39 @@ export async function turn( const gr = options.guardrails.checkOutput(assistantMsg); if (!gr.allowed) { emitEvent(onEvent, "error", { message: `Output guardrail denied: ${gr.reason}` }); + emitFailedTurnEnd(onEvent, new GuardrailError(gr.reason ?? "Output guardrail denied"), 0, processed); throw new GuardrailError(gr.reason ?? "Output guardrail denied"); } if (gr.rewrite !== undefined) { emit("result", gr.rewrite); emitEvent(onEvent, "done", { response: gr.rewrite, messages }); + emitEvent(onEvent, "turn_end", { iterations: 0, status: "success", response: gr.rewrite }); return gr.rewrite; } } emit("result", sanitizeValue("result", processed)); emitEvent(onEvent, "done", { response: processed, messages }); + emitEvent(onEvent, "turn_end", { iterations: 0, status: "success", response: processed }); return processed; } // Agent mode: prepare → [executor → toolCalls]* → executor → process const maxIterations = options?.maxIterations ?? DEFAULT_MAX_ITERATIONS; const maxLlmRetries = options?.maxLlmRetries ?? DEFAULT_MAX_LLM_RETRIES; - const onEvent = options?.onEvent; const signal = options?.signal; const contextBudget = options?.contextBudget; const guardrails = options?.guardrails; const steering = options?.steering; const parallelToolCalls = options?.parallelToolCalls ?? false; - let messages = await prepare(agent, inputs); + let messages: Message[]; + try { + messages = await prepare(agent, inputs); + } catch (err) { + emitFailedTurnEnd(onEvent, err, 0); + throw err; + } const parentInputs = inputs ?? {}; const provider = resolveProvider(agent); const executor = getExecutor(provider); @@ -760,6 +825,7 @@ export async function turn( checkCancellation(signal); } catch (err) { emitEvent(onEvent, "cancelled", {}); + emitFailedTurnEnd(onEvent, err, iteration); throw err; } @@ -790,6 +856,7 @@ export async function turn( const result = guardrails.checkInput(messages); if (!result.allowed) { emitEvent(onEvent, "error", { message: `Input guardrail denied: ${result.reason}` }); + emitFailedTurnEnd(onEvent, new GuardrailError(result.reason ?? "Input guardrail denied"), iteration); throw new GuardrailError(result.reason ?? "Input guardrail denied"); } if (result.rewrite) messages = result.rewrite; @@ -800,15 +867,36 @@ export async function turn( checkCancellation(signal); } catch (err) { emitEvent(onEvent, "cancelled", {}); + emitFailedTurnEnd(onEvent, err, iteration); throw err; } // Call LLM — §9.10: retry on transient failure - response = await invokeWithRetry(executor, agent, messages, maxLlmRetries, onEvent, signal); + emitEvent(onEvent, "llm_start", { + provider, + modelId: agent.model?.id, + messageCount: messages.length, + attempt: 0, + iteration, + }); + try { + response = await invokeWithRetry(executor, agent, messages, maxLlmRetries, onEvent, signal); + } catch (err) { + emitFailedTurnEnd(onEvent, err, iteration); + throw err; + } + emitEvent(onEvent, "llm_complete", { iteration }); // Streaming: consume the stream, extract tool calls from buffered chunks if (isAsyncIterable(response)) { - const { toolCalls, content } = await consumeStream(agent, response, onEvent); + let streamResult: Awaited>; + try { + streamResult = await consumeStream(agent, response, onEvent); + } catch (err) { + emitFailedTurnEnd(onEvent, err, iteration, response); + throw err; + } + const { toolCalls, content } = streamResult; // §13.4 — Output guardrail if (guardrails && content) { @@ -816,6 +904,7 @@ export async function turn( const gr = guardrails.checkOutput(assistantMsg); if (!gr.allowed) { emitEvent(onEvent, "error", { message: `Output guardrail denied: ${gr.reason}` }); + emitFailedTurnEnd(onEvent, new GuardrailError(gr.reason ?? "Output guardrail denied"), iteration, content); throw new GuardrailError(gr.reason ?? "Output guardrail denied"); } } @@ -824,27 +913,35 @@ export async function turn( emit("iterations", iteration); emit("result", content); emitEvent(onEvent, "done", { response: content, messages }); + emitEvent(onEvent, "turn_end", { iterations: iteration, status: "success", response: content }); return content; } iteration++; if (iteration > maxIterations) { + emitFailedTurnEnd(onEvent, new Error("Agent loop exceeded maxIterations"), iteration); throw new Error( `Agent loop exceeded maxIterations (${maxIterations}). ` + `The model kept requesting tool calls. Increase maxIterations or check your tools.`, ); } - const toolMessages = await traceSpan("toolCalls", async (toolEmit) => { - toolEmit("signature", "prompty.turn.toolCalls"); - toolEmit("description", `Tool call round ${iteration}`); - const result = await buildToolMessagesFromCallsWithExtensions( - toolCalls, content, tools, agent, parentInputs, toolEmit, - { onEvent, signal, guardrails, parallel: parallelToolCalls }, - ); - toolEmit("result", result.map((m) => ({ role: m.role, content: m.parts.map((p) => (p as { value?: string }).value ?? "").join(""), metadata: m.metadata }))); - return result; - }); + let toolMessages: Message[]; + try { + toolMessages = await traceSpan("toolCalls", async (toolEmit) => { + toolEmit("signature", "prompty.turn.toolCalls"); + toolEmit("description", `Tool call round ${iteration}`); + const result = await buildToolMessagesFromCallsWithExtensions( + toolCalls, content, tools, agent, parentInputs, toolEmit, + { onEvent, signal, guardrails, parallel: parallelToolCalls }, + ); + toolEmit("result", result.map((m) => ({ role: m.role, content: m.parts.map((p) => (p as { value?: string }).value ?? "").join(""), metadata: m.metadata }))); + return result; + }); + } catch (err) { + emitFailedTurnEnd(onEvent, err, iteration, content); + throw err; + } messages.push(...toolMessages); emitEvent(onEvent, "messages_updated", { messages }); @@ -853,25 +950,34 @@ export async function turn( // Non-streaming: check raw response for tool calls if (!hasToolCalls(response)) { - const finalResult = options?.raw ? response : await process(agent, response); + let finalResult: unknown; + try { + finalResult = options?.raw ? response : await process(agent, response); + } catch (err) { + emitFailedTurnEnd(onEvent, err, iteration, response); + throw err; + } if (guardrails) { const contentStr = typeof finalResult === "string" ? finalResult : JSON.stringify(finalResult); const assistantMsg = new Message({ role: "assistant", parts: [text(contentStr)] }); const gr = guardrails.checkOutput(assistantMsg); if (!gr.allowed) { emitEvent(onEvent, "error", { message: `Output guardrail denied: ${gr.reason}` }); + emitFailedTurnEnd(onEvent, new GuardrailError(gr.reason ?? "Output guardrail denied"), iteration, finalResult); throw new GuardrailError(gr.reason ?? "Output guardrail denied"); } if (gr.rewrite !== undefined) { emit("iterations", iteration); emit("result", gr.rewrite); emitEvent(onEvent, "done", { response: gr.rewrite, messages }); + emitEvent(onEvent, "turn_end", { iterations: iteration, status: "success", response: gr.rewrite }); return gr.rewrite; } } emit("iterations", iteration); emit("result", finalResult); emitEvent(onEvent, "done", { response: finalResult, messages }); + emitEvent(onEvent, "turn_end", { iterations: iteration, status: "success", response: finalResult }); return finalResult; } @@ -883,6 +989,7 @@ export async function turn( const gr = guardrails.checkOutput(assistantMsg); if (!gr.allowed) { emitEvent(onEvent, "error", { message: `Output guardrail denied: ${gr.reason}` }); + emitFailedTurnEnd(onEvent, new GuardrailError(gr.reason ?? "Output guardrail denied"), iteration, textContent); throw new GuardrailError(gr.reason ?? "Output guardrail denied"); } } @@ -890,22 +997,29 @@ export async function turn( iteration++; if (iteration > maxIterations) { + emitFailedTurnEnd(onEvent, new Error("Agent loop exceeded maxIterations"), iteration); throw new Error( `Agent loop exceeded maxIterations (${maxIterations}). ` + `The model kept requesting tool calls. Increase maxIterations or check your tools.`, ); } - const toolMessages = await traceSpan("toolCalls", async (toolEmit) => { - toolEmit("signature", "prompty.turn.toolCalls"); - toolEmit("description", `Tool call round ${iteration}`); - const result = await buildToolResultMessagesWithExtensions( - response, tools, agent, parentInputs, toolEmit, - { onEvent, signal, guardrails, parallel: parallelToolCalls }, - ); - toolEmit("result", result.map((m) => ({ role: m.role, content: m.parts.map((p) => (p as { value?: string }).value ?? "").join(""), metadata: m.metadata }))); - return result; - }); + let toolMessages: Message[]; + try { + toolMessages = await traceSpan("toolCalls", async (toolEmit) => { + toolEmit("signature", "prompty.turn.toolCalls"); + toolEmit("description", `Tool call round ${iteration}`); + const result = await buildToolResultMessagesWithExtensions( + response, tools, agent, parentInputs, toolEmit, + { onEvent, signal, guardrails, parallel: parallelToolCalls }, + ); + toolEmit("result", result.map((m) => ({ role: m.role, content: m.parts.map((p) => (p as { value?: string }).value ?? "").join(""), metadata: m.metadata }))); + return result; + }); + } catch (err) { + emitFailedTurnEnd(onEvent, err, iteration, response); + throw err; + } messages.push(...toolMessages); emitEvent(onEvent, "messages_updated", { messages }); @@ -1207,7 +1321,8 @@ async function dispatchOneToolWithExtensions( } // §13.1 — Emit tool_call_start - emitEvent(onEvent, "tool_call_start", { name: tc.name, arguments: tc.arguments }); + emitEvent(onEvent, "tool_call_start", { id: tc.id, name: tc.name, arguments: tc.arguments }); + const started = performance.now(); // §13.4 — Tool guardrail if (guardrails) { @@ -1216,6 +1331,14 @@ async function dispatchOneToolWithExtensions( if (!gr.allowed) { const deniedMsg = `Tool denied by guardrail: ${gr.reason}`; emitEvent(onEvent, "tool_result", { name: tc.name, result: deniedMsg }); + emitEvent(onEvent, "tool_call_complete", { + id: tc.id, + name: tc.name, + success: false, + result: deniedMsg, + durationMs: performance.now() - started, + errorKind: "guardrail_denied", + }); return deniedMsg; } if (gr.rewrite !== undefined) { @@ -1233,6 +1356,14 @@ async function dispatchOneToolWithExtensions( result = `Error: Tool '${tc.name}' received unparseable arguments`; emitEvent(onEvent, "error", { tool: tc.name, error: "Unparseable tool arguments" }); emitEvent(onEvent, "tool_result", { name: tc.name, result }); + emitEvent(onEvent, "tool_call_complete", { + id: tc.id, + name: tc.name, + success: false, + result, + durationMs: performance.now() - started, + errorKind: "invalid_arguments", + }); return result; } if (agent && parentInputs && typeof parsedArgs === "object" && parsedArgs !== null && !Array.isArray(parsedArgs)) { @@ -1257,6 +1388,15 @@ async function dispatchOneToolWithExtensions( // §13.1 — Emit tool_result emitEvent(onEvent, "tool_result", { name: tc.name, result }); + const success = !result.startsWith("Error:"); + emitEvent(onEvent, "tool_call_complete", { + id: tc.id, + name: tc.name, + success, + result, + durationMs: performance.now() - started, + errorKind: success ? undefined : "tool_error", + }); // §9.9 — Emit error event when tool result indicates failure if (result.startsWith("Error:")) { diff --git a/runtime/typescript/packages/core/src/model/conversation/tool-result.ts b/runtime/typescript/packages/core/src/model/conversation/tool-result.ts index ad5d4fa1..0bf3e59c 100644 --- a/runtime/typescript/packages/core/src/model/conversation/tool-result.ts +++ b/runtime/typescript/packages/core/src/model/conversation/tool-result.ts @@ -4,13 +4,31 @@ import { LoadContext, SaveContext } from "../context"; import { ContentPart, TextPart } from "./content-part"; +export type ToolResultStatus = "success" | "error" | "cancelled" | "timeout"; + export class ToolResult { static readonly shorthandProperty: string | undefined = undefined; parts: ContentPart[] = []; + status?: ToolResultStatus | undefined; + errorKind?: string | undefined; + errorMessage?: string | undefined; + durationMs?: number | undefined; constructor(init?: Partial) { this.parts = init?.parts ?? []; + if (init?.status !== undefined) { + this.status = init.status; + } + if (init?.errorKind !== undefined) { + this.errorKind = init.errorKind; + } + if (init?.errorMessage !== undefined) { + this.errorMessage = init.errorMessage; + } + if (init?.durationMs !== undefined) { + this.durationMs = init.durationMs; + } } //#region Load Methods @@ -31,6 +49,18 @@ export class ToolResult { context, ); } + if (data["status"] !== undefined && data["status"] !== null) { + instance.status = String(data["status"]) as ToolResultStatus; + } + if (data["errorKind"] !== undefined && data["errorKind"] !== null) { + instance.errorKind = String(data["errorKind"]); + } + if (data["errorMessage"] !== undefined && data["errorMessage"] !== null) { + instance.errorMessage = String(data["errorMessage"]); + } + if (data["durationMs"] !== undefined && data["durationMs"] !== null) { + instance.durationMs = Number(data["durationMs"]); + } if (context) { return context.processOutput(instance) as ToolResult; @@ -86,6 +116,18 @@ export class ToolResult { if (obj.parts !== undefined && obj.parts !== null) { result["parts"] = ToolResult.saveParts(obj.parts, context); } + if (obj.status !== undefined && obj.status !== null) { + result["status"] = obj.status; + } + if (obj.errorKind !== undefined && obj.errorKind !== null) { + result["errorKind"] = obj.errorKind; + } + if (obj.errorMessage !== undefined && obj.errorMessage !== null) { + result["errorMessage"] = obj.errorMessage; + } + if (obj.durationMs !== undefined && obj.durationMs !== null) { + result["durationMs"] = obj.durationMs; + } if (context) { return context.processDict(result); diff --git a/runtime/typescript/packages/core/src/model/events/compaction-complete-payload.ts b/runtime/typescript/packages/core/src/model/events/compaction-complete-payload.ts index 245dbb51..53ef6cca 100644 --- a/runtime/typescript/packages/core/src/model/events/compaction-complete-payload.ts +++ b/runtime/typescript/packages/core/src/model/events/compaction-complete-payload.ts @@ -8,10 +8,14 @@ export class CompactionCompletePayload { removed: number = 0; remaining: number = 0; + summaryLength?: number | undefined; constructor(init?: Partial) { this.removed = init?.removed ?? 0; this.remaining = init?.remaining ?? 0; + if (init?.summaryLength !== undefined) { + this.summaryLength = init.summaryLength; + } } //#region Load Methods @@ -32,6 +36,9 @@ export class CompactionCompletePayload { if (data["remaining"] !== undefined && data["remaining"] !== null) { instance.remaining = Number(data["remaining"]); } + if (data["summaryLength"] !== undefined && data["summaryLength"] !== null) { + instance.summaryLength = Number(data["summaryLength"]); + } if (context) { return context.processOutput(instance) as CompactionCompletePayload; @@ -57,6 +64,9 @@ export class CompactionCompletePayload { if (obj.remaining !== undefined && obj.remaining !== null) { result["remaining"] = obj.remaining; } + if (obj.summaryLength !== undefined && obj.summaryLength !== null) { + result["summaryLength"] = obj.summaryLength; + } if (context) { return context.processDict(result); diff --git a/runtime/typescript/packages/core/src/model/events/compaction-start-payload.ts b/runtime/typescript/packages/core/src/model/events/compaction-start-payload.ts new file mode 100644 index 00000000..aab36724 --- /dev/null +++ b/runtime/typescript/packages/core/src/model/events/compaction-start-payload.ts @@ -0,0 +1,87 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { LoadContext, SaveContext } from "../context"; + +export class CompactionStartPayload { + static readonly shorthandProperty: string | undefined = undefined; + + droppedCount: number = 0; + + constructor(init?: Partial) { + this.droppedCount = init?.droppedCount ?? 0; + } + + //#region Load Methods + + static load( + data: Record, + context?: LoadContext, + ): CompactionStartPayload { + if (context) { + data = context.processInput(data) as Record; + } + + const instance = new CompactionStartPayload(); + + if (data["droppedCount"] !== undefined && data["droppedCount"] !== null) { + instance.droppedCount = Number(data["droppedCount"]); + } + + if (context) { + return context.processOutput(instance) as CompactionStartPayload; + } + return instance; + } + + //#endregion + + //#region Save Methods + + save(context?: SaveContext): Record { + let obj: this = this; + if (context) { + obj = context.processObject(obj) as this; + } + + const result: Record = {}; + + if (obj.droppedCount !== undefined && obj.droppedCount !== null) { + result["droppedCount"] = obj.droppedCount; + } + + if (context) { + return context.processDict(result); + } + return result; + } + + toYaml(context?: SaveContext): string { + context = context ?? new SaveContext(); + return context.toYaml(this.save(context)); + } + + toJson(context?: SaveContext, indent: number = 2): string { + context = context ?? new SaveContext(); + return context.toJson(this.save(context), indent); + } + + static fromJson(json: string, context?: LoadContext): CompactionStartPayload { + const data = JSON.parse(json); + return CompactionStartPayload.load( + data as Record, + context, + ); + } + + static fromYaml(yaml: string, context?: LoadContext): CompactionStartPayload { + const { parse } = require("yaml"); + const data = parse(yaml); + return CompactionStartPayload.load( + data as Record, + context, + ); + } + + //#endregion +} diff --git a/runtime/typescript/packages/core/src/model/events/done-event-payload.ts b/runtime/typescript/packages/core/src/model/events/done-event-payload.ts index e83f047f..2e42b467 100644 --- a/runtime/typescript/packages/core/src/model/events/done-event-payload.ts +++ b/runtime/typescript/packages/core/src/model/events/done-event-payload.ts @@ -7,7 +7,7 @@ import { Message } from "../conversation/message"; export class DoneEventPayload { static readonly shorthandProperty: string | undefined = undefined; - response: string = ""; + response: unknown; messages: Message[] = []; constructor(init?: Partial) { @@ -28,7 +28,7 @@ export class DoneEventPayload { const instance = new DoneEventPayload(); if (data["response"] !== undefined && data["response"] !== null) { - instance.response = String(data["response"]); + instance.response = data["response"] as unknown; } if (data["messages"] !== undefined && data["messages"] !== null) { instance.messages = DoneEventPayload.loadMessages( diff --git a/runtime/typescript/packages/core/src/model/events/error-event-payload.ts b/runtime/typescript/packages/core/src/model/events/error-event-payload.ts index 8a83802f..048c70dc 100644 --- a/runtime/typescript/packages/core/src/model/events/error-event-payload.ts +++ b/runtime/typescript/packages/core/src/model/events/error-event-payload.ts @@ -7,9 +7,17 @@ export class ErrorEventPayload { static readonly shorthandProperty: string | undefined = undefined; message: string = ""; + errorKind?: string | undefined; + phase?: string | undefined; constructor(init?: Partial) { this.message = init?.message ?? ""; + if (init?.errorKind !== undefined) { + this.errorKind = init.errorKind; + } + if (init?.phase !== undefined) { + this.phase = init.phase; + } } //#region Load Methods @@ -27,6 +35,12 @@ export class ErrorEventPayload { if (data["message"] !== undefined && data["message"] !== null) { instance.message = String(data["message"]); } + if (data["errorKind"] !== undefined && data["errorKind"] !== null) { + instance.errorKind = String(data["errorKind"]); + } + if (data["phase"] !== undefined && data["phase"] !== null) { + instance.phase = String(data["phase"]); + } if (context) { return context.processOutput(instance) as ErrorEventPayload; @@ -49,6 +63,12 @@ export class ErrorEventPayload { if (obj.message !== undefined && obj.message !== null) { result["message"] = obj.message; } + if (obj.errorKind !== undefined && obj.errorKind !== null) { + result["errorKind"] = obj.errorKind; + } + if (obj.phase !== undefined && obj.phase !== null) { + result["phase"] = obj.phase; + } if (context) { return context.processDict(result); diff --git a/runtime/typescript/packages/core/src/model/events/index.ts b/runtime/typescript/packages/core/src/model/events/index.ts index 0025477f..34d8f612 100644 --- a/runtime/typescript/packages/core/src/model/events/index.ts +++ b/runtime/typescript/packages/core/src/model/events/index.ts @@ -1,16 +1,28 @@ // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. +export { TurnEvent } from "./turn-event"; +export { TurnStartPayload } from "./turn-start-payload"; +export { TurnEndPayload } from "./turn-end-payload"; +export { LlmStartPayload } from "./llm-start-payload"; +export { LlmCompletePayload } from "./llm-complete-payload"; +export { RetryPayload } from "./retry-payload"; +export { PermissionRequestedPayload } from "./permission-requested-payload"; +export { PermissionCompletedPayload } from "./permission-completed-payload"; export { TokenEventPayload } from "./token-event-payload"; export { ThinkingEventPayload } from "./thinking-event-payload"; export { ToolCallStartPayload } from "./tool-call-start-payload"; +export { ToolCallCompletePayload } from "./tool-call-complete-payload"; export { ToolResultPayload } from "./tool-result-payload"; export { StatusEventPayload } from "./status-event-payload"; export { MessagesUpdatedPayload } from "./messages-updated-payload"; export { DoneEventPayload } from "./done-event-payload"; export { ErrorEventPayload } from "./error-event-payload"; +export { CompactionStartPayload } from "./compaction-start-payload"; export { CompactionCompletePayload } from "./compaction-complete-payload"; export { CompactionFailedPayload } from "./compaction-failed-payload"; +export { TurnSummary } from "./turn-summary"; +export { TurnTrace } from "./turn-trace"; export { StreamChunk, TextChunk, diff --git a/runtime/typescript/packages/core/src/model/events/llm-complete-payload.ts b/runtime/typescript/packages/core/src/model/events/llm-complete-payload.ts new file mode 100644 index 00000000..b3496839 --- /dev/null +++ b/runtime/typescript/packages/core/src/model/events/llm-complete-payload.ts @@ -0,0 +1,120 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { LoadContext, SaveContext } from "../context"; +import { TokenUsage } from "../model/token-usage"; + +export class LlmCompletePayload { + static readonly shorthandProperty: string | undefined = undefined; + + requestId?: string | undefined; + serviceRequestId?: string | undefined; + usage?: TokenUsage | undefined; + durationMs?: number | undefined; + + constructor(init?: Partial) { + if (init?.requestId !== undefined) { + this.requestId = init.requestId; + } + if (init?.serviceRequestId !== undefined) { + this.serviceRequestId = init.serviceRequestId; + } + if (init?.usage !== undefined) { + this.usage = init.usage; + } + if (init?.durationMs !== undefined) { + this.durationMs = init.durationMs; + } + } + + //#region Load Methods + + static load( + data: Record, + context?: LoadContext, + ): LlmCompletePayload { + if (context) { + data = context.processInput(data) as Record; + } + + const instance = new LlmCompletePayload(); + + if (data["requestId"] !== undefined && data["requestId"] !== null) { + instance.requestId = String(data["requestId"]); + } + if ( + data["serviceRequestId"] !== undefined && + data["serviceRequestId"] !== null + ) { + instance.serviceRequestId = String(data["serviceRequestId"]); + } + if (data["usage"] !== undefined && data["usage"] !== null) { + instance.usage = TokenUsage.load( + data["usage"] as Record, + context, + ); + } + if (data["durationMs"] !== undefined && data["durationMs"] !== null) { + instance.durationMs = Number(data["durationMs"]); + } + + if (context) { + return context.processOutput(instance) as LlmCompletePayload; + } + return instance; + } + + //#endregion + + //#region Save Methods + + save(context?: SaveContext): Record { + let obj: this = this; + if (context) { + obj = context.processObject(obj) as this; + } + + const result: Record = {}; + + if (obj.requestId !== undefined && obj.requestId !== null) { + result["requestId"] = obj.requestId; + } + if (obj.serviceRequestId !== undefined && obj.serviceRequestId !== null) { + result["serviceRequestId"] = obj.serviceRequestId; + } + if (obj.usage !== undefined && obj.usage !== null) { + result["usage"] = obj.usage.save(context); + } + if (obj.durationMs !== undefined && obj.durationMs !== null) { + result["durationMs"] = obj.durationMs; + } + + if (context) { + return context.processDict(result); + } + return result; + } + + toYaml(context?: SaveContext): string { + context = context ?? new SaveContext(); + return context.toYaml(this.save(context)); + } + + toJson(context?: SaveContext, indent: number = 2): string { + context = context ?? new SaveContext(); + return context.toJson(this.save(context), indent); + } + + static fromJson(json: string, context?: LoadContext): LlmCompletePayload { + const data = JSON.parse(json); + return LlmCompletePayload.load(data as Record, context); + } + + static fromYaml(yaml: string, context?: LoadContext): LlmCompletePayload { + const { parse } = require("yaml"); + const data = parse(yaml); + return LlmCompletePayload.load(data as Record, context); + } + + //#endregion +} diff --git a/runtime/typescript/packages/core/src/model/events/llm-start-payload.ts b/runtime/typescript/packages/core/src/model/events/llm-start-payload.ts new file mode 100644 index 00000000..a98702fb --- /dev/null +++ b/runtime/typescript/packages/core/src/model/events/llm-start-payload.ts @@ -0,0 +1,113 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { LoadContext, SaveContext } from "../context"; + +export class LlmStartPayload { + static readonly shorthandProperty: string | undefined = undefined; + + provider?: string | undefined; + modelId?: string | undefined; + messageCount?: number | undefined; + attempt?: number | undefined; + + constructor(init?: Partial) { + if (init?.provider !== undefined) { + this.provider = init.provider; + } + if (init?.modelId !== undefined) { + this.modelId = init.modelId; + } + if (init?.messageCount !== undefined) { + this.messageCount = init.messageCount; + } + if (init?.attempt !== undefined) { + this.attempt = init.attempt; + } + } + + //#region Load Methods + + static load( + data: Record, + context?: LoadContext, + ): LlmStartPayload { + if (context) { + data = context.processInput(data) as Record; + } + + const instance = new LlmStartPayload(); + + if (data["provider"] !== undefined && data["provider"] !== null) { + instance.provider = String(data["provider"]); + } + if (data["modelId"] !== undefined && data["modelId"] !== null) { + instance.modelId = String(data["modelId"]); + } + if (data["messageCount"] !== undefined && data["messageCount"] !== null) { + instance.messageCount = Number(data["messageCount"]); + } + if (data["attempt"] !== undefined && data["attempt"] !== null) { + instance.attempt = Number(data["attempt"]); + } + + if (context) { + return context.processOutput(instance) as LlmStartPayload; + } + return instance; + } + + //#endregion + + //#region Save Methods + + save(context?: SaveContext): Record { + let obj: this = this; + if (context) { + obj = context.processObject(obj) as this; + } + + const result: Record = {}; + + if (obj.provider !== undefined && obj.provider !== null) { + result["provider"] = obj.provider; + } + if (obj.modelId !== undefined && obj.modelId !== null) { + result["modelId"] = obj.modelId; + } + if (obj.messageCount !== undefined && obj.messageCount !== null) { + result["messageCount"] = obj.messageCount; + } + if (obj.attempt !== undefined && obj.attempt !== null) { + result["attempt"] = obj.attempt; + } + + if (context) { + return context.processDict(result); + } + return result; + } + + toYaml(context?: SaveContext): string { + context = context ?? new SaveContext(); + return context.toYaml(this.save(context)); + } + + toJson(context?: SaveContext, indent: number = 2): string { + context = context ?? new SaveContext(); + return context.toJson(this.save(context), indent); + } + + static fromJson(json: string, context?: LoadContext): LlmStartPayload { + const data = JSON.parse(json); + return LlmStartPayload.load(data as Record, context); + } + + static fromYaml(yaml: string, context?: LoadContext): LlmStartPayload { + const { parse } = require("yaml"); + const data = parse(yaml); + return LlmStartPayload.load(data as Record, context); + } + + //#endregion +} diff --git a/runtime/typescript/packages/core/src/model/events/messages-updated-payload.ts b/runtime/typescript/packages/core/src/model/events/messages-updated-payload.ts index 2a6af48a..191507eb 100644 --- a/runtime/typescript/packages/core/src/model/events/messages-updated-payload.ts +++ b/runtime/typescript/packages/core/src/model/events/messages-updated-payload.ts @@ -7,10 +7,24 @@ import { Message } from "../conversation/message"; export class MessagesUpdatedPayload { static readonly shorthandProperty: string | undefined = undefined; - messages: Message[] = []; + messages?: Message[] = []; + reason?: string | undefined; + appended?: Message[] = []; + removed?: number | undefined; constructor(init?: Partial) { - this.messages = init?.messages ?? []; + if (init?.messages !== undefined) { + this.messages = init.messages; + } + if (init?.reason !== undefined) { + this.reason = init.reason; + } + if (init?.appended !== undefined) { + this.appended = init.appended; + } + if (init?.removed !== undefined) { + this.removed = init.removed; + } } //#region Load Methods @@ -31,6 +45,18 @@ export class MessagesUpdatedPayload { context, ); } + if (data["reason"] !== undefined && data["reason"] !== null) { + instance.reason = String(data["reason"]); + } + if (data["appended"] !== undefined && data["appended"] !== null) { + instance.appended = MessagesUpdatedPayload.loadAppended( + data["appended"] as unknown[], + context, + ); + } + if (data["removed"] !== undefined && data["removed"] !== null) { + instance.removed = Number(data["removed"]); + } if (context) { return context.processOutput(instance) as MessagesUpdatedPayload; @@ -71,6 +97,39 @@ export class MessagesUpdatedPayload { return items.map((item) => item.save(context)); } + static loadAppended( + data: Record[] | unknown[], + context?: LoadContext, + ): Message[] { + if (!Array.isArray(data)) { + // Convert dict/object format to array format + const result: Record[] = []; + for (const [k, v] of Object.entries(data)) { + if (typeof v === "object" && v !== null && !Array.isArray(v)) { + result.push({ name: k, ...(v as Record) }); + } else { + result.push({ name: k, role: v }); + } + } + data = result; + } + return data.map((item) => + Message.load(item as Record, context), + ); + } + + static saveAppended( + items: Message[], + context?: SaveContext, + ): Record[] | Record { + if (!context) { + context = new SaveContext(); + } + + // This type doesn't have a 'name' property, so always use array format + return items.map((item) => item.save(context)); + } + //#endregion //#region Save Methods @@ -89,6 +148,18 @@ export class MessagesUpdatedPayload { context, ); } + if (obj.reason !== undefined && obj.reason !== null) { + result["reason"] = obj.reason; + } + if (obj.appended !== undefined && obj.appended !== null) { + result["appended"] = MessagesUpdatedPayload.saveAppended( + obj.appended, + context, + ); + } + if (obj.removed !== undefined && obj.removed !== null) { + result["removed"] = obj.removed; + } if (context) { return context.processDict(result); diff --git a/runtime/typescript/packages/core/src/model/events/permission-completed-payload.ts b/runtime/typescript/packages/core/src/model/events/permission-completed-payload.ts new file mode 100644 index 00000000..0ab61ace --- /dev/null +++ b/runtime/typescript/packages/core/src/model/events/permission-completed-payload.ts @@ -0,0 +1,111 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { LoadContext, SaveContext } from "../context"; + +export class PermissionCompletedPayload { + static readonly shorthandProperty: string | undefined = undefined; + + permission: string = ""; + approved: boolean = false; + reason?: string | undefined; + + constructor(init?: Partial) { + this.permission = init?.permission ?? ""; + this.approved = init?.approved ?? false; + if (init?.reason !== undefined) { + this.reason = init.reason; + } + } + + //#region Load Methods + + static load( + data: Record, + context?: LoadContext, + ): PermissionCompletedPayload { + if (context) { + data = context.processInput(data) as Record; + } + + const instance = new PermissionCompletedPayload(); + + if (data["permission"] !== undefined && data["permission"] !== null) { + instance.permission = String(data["permission"]); + } + if (data["approved"] !== undefined && data["approved"] !== null) { + instance.approved = Boolean(data["approved"]); + } + if (data["reason"] !== undefined && data["reason"] !== null) { + instance.reason = String(data["reason"]); + } + + if (context) { + return context.processOutput(instance) as PermissionCompletedPayload; + } + return instance; + } + + //#endregion + + //#region Save Methods + + save(context?: SaveContext): Record { + let obj: this = this; + if (context) { + obj = context.processObject(obj) as this; + } + + const result: Record = {}; + + if (obj.permission !== undefined && obj.permission !== null) { + result["permission"] = obj.permission; + } + if (obj.approved !== undefined && obj.approved !== null) { + result["approved"] = obj.approved; + } + if (obj.reason !== undefined && obj.reason !== null) { + result["reason"] = obj.reason; + } + + if (context) { + return context.processDict(result); + } + return result; + } + + toYaml(context?: SaveContext): string { + context = context ?? new SaveContext(); + return context.toYaml(this.save(context)); + } + + toJson(context?: SaveContext, indent: number = 2): string { + context = context ?? new SaveContext(); + return context.toJson(this.save(context), indent); + } + + static fromJson( + json: string, + context?: LoadContext, + ): PermissionCompletedPayload { + const data = JSON.parse(json); + return PermissionCompletedPayload.load( + data as Record, + context, + ); + } + + static fromYaml( + yaml: string, + context?: LoadContext, + ): PermissionCompletedPayload { + const { parse } = require("yaml"); + const data = parse(yaml); + return PermissionCompletedPayload.load( + data as Record, + context, + ); + } + + //#endregion +} diff --git a/runtime/typescript/packages/core/src/model/events/permission-requested-payload.ts b/runtime/typescript/packages/core/src/model/events/permission-requested-payload.ts new file mode 100644 index 00000000..a7f8483c --- /dev/null +++ b/runtime/typescript/packages/core/src/model/events/permission-requested-payload.ts @@ -0,0 +1,113 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { LoadContext, SaveContext } from "../context"; + +export class PermissionRequestedPayload { + static readonly shorthandProperty: string | undefined = undefined; + + permission: string = ""; + target?: string | undefined; + details?: Record | undefined; + + constructor(init?: Partial) { + this.permission = init?.permission ?? ""; + if (init?.target !== undefined) { + this.target = init.target; + } + if (init?.details !== undefined) { + this.details = init.details; + } + } + + //#region Load Methods + + static load( + data: Record, + context?: LoadContext, + ): PermissionRequestedPayload { + if (context) { + data = context.processInput(data) as Record; + } + + const instance = new PermissionRequestedPayload(); + + if (data["permission"] !== undefined && data["permission"] !== null) { + instance.permission = String(data["permission"]); + } + if (data["target"] !== undefined && data["target"] !== null) { + instance.target = String(data["target"]); + } + if (data["details"] !== undefined && data["details"] !== null) { + instance.details = data["details"] as Record; + } + + if (context) { + return context.processOutput(instance) as PermissionRequestedPayload; + } + return instance; + } + + //#endregion + + //#region Save Methods + + save(context?: SaveContext): Record { + let obj: this = this; + if (context) { + obj = context.processObject(obj) as this; + } + + const result: Record = {}; + + if (obj.permission !== undefined && obj.permission !== null) { + result["permission"] = obj.permission; + } + if (obj.target !== undefined && obj.target !== null) { + result["target"] = obj.target; + } + if (obj.details !== undefined && obj.details !== null) { + result["details"] = obj.details; + } + + if (context) { + return context.processDict(result); + } + return result; + } + + toYaml(context?: SaveContext): string { + context = context ?? new SaveContext(); + return context.toYaml(this.save(context)); + } + + toJson(context?: SaveContext, indent: number = 2): string { + context = context ?? new SaveContext(); + return context.toJson(this.save(context), indent); + } + + static fromJson( + json: string, + context?: LoadContext, + ): PermissionRequestedPayload { + const data = JSON.parse(json); + return PermissionRequestedPayload.load( + data as Record, + context, + ); + } + + static fromYaml( + yaml: string, + context?: LoadContext, + ): PermissionRequestedPayload { + const { parse } = require("yaml"); + const data = parse(yaml); + return PermissionRequestedPayload.load( + data as Record, + context, + ); + } + + //#endregion +} diff --git a/runtime/typescript/packages/core/src/model/events/retry-payload.ts b/runtime/typescript/packages/core/src/model/events/retry-payload.ts new file mode 100644 index 00000000..100a48e2 --- /dev/null +++ b/runtime/typescript/packages/core/src/model/events/retry-payload.ts @@ -0,0 +1,119 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { LoadContext, SaveContext } from "../context"; + +export class RetryPayload { + static readonly shorthandProperty: string | undefined = undefined; + + operation: string = ""; + attempt: number = 0; + maxAttempts?: number | undefined; + delayMs?: number | undefined; + reason?: string | undefined; + + constructor(init?: Partial) { + this.operation = init?.operation ?? ""; + this.attempt = init?.attempt ?? 0; + if (init?.maxAttempts !== undefined) { + this.maxAttempts = init.maxAttempts; + } + if (init?.delayMs !== undefined) { + this.delayMs = init.delayMs; + } + if (init?.reason !== undefined) { + this.reason = init.reason; + } + } + + //#region Load Methods + + static load( + data: Record, + context?: LoadContext, + ): RetryPayload { + if (context) { + data = context.processInput(data) as Record; + } + + const instance = new RetryPayload(); + + if (data["operation"] !== undefined && data["operation"] !== null) { + instance.operation = String(data["operation"]); + } + if (data["attempt"] !== undefined && data["attempt"] !== null) { + instance.attempt = Number(data["attempt"]); + } + if (data["maxAttempts"] !== undefined && data["maxAttempts"] !== null) { + instance.maxAttempts = Number(data["maxAttempts"]); + } + if (data["delayMs"] !== undefined && data["delayMs"] !== null) { + instance.delayMs = Number(data["delayMs"]); + } + if (data["reason"] !== undefined && data["reason"] !== null) { + instance.reason = String(data["reason"]); + } + + if (context) { + return context.processOutput(instance) as RetryPayload; + } + return instance; + } + + //#endregion + + //#region Save Methods + + save(context?: SaveContext): Record { + let obj: this = this; + if (context) { + obj = context.processObject(obj) as this; + } + + const result: Record = {}; + + if (obj.operation !== undefined && obj.operation !== null) { + result["operation"] = obj.operation; + } + if (obj.attempt !== undefined && obj.attempt !== null) { + result["attempt"] = obj.attempt; + } + if (obj.maxAttempts !== undefined && obj.maxAttempts !== null) { + result["maxAttempts"] = obj.maxAttempts; + } + if (obj.delayMs !== undefined && obj.delayMs !== null) { + result["delayMs"] = obj.delayMs; + } + if (obj.reason !== undefined && obj.reason !== null) { + result["reason"] = obj.reason; + } + + if (context) { + return context.processDict(result); + } + return result; + } + + toYaml(context?: SaveContext): string { + context = context ?? new SaveContext(); + return context.toYaml(this.save(context)); + } + + toJson(context?: SaveContext, indent: number = 2): string { + context = context ?? new SaveContext(); + return context.toJson(this.save(context), indent); + } + + static fromJson(json: string, context?: LoadContext): RetryPayload { + const data = JSON.parse(json); + return RetryPayload.load(data as Record, context); + } + + static fromYaml(yaml: string, context?: LoadContext): RetryPayload { + const { parse } = require("yaml"); + const data = parse(yaml); + return RetryPayload.load(data as Record, context); + } + + //#endregion +} diff --git a/runtime/typescript/packages/core/src/model/events/tool-call-complete-payload.ts b/runtime/typescript/packages/core/src/model/events/tool-call-complete-payload.ts new file mode 100644 index 00000000..8245af79 --- /dev/null +++ b/runtime/typescript/packages/core/src/model/events/tool-call-complete-payload.ts @@ -0,0 +1,145 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { LoadContext, SaveContext } from "../context"; +import { ToolResult } from "../conversation/tool-result"; + +export class ToolCallCompletePayload { + static readonly shorthandProperty: string | undefined = undefined; + + id?: string | undefined; + name: string = ""; + success: boolean = false; + result?: ToolResult | undefined; + durationMs?: number | undefined; + errorKind?: string | undefined; + + constructor(init?: Partial) { + if (init?.id !== undefined) { + this.id = init.id; + } + this.name = init?.name ?? ""; + this.success = init?.success ?? false; + if (init?.result !== undefined) { + this.result = init.result; + } + if (init?.durationMs !== undefined) { + this.durationMs = init.durationMs; + } + if (init?.errorKind !== undefined) { + this.errorKind = init.errorKind; + } + } + + //#region Load Methods + + static load( + data: Record, + context?: LoadContext, + ): ToolCallCompletePayload { + if (context) { + data = context.processInput(data) as Record; + } + + const instance = new ToolCallCompletePayload(); + + if (data["id"] !== undefined && data["id"] !== null) { + instance.id = String(data["id"]); + } + if (data["name"] !== undefined && data["name"] !== null) { + instance.name = String(data["name"]); + } + if (data["success"] !== undefined && data["success"] !== null) { + instance.success = Boolean(data["success"]); + } + if (data["result"] !== undefined && data["result"] !== null) { + instance.result = ToolResult.load( + data["result"] as Record, + context, + ); + } + if (data["durationMs"] !== undefined && data["durationMs"] !== null) { + instance.durationMs = Number(data["durationMs"]); + } + if (data["errorKind"] !== undefined && data["errorKind"] !== null) { + instance.errorKind = String(data["errorKind"]); + } + + if (context) { + return context.processOutput(instance) as ToolCallCompletePayload; + } + return instance; + } + + //#endregion + + //#region Save Methods + + save(context?: SaveContext): Record { + let obj: this = this; + if (context) { + obj = context.processObject(obj) as this; + } + + const result: Record = {}; + + if (obj.id !== undefined && obj.id !== null) { + result["id"] = obj.id; + } + if (obj.name !== undefined && obj.name !== null) { + result["name"] = obj.name; + } + if (obj.success !== undefined && obj.success !== null) { + result["success"] = obj.success; + } + if (obj.result !== undefined && obj.result !== null) { + result["result"] = obj.result.save(context); + } + if (obj.durationMs !== undefined && obj.durationMs !== null) { + result["durationMs"] = obj.durationMs; + } + if (obj.errorKind !== undefined && obj.errorKind !== null) { + result["errorKind"] = obj.errorKind; + } + + if (context) { + return context.processDict(result); + } + return result; + } + + toYaml(context?: SaveContext): string { + context = context ?? new SaveContext(); + return context.toYaml(this.save(context)); + } + + toJson(context?: SaveContext, indent: number = 2): string { + context = context ?? new SaveContext(); + return context.toJson(this.save(context), indent); + } + + static fromJson( + json: string, + context?: LoadContext, + ): ToolCallCompletePayload { + const data = JSON.parse(json); + return ToolCallCompletePayload.load( + data as Record, + context, + ); + } + + static fromYaml( + yaml: string, + context?: LoadContext, + ): ToolCallCompletePayload { + const { parse } = require("yaml"); + const data = parse(yaml); + return ToolCallCompletePayload.load( + data as Record, + context, + ); + } + + //#endregion +} diff --git a/runtime/typescript/packages/core/src/model/events/tool-call-start-payload.ts b/runtime/typescript/packages/core/src/model/events/tool-call-start-payload.ts index 2d66b815..66c35f20 100644 --- a/runtime/typescript/packages/core/src/model/events/tool-call-start-payload.ts +++ b/runtime/typescript/packages/core/src/model/events/tool-call-start-payload.ts @@ -6,10 +6,14 @@ import { LoadContext, SaveContext } from "../context"; export class ToolCallStartPayload { static readonly shorthandProperty: string | undefined = undefined; + id?: string | undefined; name: string = ""; arguments: string = ""; constructor(init?: Partial) { + if (init?.id !== undefined) { + this.id = init.id; + } this.name = init?.name ?? ""; this.arguments = init?.arguments ?? ""; } @@ -26,6 +30,9 @@ export class ToolCallStartPayload { const instance = new ToolCallStartPayload(); + if (data["id"] !== undefined && data["id"] !== null) { + instance.id = String(data["id"]); + } if (data["name"] !== undefined && data["name"] !== null) { instance.name = String(data["name"]); } @@ -51,6 +58,9 @@ export class ToolCallStartPayload { const result: Record = {}; + if (obj.id !== undefined && obj.id !== null) { + result["id"] = obj.id; + } if (obj.name !== undefined && obj.name !== null) { result["name"] = obj.name; } diff --git a/runtime/typescript/packages/core/src/model/events/turn-end-payload.ts b/runtime/typescript/packages/core/src/model/events/turn-end-payload.ts new file mode 100644 index 00000000..f95d5043 --- /dev/null +++ b/runtime/typescript/packages/core/src/model/events/turn-end-payload.ts @@ -0,0 +1,115 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { LoadContext, SaveContext } from "../context"; + +export type TurnStatus = "success" | "error" | "cancelled"; + +export class TurnEndPayload { + static readonly shorthandProperty: string | undefined = undefined; + + iterations?: number | undefined; + status?: TurnStatus | undefined; + response?: unknown | undefined; + durationMs?: number | undefined; + + constructor(init?: Partial) { + if (init?.iterations !== undefined) { + this.iterations = init.iterations; + } + if (init?.status !== undefined) { + this.status = init.status; + } + if (init?.response !== undefined) { + this.response = init.response; + } + if (init?.durationMs !== undefined) { + this.durationMs = init.durationMs; + } + } + + //#region Load Methods + + static load( + data: Record, + context?: LoadContext, + ): TurnEndPayload { + if (context) { + data = context.processInput(data) as Record; + } + + const instance = new TurnEndPayload(); + + if (data["iterations"] !== undefined && data["iterations"] !== null) { + instance.iterations = Number(data["iterations"]); + } + if (data["status"] !== undefined && data["status"] !== null) { + instance.status = String(data["status"]) as TurnStatus; + } + if (data["response"] !== undefined && data["response"] !== null) { + instance.response = data["response"] as unknown; + } + if (data["durationMs"] !== undefined && data["durationMs"] !== null) { + instance.durationMs = Number(data["durationMs"]); + } + + if (context) { + return context.processOutput(instance) as TurnEndPayload; + } + return instance; + } + + //#endregion + + //#region Save Methods + + save(context?: SaveContext): Record { + let obj: this = this; + if (context) { + obj = context.processObject(obj) as this; + } + + const result: Record = {}; + + if (obj.iterations !== undefined && obj.iterations !== null) { + result["iterations"] = obj.iterations; + } + if (obj.status !== undefined && obj.status !== null) { + result["status"] = obj.status; + } + if (obj.response !== undefined && obj.response !== null) { + result["response"] = obj.response; + } + if (obj.durationMs !== undefined && obj.durationMs !== null) { + result["durationMs"] = obj.durationMs; + } + + if (context) { + return context.processDict(result); + } + return result; + } + + toYaml(context?: SaveContext): string { + context = context ?? new SaveContext(); + return context.toYaml(this.save(context)); + } + + toJson(context?: SaveContext, indent: number = 2): string { + context = context ?? new SaveContext(); + return context.toJson(this.save(context), indent); + } + + static fromJson(json: string, context?: LoadContext): TurnEndPayload { + const data = JSON.parse(json); + return TurnEndPayload.load(data as Record, context); + } + + static fromYaml(yaml: string, context?: LoadContext): TurnEndPayload { + const { parse } = require("yaml"); + const data = parse(yaml); + return TurnEndPayload.load(data as Record, context); + } + + //#endregion +} diff --git a/runtime/typescript/packages/core/src/model/events/turn-event.ts b/runtime/typescript/packages/core/src/model/events/turn-event.ts new file mode 100644 index 00000000..19219cc2 --- /dev/null +++ b/runtime/typescript/packages/core/src/model/events/turn-event.ts @@ -0,0 +1,164 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { LoadContext, SaveContext } from "../context"; + +export type TurnEventType = + | "turn_start" + | "turn_end" + | "llm_start" + | "llm_complete" + | "retry" + | "permission_requested" + | "permission_completed" + | "token" + | "thinking" + | "tool_call_start" + | "tool_call_complete" + | "tool_result" + | "status" + | "messages_updated" + | "done" + | "error" + | "cancelled" + | "compaction_start" + | "compaction_complete" + | "compaction_failed"; + +export class TurnEvent { + static readonly shorthandProperty: string | undefined = undefined; + + id: string = ""; + type: TurnEventType = "turn_start"; + timestamp: string = ""; + turnId?: string | undefined; + iteration?: number | undefined; + parentId?: string | undefined; + spanId?: string | undefined; + payload: Record = {}; + + constructor(init?: Partial) { + this.id = init?.id ?? ""; + this.type = init?.type ?? "turn_start"; + this.timestamp = init?.timestamp ?? ""; + if (init?.turnId !== undefined) { + this.turnId = init.turnId; + } + if (init?.iteration !== undefined) { + this.iteration = init.iteration; + } + if (init?.parentId !== undefined) { + this.parentId = init.parentId; + } + if (init?.spanId !== undefined) { + this.spanId = init.spanId; + } + this.payload = init?.payload ?? {}; + } + + //#region Load Methods + + static load(data: Record, context?: LoadContext): TurnEvent { + if (context) { + data = context.processInput(data) as Record; + } + + const instance = new TurnEvent(); + + if (data["id"] !== undefined && data["id"] !== null) { + instance.id = String(data["id"]); + } + if (data["type"] !== undefined && data["type"] !== null) { + instance.type = String(data["type"]) as TurnEventType; + } + if (data["timestamp"] !== undefined && data["timestamp"] !== null) { + instance.timestamp = String(data["timestamp"]); + } + if (data["turnId"] !== undefined && data["turnId"] !== null) { + instance.turnId = String(data["turnId"]); + } + if (data["iteration"] !== undefined && data["iteration"] !== null) { + instance.iteration = Number(data["iteration"]); + } + if (data["parentId"] !== undefined && data["parentId"] !== null) { + instance.parentId = String(data["parentId"]); + } + if (data["spanId"] !== undefined && data["spanId"] !== null) { + instance.spanId = String(data["spanId"]); + } + if (data["payload"] !== undefined && data["payload"] !== null) { + instance.payload = data["payload"] as Record; + } + + if (context) { + return context.processOutput(instance) as TurnEvent; + } + return instance; + } + + //#endregion + + //#region Save Methods + + save(context?: SaveContext): Record { + let obj: this = this; + if (context) { + obj = context.processObject(obj) as this; + } + + const result: Record = {}; + + if (obj.id !== undefined && obj.id !== null) { + result["id"] = obj.id; + } + if (obj.type !== undefined && obj.type !== null) { + result["type"] = obj.type; + } + if (obj.timestamp !== undefined && obj.timestamp !== null) { + result["timestamp"] = obj.timestamp; + } + if (obj.turnId !== undefined && obj.turnId !== null) { + result["turnId"] = obj.turnId; + } + if (obj.iteration !== undefined && obj.iteration !== null) { + result["iteration"] = obj.iteration; + } + if (obj.parentId !== undefined && obj.parentId !== null) { + result["parentId"] = obj.parentId; + } + if (obj.spanId !== undefined && obj.spanId !== null) { + result["spanId"] = obj.spanId; + } + if (obj.payload !== undefined && obj.payload !== null) { + result["payload"] = obj.payload; + } + + if (context) { + return context.processDict(result); + } + return result; + } + + toYaml(context?: SaveContext): string { + context = context ?? new SaveContext(); + return context.toYaml(this.save(context)); + } + + toJson(context?: SaveContext, indent: number = 2): string { + context = context ?? new SaveContext(); + return context.toJson(this.save(context), indent); + } + + static fromJson(json: string, context?: LoadContext): TurnEvent { + const data = JSON.parse(json); + return TurnEvent.load(data as Record, context); + } + + static fromYaml(yaml: string, context?: LoadContext): TurnEvent { + const { parse } = require("yaml"); + const data = parse(yaml); + return TurnEvent.load(data as Record, context); + } + + //#endregion +} diff --git a/runtime/typescript/packages/core/src/model/events/turn-start-payload.ts b/runtime/typescript/packages/core/src/model/events/turn-start-payload.ts new file mode 100644 index 00000000..d4f2bc81 --- /dev/null +++ b/runtime/typescript/packages/core/src/model/events/turn-start-payload.ts @@ -0,0 +1,103 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { LoadContext, SaveContext } from "../context"; + +export class TurnStartPayload { + static readonly shorthandProperty: string | undefined = undefined; + + agent?: string | undefined; + inputs?: Record | undefined; + maxIterations?: number | undefined; + + constructor(init?: Partial) { + if (init?.agent !== undefined) { + this.agent = init.agent; + } + if (init?.inputs !== undefined) { + this.inputs = init.inputs; + } + if (init?.maxIterations !== undefined) { + this.maxIterations = init.maxIterations; + } + } + + //#region Load Methods + + static load( + data: Record, + context?: LoadContext, + ): TurnStartPayload { + if (context) { + data = context.processInput(data) as Record; + } + + const instance = new TurnStartPayload(); + + if (data["agent"] !== undefined && data["agent"] !== null) { + instance.agent = String(data["agent"]); + } + if (data["inputs"] !== undefined && data["inputs"] !== null) { + instance.inputs = data["inputs"] as Record; + } + if (data["maxIterations"] !== undefined && data["maxIterations"] !== null) { + instance.maxIterations = Number(data["maxIterations"]); + } + + if (context) { + return context.processOutput(instance) as TurnStartPayload; + } + return instance; + } + + //#endregion + + //#region Save Methods + + save(context?: SaveContext): Record { + let obj: this = this; + if (context) { + obj = context.processObject(obj) as this; + } + + const result: Record = {}; + + if (obj.agent !== undefined && obj.agent !== null) { + result["agent"] = obj.agent; + } + if (obj.inputs !== undefined && obj.inputs !== null) { + result["inputs"] = obj.inputs; + } + if (obj.maxIterations !== undefined && obj.maxIterations !== null) { + result["maxIterations"] = obj.maxIterations; + } + + if (context) { + return context.processDict(result); + } + return result; + } + + toYaml(context?: SaveContext): string { + context = context ?? new SaveContext(); + return context.toYaml(this.save(context)); + } + + toJson(context?: SaveContext, indent: number = 2): string { + context = context ?? new SaveContext(); + return context.toJson(this.save(context), indent); + } + + static fromJson(json: string, context?: LoadContext): TurnStartPayload { + const data = JSON.parse(json); + return TurnStartPayload.load(data as Record, context); + } + + static fromYaml(yaml: string, context?: LoadContext): TurnStartPayload { + const { parse } = require("yaml"); + const data = parse(yaml); + return TurnStartPayload.load(data as Record, context); + } + + //#endregion +} diff --git a/runtime/typescript/packages/core/src/model/events/turn-summary.ts b/runtime/typescript/packages/core/src/model/events/turn-summary.ts new file mode 100644 index 00000000..a7ebc91b --- /dev/null +++ b/runtime/typescript/packages/core/src/model/events/turn-summary.ts @@ -0,0 +1,151 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { LoadContext, SaveContext } from "../context"; +import { TokenUsage } from "../model/token-usage"; + +export class TurnSummary { + static readonly shorthandProperty: string | undefined = undefined; + + turnId: string = ""; + status: string = ""; + iterations: number = 0; + llmCalls?: number | undefined; + toolCalls?: number | undefined; + retries?: number | undefined; + usage?: TokenUsage | undefined; + durationMs?: number | undefined; + + constructor(init?: Partial) { + this.turnId = init?.turnId ?? ""; + this.status = init?.status ?? ""; + this.iterations = init?.iterations ?? 0; + if (init?.llmCalls !== undefined) { + this.llmCalls = init.llmCalls; + } + if (init?.toolCalls !== undefined) { + this.toolCalls = init.toolCalls; + } + if (init?.retries !== undefined) { + this.retries = init.retries; + } + if (init?.usage !== undefined) { + this.usage = init.usage; + } + if (init?.durationMs !== undefined) { + this.durationMs = init.durationMs; + } + } + + //#region Load Methods + + static load( + data: Record, + context?: LoadContext, + ): TurnSummary { + if (context) { + data = context.processInput(data) as Record; + } + + const instance = new TurnSummary(); + + if (data["turnId"] !== undefined && data["turnId"] !== null) { + instance.turnId = String(data["turnId"]); + } + if (data["status"] !== undefined && data["status"] !== null) { + instance.status = String(data["status"]); + } + if (data["iterations"] !== undefined && data["iterations"] !== null) { + instance.iterations = Number(data["iterations"]); + } + if (data["llmCalls"] !== undefined && data["llmCalls"] !== null) { + instance.llmCalls = Number(data["llmCalls"]); + } + if (data["toolCalls"] !== undefined && data["toolCalls"] !== null) { + instance.toolCalls = Number(data["toolCalls"]); + } + if (data["retries"] !== undefined && data["retries"] !== null) { + instance.retries = Number(data["retries"]); + } + if (data["usage"] !== undefined && data["usage"] !== null) { + instance.usage = TokenUsage.load( + data["usage"] as Record, + context, + ); + } + if (data["durationMs"] !== undefined && data["durationMs"] !== null) { + instance.durationMs = Number(data["durationMs"]); + } + + if (context) { + return context.processOutput(instance) as TurnSummary; + } + return instance; + } + + //#endregion + + //#region Save Methods + + save(context?: SaveContext): Record { + let obj: this = this; + if (context) { + obj = context.processObject(obj) as this; + } + + const result: Record = {}; + + if (obj.turnId !== undefined && obj.turnId !== null) { + result["turnId"] = obj.turnId; + } + if (obj.status !== undefined && obj.status !== null) { + result["status"] = obj.status; + } + if (obj.iterations !== undefined && obj.iterations !== null) { + result["iterations"] = obj.iterations; + } + if (obj.llmCalls !== undefined && obj.llmCalls !== null) { + result["llmCalls"] = obj.llmCalls; + } + if (obj.toolCalls !== undefined && obj.toolCalls !== null) { + result["toolCalls"] = obj.toolCalls; + } + if (obj.retries !== undefined && obj.retries !== null) { + result["retries"] = obj.retries; + } + if (obj.usage !== undefined && obj.usage !== null) { + result["usage"] = obj.usage.save(context); + } + if (obj.durationMs !== undefined && obj.durationMs !== null) { + result["durationMs"] = obj.durationMs; + } + + if (context) { + return context.processDict(result); + } + return result; + } + + toYaml(context?: SaveContext): string { + context = context ?? new SaveContext(); + return context.toYaml(this.save(context)); + } + + toJson(context?: SaveContext, indent: number = 2): string { + context = context ?? new SaveContext(); + return context.toJson(this.save(context), indent); + } + + static fromJson(json: string, context?: LoadContext): TurnSummary { + const data = JSON.parse(json); + return TurnSummary.load(data as Record, context); + } + + static fromYaml(yaml: string, context?: LoadContext): TurnSummary { + const { parse } = require("yaml"); + const data = parse(yaml); + return TurnSummary.load(data as Record, context); + } + + //#endregion +} diff --git a/runtime/typescript/packages/core/src/model/events/turn-trace.ts b/runtime/typescript/packages/core/src/model/events/turn-trace.ts new file mode 100644 index 00000000..97c48ac9 --- /dev/null +++ b/runtime/typescript/packages/core/src/model/events/turn-trace.ts @@ -0,0 +1,160 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { LoadContext, SaveContext } from "../context"; +import { TurnEvent } from "./turn-event"; +import { TurnSummary } from "./turn-summary"; + +export class TurnTrace { + static readonly shorthandProperty: string | undefined = undefined; + + version: string = "1"; + runtime?: string | undefined; + promptyVersion?: string | undefined; + events: TurnEvent[] = []; + summary?: TurnSummary | undefined; + + constructor(init?: Partial) { + this.version = init?.version ?? "1"; + if (init?.runtime !== undefined) { + this.runtime = init.runtime; + } + if (init?.promptyVersion !== undefined) { + this.promptyVersion = init.promptyVersion; + } + this.events = init?.events ?? []; + if (init?.summary !== undefined) { + this.summary = init.summary; + } + } + + //#region Load Methods + + static load(data: Record, context?: LoadContext): TurnTrace { + if (context) { + data = context.processInput(data) as Record; + } + + const instance = new TurnTrace(); + + if (data["version"] !== undefined && data["version"] !== null) { + instance.version = String(data["version"]); + } + if (data["runtime"] !== undefined && data["runtime"] !== null) { + instance.runtime = String(data["runtime"]); + } + if ( + data["promptyVersion"] !== undefined && + data["promptyVersion"] !== null + ) { + instance.promptyVersion = String(data["promptyVersion"]); + } + if (data["events"] !== undefined && data["events"] !== null) { + instance.events = TurnTrace.loadEvents( + data["events"] as unknown[], + context, + ); + } + if (data["summary"] !== undefined && data["summary"] !== null) { + instance.summary = TurnSummary.load( + data["summary"] as Record, + context, + ); + } + + if (context) { + return context.processOutput(instance) as TurnTrace; + } + return instance; + } + + static loadEvents( + data: Record[] | unknown[], + context?: LoadContext, + ): TurnEvent[] { + if (!Array.isArray(data)) { + // Convert dict/object format to array format + const result: Record[] = []; + for (const [k, v] of Object.entries(data)) { + if (typeof v === "object" && v !== null && !Array.isArray(v)) { + result.push({ name: k, ...(v as Record) }); + } else { + result.push({ name: k, id: v }); + } + } + data = result; + } + return data.map((item) => + TurnEvent.load(item as Record, context), + ); + } + + static saveEvents( + items: TurnEvent[], + context?: SaveContext, + ): Record[] | Record { + if (!context) { + context = new SaveContext(); + } + + // This type doesn't have a 'name' property, so always use array format + return items.map((item) => item.save(context)); + } + + //#endregion + + //#region Save Methods + + save(context?: SaveContext): Record { + let obj: this = this; + if (context) { + obj = context.processObject(obj) as this; + } + + const result: Record = {}; + + if (obj.version !== undefined && obj.version !== null) { + result["version"] = obj.version; + } + if (obj.runtime !== undefined && obj.runtime !== null) { + result["runtime"] = obj.runtime; + } + if (obj.promptyVersion !== undefined && obj.promptyVersion !== null) { + result["promptyVersion"] = obj.promptyVersion; + } + if (obj.events !== undefined && obj.events !== null) { + result["events"] = TurnTrace.saveEvents(obj.events, context); + } + if (obj.summary !== undefined && obj.summary !== null) { + result["summary"] = obj.summary.save(context); + } + + if (context) { + return context.processDict(result); + } + return result; + } + + toYaml(context?: SaveContext): string { + context = context ?? new SaveContext(); + return context.toYaml(this.save(context)); + } + + toJson(context?: SaveContext, indent: number = 2): string { + context = context ?? new SaveContext(); + return context.toJson(this.save(context), indent); + } + + static fromJson(json: string, context?: LoadContext): TurnTrace { + const data = JSON.parse(json); + return TurnTrace.load(data as Record, context); + } + + static fromYaml(yaml: string, context?: LoadContext): TurnTrace { + const { parse } = require("yaml"); + const data = parse(yaml); + return TurnTrace.load(data as Record, context); + } + + //#endregion +} diff --git a/runtime/typescript/packages/core/src/model/index.ts b/runtime/typescript/packages/core/src/model/index.ts index f05c0984..66442384 100644 --- a/runtime/typescript/packages/core/src/model/index.ts +++ b/runtime/typescript/packages/core/src/model/index.ts @@ -34,16 +34,28 @@ export { ValidationError } from "./core/validation-error"; export { FileNotFoundError } from "./core/file-not-found-error"; export { ValidationResult } from "./core/validation-result"; +export { TurnEvent } from "./events/turn-event"; +export { TurnStartPayload } from "./events/turn-start-payload"; +export { TurnEndPayload } from "./events/turn-end-payload"; +export { LlmStartPayload } from "./events/llm-start-payload"; +export { LlmCompletePayload } from "./events/llm-complete-payload"; +export { RetryPayload } from "./events/retry-payload"; +export { PermissionRequestedPayload } from "./events/permission-requested-payload"; +export { PermissionCompletedPayload } from "./events/permission-completed-payload"; export { TokenEventPayload } from "./events/token-event-payload"; export { ThinkingEventPayload } from "./events/thinking-event-payload"; export { ToolCallStartPayload } from "./events/tool-call-start-payload"; +export { ToolCallCompletePayload } from "./events/tool-call-complete-payload"; export { ToolResultPayload } from "./events/tool-result-payload"; export { StatusEventPayload } from "./events/status-event-payload"; export { MessagesUpdatedPayload } from "./events/messages-updated-payload"; export { DoneEventPayload } from "./events/done-event-payload"; export { ErrorEventPayload } from "./events/error-event-payload"; +export { CompactionStartPayload } from "./events/compaction-start-payload"; export { CompactionCompletePayload } from "./events/compaction-complete-payload"; export { CompactionFailedPayload } from "./events/compaction-failed-payload"; +export { TurnSummary } from "./events/turn-summary"; +export { TurnTrace } from "./events/turn-trace"; export { StreamChunk, TextChunk, diff --git a/runtime/typescript/packages/core/tests/agent-extensions.test.ts b/runtime/typescript/packages/core/tests/agent-extensions.test.ts index 8a97f930..eab76f92 100644 --- a/runtime/typescript/packages/core/tests/agent-extensions.test.ts +++ b/runtime/typescript/packages/core/tests/agent-extensions.test.ts @@ -25,7 +25,19 @@ describe("emitEvent", () => { const data = { iteration: 1 }; emitEvent(cb, "status", data); expect(cb).toHaveBeenCalledOnce(); - expect(cb).toHaveBeenCalledWith("status", data); + expect(cb).toHaveBeenCalledWith( + "status", + expect.objectContaining({ + iteration: 1, + turnEvent: expect.objectContaining({ + id: expect.any(String), + type: "status", + timestamp: expect.any(String), + iteration: 1, + payload: data, + }), + }), + ); }); it("silently swallows exceptions from callback", () => { diff --git a/runtime/typescript/packages/core/tests/model/conversation/tool-result.test.ts b/runtime/typescript/packages/core/tests/model/conversation/tool-result.test.ts index e747abfd..e16970c0 100644 --- a/runtime/typescript/packages/core/tests/model/conversation/tool-result.test.ts +++ b/runtime/typescript/packages/core/tests/model/conversation/tool-result.test.ts @@ -18,31 +18,47 @@ describe("ToolResult", () => { describe("JSON serialization", () => { it("should load from JSON - example 1", () => { - const json = `{\n "parts": [\n {\n "kind": "text",\n "value": "72°F and sunny"\n }\n ]\n}`; + const json = `{\n "parts": [\n {\n "kind": "text",\n "value": "72°F and sunny"\n }\n ],\n "errorKind": "missing_tool",\n "errorMessage": "Tool 'get_weather' is not registered",\n "durationMs": 42\n}`; const instance = ToolResult.fromJson(json); expect(instance).toBeDefined(); + expect(instance.errorKind).toEqual("missing_tool"); + expect(instance.errorMessage).toEqual( + "Tool 'get_weather' is not registered", + ); + expect(instance.durationMs).toEqual(42); }); it("should round-trip JSON - example 1", () => { - const json = `{\n "parts": [\n {\n "kind": "text",\n "value": "72°F and sunny"\n }\n ]\n}`; + const json = `{\n "parts": [\n {\n "kind": "text",\n "value": "72°F and sunny"\n }\n ],\n "errorKind": "missing_tool",\n "errorMessage": "Tool 'get_weather' is not registered",\n "durationMs": 42\n}`; const instance = ToolResult.fromJson(json); const output = instance.toJson(); const reloaded = ToolResult.fromJson(output); + expect(reloaded.errorKind).toEqual(instance.errorKind); + expect(reloaded.errorMessage).toEqual(instance.errorMessage); + expect(reloaded.durationMs).toEqual(instance.durationMs); }); }); describe("YAML serialization", () => { it("should load from YAML - example 1", () => { - const yaml = `parts:\n - kind: text\n value: 72°F and sunny\n`; + const yaml = `parts:\n - kind: text\n value: 72°F and sunny\nerrorKind: missing_tool\nerrorMessage: Tool 'get_weather' is not registered\ndurationMs: 42\n`; const instance = ToolResult.fromYaml(yaml); expect(instance).toBeDefined(); + expect(instance.errorKind).toEqual("missing_tool"); + expect(instance.errorMessage).toEqual( + "Tool 'get_weather' is not registered", + ); + expect(instance.durationMs).toEqual(42); }); it("should round-trip YAML - example 1", () => { - const yaml = `parts:\n - kind: text\n value: 72°F and sunny\n`; + const yaml = `parts:\n - kind: text\n value: 72°F and sunny\nerrorKind: missing_tool\nerrorMessage: Tool 'get_weather' is not registered\ndurationMs: 42\n`; const instance = ToolResult.fromYaml(yaml); const output = instance.toYaml(); const reloaded = ToolResult.fromYaml(output); + expect(reloaded.errorKind).toEqual(instance.errorKind); + expect(reloaded.errorMessage).toEqual(instance.errorMessage); + expect(reloaded.durationMs).toEqual(instance.durationMs); }); }); diff --git a/runtime/typescript/packages/core/tests/model/events/compaction-complete-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/compaction-complete-payload.test.ts index 73e06ab7..77b00a2c 100644 --- a/runtime/typescript/packages/core/tests/model/events/compaction-complete-payload.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/compaction-complete-payload.test.ts @@ -18,39 +18,43 @@ describe("CompactionCompletePayload", () => { describe("JSON serialization", () => { it("should load from JSON - example 1", () => { - const json = `{\n "removed": 5,\n "remaining": 3\n}`; + const json = `{\n "removed": 5,\n "remaining": 3,\n "summaryLength": 1200\n}`; const instance = CompactionCompletePayload.fromJson(json); expect(instance).toBeDefined(); expect(instance.removed).toEqual(5); expect(instance.remaining).toEqual(3); + expect(instance.summaryLength).toEqual(1200); }); it("should round-trip JSON - example 1", () => { - const json = `{\n "removed": 5,\n "remaining": 3\n}`; + const json = `{\n "removed": 5,\n "remaining": 3,\n "summaryLength": 1200\n}`; const instance = CompactionCompletePayload.fromJson(json); const output = instance.toJson(); const reloaded = CompactionCompletePayload.fromJson(output); expect(reloaded.removed).toEqual(instance.removed); expect(reloaded.remaining).toEqual(instance.remaining); + expect(reloaded.summaryLength).toEqual(instance.summaryLength); }); }); describe("YAML serialization", () => { it("should load from YAML - example 1", () => { - const yaml = `removed: 5\nremaining: 3\n`; + const yaml = `removed: 5\nremaining: 3\nsummaryLength: 1200\n`; const instance = CompactionCompletePayload.fromYaml(yaml); expect(instance).toBeDefined(); expect(instance.removed).toEqual(5); expect(instance.remaining).toEqual(3); + expect(instance.summaryLength).toEqual(1200); }); it("should round-trip YAML - example 1", () => { - const yaml = `removed: 5\nremaining: 3\n`; + const yaml = `removed: 5\nremaining: 3\nsummaryLength: 1200\n`; const instance = CompactionCompletePayload.fromYaml(yaml); const output = instance.toYaml(); const reloaded = CompactionCompletePayload.fromYaml(output); expect(reloaded.removed).toEqual(instance.removed); expect(reloaded.remaining).toEqual(instance.remaining); + expect(reloaded.summaryLength).toEqual(instance.summaryLength); }); }); diff --git a/runtime/typescript/packages/core/tests/model/events/compaction-start-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/compaction-start-payload.test.ts new file mode 100644 index 00000000..80d53a23 --- /dev/null +++ b/runtime/typescript/packages/core/tests/model/events/compaction-start-payload.test.ts @@ -0,0 +1,67 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { CompactionStartPayload } from "../../../src/model/index"; + +describe("CompactionStartPayload", () => { + describe("construction", () => { + it("should create a new instance with defaults", () => { + const instance = new CompactionStartPayload(); + expect(instance).toBeDefined(); + }); + + it("should create a new instance with partial initialization", () => { + const instance = new CompactionStartPayload({}); + expect(instance).toBeDefined(); + }); + }); + + describe("JSON serialization", () => { + it("should load from JSON - example 1", () => { + const json = `{\n "droppedCount": 5\n}`; + const instance = CompactionStartPayload.fromJson(json); + expect(instance).toBeDefined(); + expect(instance.droppedCount).toEqual(5); + }); + + it("should round-trip JSON - example 1", () => { + const json = `{\n "droppedCount": 5\n}`; + const instance = CompactionStartPayload.fromJson(json); + const output = instance.toJson(); + const reloaded = CompactionStartPayload.fromJson(output); + expect(reloaded.droppedCount).toEqual(instance.droppedCount); + }); + }); + + describe("YAML serialization", () => { + it("should load from YAML - example 1", () => { + const yaml = `droppedCount: 5\n`; + const instance = CompactionStartPayload.fromYaml(yaml); + expect(instance).toBeDefined(); + expect(instance.droppedCount).toEqual(5); + }); + + it("should round-trip YAML - example 1", () => { + const yaml = `droppedCount: 5\n`; + const instance = CompactionStartPayload.fromYaml(yaml); + const output = instance.toYaml(); + const reloaded = CompactionStartPayload.fromYaml(output); + expect(reloaded.droppedCount).toEqual(instance.droppedCount); + }); + }); + + describe("load and save", () => { + it("should load from dictionary", () => { + const data: Record = {}; + const instance = CompactionStartPayload.load(data); + expect(instance).toBeDefined(); + }); + + it("should save to dictionary", () => { + const instance = new CompactionStartPayload(); + const data = instance.save(); + expect(data).toBeDefined(); + expect(typeof data).toBe("object"); + }); + }); +}); diff --git a/runtime/typescript/packages/core/tests/model/events/done-event-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/done-event-payload.test.ts index d0812504..5719e2d1 100644 --- a/runtime/typescript/packages/core/tests/model/events/done-event-payload.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/done-event-payload.test.ts @@ -16,44 +16,6 @@ describe("DoneEventPayload", () => { }); }); - describe("JSON serialization", () => { - it("should load from JSON - example 1", () => { - const json = `{\n "response": "The weather in Paris is 72°F and sunny."\n}`; - const instance = DoneEventPayload.fromJson(json); - expect(instance).toBeDefined(); - expect(instance.response).toEqual( - "The weather in Paris is 72°F and sunny.", - ); - }); - - it("should round-trip JSON - example 1", () => { - const json = `{\n "response": "The weather in Paris is 72°F and sunny."\n}`; - const instance = DoneEventPayload.fromJson(json); - const output = instance.toJson(); - const reloaded = DoneEventPayload.fromJson(output); - expect(reloaded.response).toEqual(instance.response); - }); - }); - - describe("YAML serialization", () => { - it("should load from YAML - example 1", () => { - const yaml = `response: The weather in Paris is 72°F and sunny.\n`; - const instance = DoneEventPayload.fromYaml(yaml); - expect(instance).toBeDefined(); - expect(instance.response).toEqual( - "The weather in Paris is 72°F and sunny.", - ); - }); - - it("should round-trip YAML - example 1", () => { - const yaml = `response: The weather in Paris is 72°F and sunny.\n`; - const instance = DoneEventPayload.fromYaml(yaml); - const output = instance.toYaml(); - const reloaded = DoneEventPayload.fromYaml(output); - expect(reloaded.response).toEqual(instance.response); - }); - }); - describe("load and save", () => { it("should load from dictionary", () => { const data: Record = {}; diff --git a/runtime/typescript/packages/core/tests/model/events/error-event-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/error-event-payload.test.ts index f105f005..89197a27 100644 --- a/runtime/typescript/packages/core/tests/model/events/error-event-payload.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/error-event-payload.test.ts @@ -18,35 +18,43 @@ describe("ErrorEventPayload", () => { describe("JSON serialization", () => { it("should load from JSON - example 1", () => { - const json = `{\n "message": "Rate limit exceeded"\n}`; + const json = `{\n "message": "Rate limit exceeded",\n "errorKind": "rate_limit",\n "phase": "llm"\n}`; const instance = ErrorEventPayload.fromJson(json); expect(instance).toBeDefined(); expect(instance.message).toEqual("Rate limit exceeded"); + expect(instance.errorKind).toEqual("rate_limit"); + expect(instance.phase).toEqual("llm"); }); it("should round-trip JSON - example 1", () => { - const json = `{\n "message": "Rate limit exceeded"\n}`; + const json = `{\n "message": "Rate limit exceeded",\n "errorKind": "rate_limit",\n "phase": "llm"\n}`; const instance = ErrorEventPayload.fromJson(json); const output = instance.toJson(); const reloaded = ErrorEventPayload.fromJson(output); expect(reloaded.message).toEqual(instance.message); + expect(reloaded.errorKind).toEqual(instance.errorKind); + expect(reloaded.phase).toEqual(instance.phase); }); }); describe("YAML serialization", () => { it("should load from YAML - example 1", () => { - const yaml = `message: Rate limit exceeded\n`; + const yaml = `message: Rate limit exceeded\nerrorKind: rate_limit\nphase: llm\n`; const instance = ErrorEventPayload.fromYaml(yaml); expect(instance).toBeDefined(); expect(instance.message).toEqual("Rate limit exceeded"); + expect(instance.errorKind).toEqual("rate_limit"); + expect(instance.phase).toEqual("llm"); }); it("should round-trip YAML - example 1", () => { - const yaml = `message: Rate limit exceeded\n`; + const yaml = `message: Rate limit exceeded\nerrorKind: rate_limit\nphase: llm\n`; const instance = ErrorEventPayload.fromYaml(yaml); const output = instance.toYaml(); const reloaded = ErrorEventPayload.fromYaml(output); expect(reloaded.message).toEqual(instance.message); + expect(reloaded.errorKind).toEqual(instance.errorKind); + expect(reloaded.phase).toEqual(instance.phase); }); }); diff --git a/runtime/typescript/packages/core/tests/model/events/llm-complete-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/llm-complete-payload.test.ts new file mode 100644 index 00000000..65b989ab --- /dev/null +++ b/runtime/typescript/packages/core/tests/model/events/llm-complete-payload.test.ts @@ -0,0 +1,75 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { LlmCompletePayload } from "../../../src/model/index"; + +describe("LlmCompletePayload", () => { + describe("construction", () => { + it("should create a new instance with defaults", () => { + const instance = new LlmCompletePayload(); + expect(instance).toBeDefined(); + }); + + it("should create a new instance with partial initialization", () => { + const instance = new LlmCompletePayload({}); + expect(instance).toBeDefined(); + }); + }); + + describe("JSON serialization", () => { + it("should load from JSON - example 1", () => { + const json = `{\n "requestId": "req_abc123",\n "serviceRequestId": "srv_abc123",\n "durationMs": 820\n}`; + const instance = LlmCompletePayload.fromJson(json); + expect(instance).toBeDefined(); + expect(instance.requestId).toEqual("req_abc123"); + expect(instance.serviceRequestId).toEqual("srv_abc123"); + expect(instance.durationMs).toEqual(820); + }); + + it("should round-trip JSON - example 1", () => { + const json = `{\n "requestId": "req_abc123",\n "serviceRequestId": "srv_abc123",\n "durationMs": 820\n}`; + const instance = LlmCompletePayload.fromJson(json); + const output = instance.toJson(); + const reloaded = LlmCompletePayload.fromJson(output); + expect(reloaded.requestId).toEqual(instance.requestId); + expect(reloaded.serviceRequestId).toEqual(instance.serviceRequestId); + expect(reloaded.durationMs).toEqual(instance.durationMs); + }); + }); + + describe("YAML serialization", () => { + it("should load from YAML - example 1", () => { + const yaml = `requestId: req_abc123\nserviceRequestId: srv_abc123\ndurationMs: 820\n`; + const instance = LlmCompletePayload.fromYaml(yaml); + expect(instance).toBeDefined(); + expect(instance.requestId).toEqual("req_abc123"); + expect(instance.serviceRequestId).toEqual("srv_abc123"); + expect(instance.durationMs).toEqual(820); + }); + + it("should round-trip YAML - example 1", () => { + const yaml = `requestId: req_abc123\nserviceRequestId: srv_abc123\ndurationMs: 820\n`; + const instance = LlmCompletePayload.fromYaml(yaml); + const output = instance.toYaml(); + const reloaded = LlmCompletePayload.fromYaml(output); + expect(reloaded.requestId).toEqual(instance.requestId); + expect(reloaded.serviceRequestId).toEqual(instance.serviceRequestId); + expect(reloaded.durationMs).toEqual(instance.durationMs); + }); + }); + + describe("load and save", () => { + it("should load from dictionary", () => { + const data: Record = {}; + const instance = LlmCompletePayload.load(data); + expect(instance).toBeDefined(); + }); + + it("should save to dictionary", () => { + const instance = new LlmCompletePayload(); + const data = instance.save(); + expect(data).toBeDefined(); + expect(typeof data).toBe("object"); + }); + }); +}); diff --git a/runtime/typescript/packages/core/tests/model/events/llm-start-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/llm-start-payload.test.ts new file mode 100644 index 00000000..fe8003b7 --- /dev/null +++ b/runtime/typescript/packages/core/tests/model/events/llm-start-payload.test.ts @@ -0,0 +1,79 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { LlmStartPayload } from "../../../src/model/index"; + +describe("LlmStartPayload", () => { + describe("construction", () => { + it("should create a new instance with defaults", () => { + const instance = new LlmStartPayload(); + expect(instance).toBeDefined(); + }); + + it("should create a new instance with partial initialization", () => { + const instance = new LlmStartPayload({}); + expect(instance).toBeDefined(); + }); + }); + + describe("JSON serialization", () => { + it("should load from JSON - example 1", () => { + const json = `{\n "provider": "openai",\n "modelId": "gpt-4o-mini",\n "messageCount": 4,\n "attempt": 0\n}`; + const instance = LlmStartPayload.fromJson(json); + expect(instance).toBeDefined(); + expect(instance.provider).toEqual("openai"); + expect(instance.modelId).toEqual("gpt-4o-mini"); + expect(instance.messageCount).toEqual(4); + expect(instance.attempt).toEqual(0); + }); + + it("should round-trip JSON - example 1", () => { + const json = `{\n "provider": "openai",\n "modelId": "gpt-4o-mini",\n "messageCount": 4,\n "attempt": 0\n}`; + const instance = LlmStartPayload.fromJson(json); + const output = instance.toJson(); + const reloaded = LlmStartPayload.fromJson(output); + expect(reloaded.provider).toEqual(instance.provider); + expect(reloaded.modelId).toEqual(instance.modelId); + expect(reloaded.messageCount).toEqual(instance.messageCount); + expect(reloaded.attempt).toEqual(instance.attempt); + }); + }); + + describe("YAML serialization", () => { + it("should load from YAML - example 1", () => { + const yaml = `provider: openai\nmodelId: gpt-4o-mini\nmessageCount: 4\nattempt: 0\n`; + const instance = LlmStartPayload.fromYaml(yaml); + expect(instance).toBeDefined(); + expect(instance.provider).toEqual("openai"); + expect(instance.modelId).toEqual("gpt-4o-mini"); + expect(instance.messageCount).toEqual(4); + expect(instance.attempt).toEqual(0); + }); + + it("should round-trip YAML - example 1", () => { + const yaml = `provider: openai\nmodelId: gpt-4o-mini\nmessageCount: 4\nattempt: 0\n`; + const instance = LlmStartPayload.fromYaml(yaml); + const output = instance.toYaml(); + const reloaded = LlmStartPayload.fromYaml(output); + expect(reloaded.provider).toEqual(instance.provider); + expect(reloaded.modelId).toEqual(instance.modelId); + expect(reloaded.messageCount).toEqual(instance.messageCount); + expect(reloaded.attempt).toEqual(instance.attempt); + }); + }); + + describe("load and save", () => { + it("should load from dictionary", () => { + const data: Record = {}; + const instance = LlmStartPayload.load(data); + expect(instance).toBeDefined(); + }); + + it("should save to dictionary", () => { + const instance = new LlmStartPayload(); + const data = instance.save(); + expect(data).toBeDefined(); + expect(typeof data).toBe("object"); + }); + }); +}); diff --git a/runtime/typescript/packages/core/tests/model/events/messages-updated-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/messages-updated-payload.test.ts index 57c00cff..7e5dafb6 100644 --- a/runtime/typescript/packages/core/tests/model/events/messages-updated-payload.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/messages-updated-payload.test.ts @@ -16,6 +16,44 @@ describe("MessagesUpdatedPayload", () => { }); }); + describe("JSON serialization", () => { + it("should load from JSON - example 1", () => { + const json = `{\n "reason": "tool_results",\n "removed": 2\n}`; + const instance = MessagesUpdatedPayload.fromJson(json); + expect(instance).toBeDefined(); + expect(instance.reason).toEqual("tool_results"); + expect(instance.removed).toEqual(2); + }); + + it("should round-trip JSON - example 1", () => { + const json = `{\n "reason": "tool_results",\n "removed": 2\n}`; + const instance = MessagesUpdatedPayload.fromJson(json); + const output = instance.toJson(); + const reloaded = MessagesUpdatedPayload.fromJson(output); + expect(reloaded.reason).toEqual(instance.reason); + expect(reloaded.removed).toEqual(instance.removed); + }); + }); + + describe("YAML serialization", () => { + it("should load from YAML - example 1", () => { + const yaml = `reason: tool_results\nremoved: 2\n`; + const instance = MessagesUpdatedPayload.fromYaml(yaml); + expect(instance).toBeDefined(); + expect(instance.reason).toEqual("tool_results"); + expect(instance.removed).toEqual(2); + }); + + it("should round-trip YAML - example 1", () => { + const yaml = `reason: tool_results\nremoved: 2\n`; + const instance = MessagesUpdatedPayload.fromYaml(yaml); + const output = instance.toYaml(); + const reloaded = MessagesUpdatedPayload.fromYaml(output); + expect(reloaded.reason).toEqual(instance.reason); + expect(reloaded.removed).toEqual(instance.removed); + }); + }); + describe("load and save", () => { it("should load from dictionary", () => { const data: Record = {}; diff --git a/runtime/typescript/packages/core/tests/model/events/permission-completed-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/permission-completed-payload.test.ts new file mode 100644 index 00000000..8d450523 --- /dev/null +++ b/runtime/typescript/packages/core/tests/model/events/permission-completed-payload.test.ts @@ -0,0 +1,75 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { PermissionCompletedPayload } from "../../../src/model/index"; + +describe("PermissionCompletedPayload", () => { + describe("construction", () => { + it("should create a new instance with defaults", () => { + const instance = new PermissionCompletedPayload(); + expect(instance).toBeDefined(); + }); + + it("should create a new instance with partial initialization", () => { + const instance = new PermissionCompletedPayload({}); + expect(instance).toBeDefined(); + }); + }); + + describe("JSON serialization", () => { + it("should load from JSON - example 1", () => { + const json = `{\n "permission": "tool.execute",\n "approved": true,\n "reason": "user_approved"\n}`; + const instance = PermissionCompletedPayload.fromJson(json); + expect(instance).toBeDefined(); + expect(instance.permission).toEqual("tool.execute"); + expect(instance.approved).toEqual(true); + expect(instance.reason).toEqual("user_approved"); + }); + + it("should round-trip JSON - example 1", () => { + const json = `{\n "permission": "tool.execute",\n "approved": true,\n "reason": "user_approved"\n}`; + const instance = PermissionCompletedPayload.fromJson(json); + const output = instance.toJson(); + const reloaded = PermissionCompletedPayload.fromJson(output); + expect(reloaded.permission).toEqual(instance.permission); + expect(reloaded.approved).toEqual(instance.approved); + expect(reloaded.reason).toEqual(instance.reason); + }); + }); + + describe("YAML serialization", () => { + it("should load from YAML - example 1", () => { + const yaml = `permission: tool.execute\napproved: true\nreason: user_approved\n`; + const instance = PermissionCompletedPayload.fromYaml(yaml); + expect(instance).toBeDefined(); + expect(instance.permission).toEqual("tool.execute"); + expect(instance.approved).toEqual(true); + expect(instance.reason).toEqual("user_approved"); + }); + + it("should round-trip YAML - example 1", () => { + const yaml = `permission: tool.execute\napproved: true\nreason: user_approved\n`; + const instance = PermissionCompletedPayload.fromYaml(yaml); + const output = instance.toYaml(); + const reloaded = PermissionCompletedPayload.fromYaml(output); + expect(reloaded.permission).toEqual(instance.permission); + expect(reloaded.approved).toEqual(instance.approved); + expect(reloaded.reason).toEqual(instance.reason); + }); + }); + + describe("load and save", () => { + it("should load from dictionary", () => { + const data: Record = {}; + const instance = PermissionCompletedPayload.load(data); + expect(instance).toBeDefined(); + }); + + it("should save to dictionary", () => { + const instance = new PermissionCompletedPayload(); + const data = instance.save(); + expect(data).toBeDefined(); + expect(typeof data).toBe("object"); + }); + }); +}); diff --git a/runtime/typescript/packages/core/tests/model/events/permission-requested-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/permission-requested-payload.test.ts new file mode 100644 index 00000000..e19ad6f2 --- /dev/null +++ b/runtime/typescript/packages/core/tests/model/events/permission-requested-payload.test.ts @@ -0,0 +1,71 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { PermissionRequestedPayload } from "../../../src/model/index"; + +describe("PermissionRequestedPayload", () => { + describe("construction", () => { + it("should create a new instance with defaults", () => { + const instance = new PermissionRequestedPayload(); + expect(instance).toBeDefined(); + }); + + it("should create a new instance with partial initialization", () => { + const instance = new PermissionRequestedPayload({}); + expect(instance).toBeDefined(); + }); + }); + + describe("JSON serialization", () => { + it("should load from JSON - example 1", () => { + const json = `{\n "permission": "tool.execute",\n "target": "shell"\n}`; + const instance = PermissionRequestedPayload.fromJson(json); + expect(instance).toBeDefined(); + expect(instance.permission).toEqual("tool.execute"); + expect(instance.target).toEqual("shell"); + }); + + it("should round-trip JSON - example 1", () => { + const json = `{\n "permission": "tool.execute",\n "target": "shell"\n}`; + const instance = PermissionRequestedPayload.fromJson(json); + const output = instance.toJson(); + const reloaded = PermissionRequestedPayload.fromJson(output); + expect(reloaded.permission).toEqual(instance.permission); + expect(reloaded.target).toEqual(instance.target); + }); + }); + + describe("YAML serialization", () => { + it("should load from YAML - example 1", () => { + const yaml = `permission: tool.execute\ntarget: shell\n`; + const instance = PermissionRequestedPayload.fromYaml(yaml); + expect(instance).toBeDefined(); + expect(instance.permission).toEqual("tool.execute"); + expect(instance.target).toEqual("shell"); + }); + + it("should round-trip YAML - example 1", () => { + const yaml = `permission: tool.execute\ntarget: shell\n`; + const instance = PermissionRequestedPayload.fromYaml(yaml); + const output = instance.toYaml(); + const reloaded = PermissionRequestedPayload.fromYaml(output); + expect(reloaded.permission).toEqual(instance.permission); + expect(reloaded.target).toEqual(instance.target); + }); + }); + + describe("load and save", () => { + it("should load from dictionary", () => { + const data: Record = {}; + const instance = PermissionRequestedPayload.load(data); + expect(instance).toBeDefined(); + }); + + it("should save to dictionary", () => { + const instance = new PermissionRequestedPayload(); + const data = instance.save(); + expect(data).toBeDefined(); + expect(typeof data).toBe("object"); + }); + }); +}); diff --git a/runtime/typescript/packages/core/tests/model/events/retry-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/retry-payload.test.ts new file mode 100644 index 00000000..453c687a --- /dev/null +++ b/runtime/typescript/packages/core/tests/model/events/retry-payload.test.ts @@ -0,0 +1,83 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { RetryPayload } from "../../../src/model/index"; + +describe("RetryPayload", () => { + describe("construction", () => { + it("should create a new instance with defaults", () => { + const instance = new RetryPayload(); + expect(instance).toBeDefined(); + }); + + it("should create a new instance with partial initialization", () => { + const instance = new RetryPayload({}); + expect(instance).toBeDefined(); + }); + }); + + describe("JSON serialization", () => { + it("should load from JSON - example 1", () => { + const json = `{\n "operation": "llm",\n "attempt": 2,\n "maxAttempts": 3,\n "delayMs": 1250,\n "reason": "rate_limit"\n}`; + const instance = RetryPayload.fromJson(json); + expect(instance).toBeDefined(); + expect(instance.operation).toEqual("llm"); + expect(instance.attempt).toEqual(2); + expect(instance.maxAttempts).toEqual(3); + expect(instance.delayMs).toEqual(1250); + expect(instance.reason).toEqual("rate_limit"); + }); + + it("should round-trip JSON - example 1", () => { + const json = `{\n "operation": "llm",\n "attempt": 2,\n "maxAttempts": 3,\n "delayMs": 1250,\n "reason": "rate_limit"\n}`; + const instance = RetryPayload.fromJson(json); + const output = instance.toJson(); + const reloaded = RetryPayload.fromJson(output); + expect(reloaded.operation).toEqual(instance.operation); + expect(reloaded.attempt).toEqual(instance.attempt); + expect(reloaded.maxAttempts).toEqual(instance.maxAttempts); + expect(reloaded.delayMs).toEqual(instance.delayMs); + expect(reloaded.reason).toEqual(instance.reason); + }); + }); + + describe("YAML serialization", () => { + it("should load from YAML - example 1", () => { + const yaml = `operation: llm\nattempt: 2\nmaxAttempts: 3\ndelayMs: 1250\nreason: rate_limit\n`; + const instance = RetryPayload.fromYaml(yaml); + expect(instance).toBeDefined(); + expect(instance.operation).toEqual("llm"); + expect(instance.attempt).toEqual(2); + expect(instance.maxAttempts).toEqual(3); + expect(instance.delayMs).toEqual(1250); + expect(instance.reason).toEqual("rate_limit"); + }); + + it("should round-trip YAML - example 1", () => { + const yaml = `operation: llm\nattempt: 2\nmaxAttempts: 3\ndelayMs: 1250\nreason: rate_limit\n`; + const instance = RetryPayload.fromYaml(yaml); + const output = instance.toYaml(); + const reloaded = RetryPayload.fromYaml(output); + expect(reloaded.operation).toEqual(instance.operation); + expect(reloaded.attempt).toEqual(instance.attempt); + expect(reloaded.maxAttempts).toEqual(instance.maxAttempts); + expect(reloaded.delayMs).toEqual(instance.delayMs); + expect(reloaded.reason).toEqual(instance.reason); + }); + }); + + describe("load and save", () => { + it("should load from dictionary", () => { + const data: Record = {}; + const instance = RetryPayload.load(data); + expect(instance).toBeDefined(); + }); + + it("should save to dictionary", () => { + const instance = new RetryPayload(); + const data = instance.save(); + expect(data).toBeDefined(); + expect(typeof data).toBe("object"); + }); + }); +}); diff --git a/runtime/typescript/packages/core/tests/model/events/tool-call-complete-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/tool-call-complete-payload.test.ts new file mode 100644 index 00000000..f5491a3d --- /dev/null +++ b/runtime/typescript/packages/core/tests/model/events/tool-call-complete-payload.test.ts @@ -0,0 +1,83 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { ToolCallCompletePayload } from "../../../src/model/index"; + +describe("ToolCallCompletePayload", () => { + describe("construction", () => { + it("should create a new instance with defaults", () => { + const instance = new ToolCallCompletePayload(); + expect(instance).toBeDefined(); + }); + + it("should create a new instance with partial initialization", () => { + const instance = new ToolCallCompletePayload({}); + expect(instance).toBeDefined(); + }); + }); + + describe("JSON serialization", () => { + it("should load from JSON - example 1", () => { + const json = `{\n "id": "call_abc123",\n "name": "get_weather",\n "success": true,\n "durationMs": 42,\n "errorKind": "timeout"\n}`; + const instance = ToolCallCompletePayload.fromJson(json); + expect(instance).toBeDefined(); + expect(instance.id).toEqual("call_abc123"); + expect(instance.name).toEqual("get_weather"); + expect(instance.success).toEqual(true); + expect(instance.durationMs).toEqual(42); + expect(instance.errorKind).toEqual("timeout"); + }); + + it("should round-trip JSON - example 1", () => { + const json = `{\n "id": "call_abc123",\n "name": "get_weather",\n "success": true,\n "durationMs": 42,\n "errorKind": "timeout"\n}`; + const instance = ToolCallCompletePayload.fromJson(json); + const output = instance.toJson(); + const reloaded = ToolCallCompletePayload.fromJson(output); + expect(reloaded.id).toEqual(instance.id); + expect(reloaded.name).toEqual(instance.name); + expect(reloaded.success).toEqual(instance.success); + expect(reloaded.durationMs).toEqual(instance.durationMs); + expect(reloaded.errorKind).toEqual(instance.errorKind); + }); + }); + + describe("YAML serialization", () => { + it("should load from YAML - example 1", () => { + const yaml = `id: call_abc123\nname: get_weather\nsuccess: true\ndurationMs: 42\nerrorKind: timeout\n`; + const instance = ToolCallCompletePayload.fromYaml(yaml); + expect(instance).toBeDefined(); + expect(instance.id).toEqual("call_abc123"); + expect(instance.name).toEqual("get_weather"); + expect(instance.success).toEqual(true); + expect(instance.durationMs).toEqual(42); + expect(instance.errorKind).toEqual("timeout"); + }); + + it("should round-trip YAML - example 1", () => { + const yaml = `id: call_abc123\nname: get_weather\nsuccess: true\ndurationMs: 42\nerrorKind: timeout\n`; + const instance = ToolCallCompletePayload.fromYaml(yaml); + const output = instance.toYaml(); + const reloaded = ToolCallCompletePayload.fromYaml(output); + expect(reloaded.id).toEqual(instance.id); + expect(reloaded.name).toEqual(instance.name); + expect(reloaded.success).toEqual(instance.success); + expect(reloaded.durationMs).toEqual(instance.durationMs); + expect(reloaded.errorKind).toEqual(instance.errorKind); + }); + }); + + describe("load and save", () => { + it("should load from dictionary", () => { + const data: Record = {}; + const instance = ToolCallCompletePayload.load(data); + expect(instance).toBeDefined(); + }); + + it("should save to dictionary", () => { + const instance = new ToolCallCompletePayload(); + const data = instance.save(); + expect(data).toBeDefined(); + expect(typeof data).toBe("object"); + }); + }); +}); diff --git a/runtime/typescript/packages/core/tests/model/events/tool-call-start-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/tool-call-start-payload.test.ts index 144920d5..0e2fb23f 100644 --- a/runtime/typescript/packages/core/tests/model/events/tool-call-start-payload.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/tool-call-start-payload.test.ts @@ -18,18 +18,20 @@ describe("ToolCallStartPayload", () => { describe("JSON serialization", () => { it("should load from JSON - example 1", () => { - const json = `{\n "name": "get_weather",\n "arguments": "{\\"city\\": \\"Paris\\"}"\n}`; + const json = `{\n "id": "call_abc123",\n "name": "get_weather",\n "arguments": "{\\"city\\": \\"Paris\\"}"\n}`; const instance = ToolCallStartPayload.fromJson(json); expect(instance).toBeDefined(); + expect(instance.id).toEqual("call_abc123"); expect(instance.name).toEqual("get_weather"); expect(instance.arguments).toEqual('{"city": "Paris"}'); }); it("should round-trip JSON - example 1", () => { - const json = `{\n "name": "get_weather",\n "arguments": "{\\"city\\": \\"Paris\\"}"\n}`; + const json = `{\n "id": "call_abc123",\n "name": "get_weather",\n "arguments": "{\\"city\\": \\"Paris\\"}"\n}`; const instance = ToolCallStartPayload.fromJson(json); const output = instance.toJson(); const reloaded = ToolCallStartPayload.fromJson(output); + expect(reloaded.id).toEqual(instance.id); expect(reloaded.name).toEqual(instance.name); expect(reloaded.arguments).toEqual(instance.arguments); }); @@ -37,18 +39,20 @@ describe("ToolCallStartPayload", () => { describe("YAML serialization", () => { it("should load from YAML - example 1", () => { - const yaml = `name: get_weather\narguments: "{\\"city\\": \\"Paris\\"}"\n`; + const yaml = `id: call_abc123\nname: get_weather\narguments: "{\\"city\\": \\"Paris\\"}"\n`; const instance = ToolCallStartPayload.fromYaml(yaml); expect(instance).toBeDefined(); + expect(instance.id).toEqual("call_abc123"); expect(instance.name).toEqual("get_weather"); expect(instance.arguments).toEqual('{"city": "Paris"}'); }); it("should round-trip YAML - example 1", () => { - const yaml = `name: get_weather\narguments: "{\\"city\\": \\"Paris\\"}"\n`; + const yaml = `id: call_abc123\nname: get_weather\narguments: "{\\"city\\": \\"Paris\\"}"\n`; const instance = ToolCallStartPayload.fromYaml(yaml); const output = instance.toYaml(); const reloaded = ToolCallStartPayload.fromYaml(output); + expect(reloaded.id).toEqual(instance.id); expect(reloaded.name).toEqual(instance.name); expect(reloaded.arguments).toEqual(instance.arguments); }); diff --git a/runtime/typescript/packages/core/tests/model/events/turn-end-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/turn-end-payload.test.ts new file mode 100644 index 00000000..783f75d1 --- /dev/null +++ b/runtime/typescript/packages/core/tests/model/events/turn-end-payload.test.ts @@ -0,0 +1,71 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { TurnEndPayload } from "../../../src/model/index"; + +describe("TurnEndPayload", () => { + describe("construction", () => { + it("should create a new instance with defaults", () => { + const instance = new TurnEndPayload(); + expect(instance).toBeDefined(); + }); + + it("should create a new instance with partial initialization", () => { + const instance = new TurnEndPayload({}); + expect(instance).toBeDefined(); + }); + }); + + describe("JSON serialization", () => { + it("should load from JSON - example 1", () => { + const json = `{\n "iterations": 2,\n "durationMs": 1500\n}`; + const instance = TurnEndPayload.fromJson(json); + expect(instance).toBeDefined(); + expect(instance.iterations).toEqual(2); + expect(instance.durationMs).toEqual(1500); + }); + + it("should round-trip JSON - example 1", () => { + const json = `{\n "iterations": 2,\n "durationMs": 1500\n}`; + const instance = TurnEndPayload.fromJson(json); + const output = instance.toJson(); + const reloaded = TurnEndPayload.fromJson(output); + expect(reloaded.iterations).toEqual(instance.iterations); + expect(reloaded.durationMs).toEqual(instance.durationMs); + }); + }); + + describe("YAML serialization", () => { + it("should load from YAML - example 1", () => { + const yaml = `iterations: 2\ndurationMs: 1500\n`; + const instance = TurnEndPayload.fromYaml(yaml); + expect(instance).toBeDefined(); + expect(instance.iterations).toEqual(2); + expect(instance.durationMs).toEqual(1500); + }); + + it("should round-trip YAML - example 1", () => { + const yaml = `iterations: 2\ndurationMs: 1500\n`; + const instance = TurnEndPayload.fromYaml(yaml); + const output = instance.toYaml(); + const reloaded = TurnEndPayload.fromYaml(output); + expect(reloaded.iterations).toEqual(instance.iterations); + expect(reloaded.durationMs).toEqual(instance.durationMs); + }); + }); + + describe("load and save", () => { + it("should load from dictionary", () => { + const data: Record = {}; + const instance = TurnEndPayload.load(data); + expect(instance).toBeDefined(); + }); + + it("should save to dictionary", () => { + const instance = new TurnEndPayload(); + const data = instance.save(); + expect(data).toBeDefined(); + expect(typeof data).toBe("object"); + }); + }); +}); diff --git a/runtime/typescript/packages/core/tests/model/events/turn-event.test.ts b/runtime/typescript/packages/core/tests/model/events/turn-event.test.ts new file mode 100644 index 00000000..fe8939a7 --- /dev/null +++ b/runtime/typescript/packages/core/tests/model/events/turn-event.test.ts @@ -0,0 +1,87 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { TurnEvent } from "../../../src/model/index"; + +describe("TurnEvent", () => { + describe("construction", () => { + it("should create a new instance with defaults", () => { + const instance = new TurnEvent(); + expect(instance).toBeDefined(); + }); + + it("should create a new instance with partial initialization", () => { + const instance = new TurnEvent({}); + expect(instance).toBeDefined(); + }); + }); + + describe("JSON serialization", () => { + it("should load from JSON - example 1", () => { + const json = `{\n "id": "evt_abc123",\n "timestamp": "2026-06-09T20:00:00Z",\n "turnId": "turn_001",\n "iteration": 0,\n "parentId": "evt_parent",\n "spanId": "span_tool_001"\n}`; + const instance = TurnEvent.fromJson(json); + expect(instance).toBeDefined(); + expect(instance.id).toEqual("evt_abc123"); + expect(instance.timestamp).toEqual("2026-06-09T20:00:00Z"); + expect(instance.turnId).toEqual("turn_001"); + expect(instance.iteration).toEqual(0); + expect(instance.parentId).toEqual("evt_parent"); + expect(instance.spanId).toEqual("span_tool_001"); + }); + + it("should round-trip JSON - example 1", () => { + const json = `{\n "id": "evt_abc123",\n "timestamp": "2026-06-09T20:00:00Z",\n "turnId": "turn_001",\n "iteration": 0,\n "parentId": "evt_parent",\n "spanId": "span_tool_001"\n}`; + const instance = TurnEvent.fromJson(json); + const output = instance.toJson(); + const reloaded = TurnEvent.fromJson(output); + expect(reloaded.id).toEqual(instance.id); + expect(reloaded.timestamp).toEqual(instance.timestamp); + expect(reloaded.turnId).toEqual(instance.turnId); + expect(reloaded.iteration).toEqual(instance.iteration); + expect(reloaded.parentId).toEqual(instance.parentId); + expect(reloaded.spanId).toEqual(instance.spanId); + }); + }); + + describe("YAML serialization", () => { + it("should load from YAML - example 1", () => { + const yaml = `id: evt_abc123\ntimestamp: "2026-06-09T20:00:00Z"\nturnId: turn_001\niteration: 0\nparentId: evt_parent\nspanId: span_tool_001\n`; + const instance = TurnEvent.fromYaml(yaml); + expect(instance).toBeDefined(); + expect(instance.id).toEqual("evt_abc123"); + expect(instance.timestamp).toEqual("2026-06-09T20:00:00Z"); + expect(instance.turnId).toEqual("turn_001"); + expect(instance.iteration).toEqual(0); + expect(instance.parentId).toEqual("evt_parent"); + expect(instance.spanId).toEqual("span_tool_001"); + }); + + it("should round-trip YAML - example 1", () => { + const yaml = `id: evt_abc123\ntimestamp: "2026-06-09T20:00:00Z"\nturnId: turn_001\niteration: 0\nparentId: evt_parent\nspanId: span_tool_001\n`; + const instance = TurnEvent.fromYaml(yaml); + const output = instance.toYaml(); + const reloaded = TurnEvent.fromYaml(output); + expect(reloaded.id).toEqual(instance.id); + expect(reloaded.timestamp).toEqual(instance.timestamp); + expect(reloaded.turnId).toEqual(instance.turnId); + expect(reloaded.iteration).toEqual(instance.iteration); + expect(reloaded.parentId).toEqual(instance.parentId); + expect(reloaded.spanId).toEqual(instance.spanId); + }); + }); + + describe("load and save", () => { + it("should load from dictionary", () => { + const data: Record = {}; + const instance = TurnEvent.load(data); + expect(instance).toBeDefined(); + }); + + it("should save to dictionary", () => { + const instance = new TurnEvent(); + const data = instance.save(); + expect(data).toBeDefined(); + expect(typeof data).toBe("object"); + }); + }); +}); diff --git a/runtime/typescript/packages/core/tests/model/events/turn-start-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/turn-start-payload.test.ts new file mode 100644 index 00000000..fc16c852 --- /dev/null +++ b/runtime/typescript/packages/core/tests/model/events/turn-start-payload.test.ts @@ -0,0 +1,71 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { TurnStartPayload } from "../../../src/model/index"; + +describe("TurnStartPayload", () => { + describe("construction", () => { + it("should create a new instance with defaults", () => { + const instance = new TurnStartPayload(); + expect(instance).toBeDefined(); + }); + + it("should create a new instance with partial initialization", () => { + const instance = new TurnStartPayload({}); + expect(instance).toBeDefined(); + }); + }); + + describe("JSON serialization", () => { + it("should load from JSON - example 1", () => { + const json = `{\n "agent": "weather-agent",\n "maxIterations": 10\n}`; + const instance = TurnStartPayload.fromJson(json); + expect(instance).toBeDefined(); + expect(instance.agent).toEqual("weather-agent"); + expect(instance.maxIterations).toEqual(10); + }); + + it("should round-trip JSON - example 1", () => { + const json = `{\n "agent": "weather-agent",\n "maxIterations": 10\n}`; + const instance = TurnStartPayload.fromJson(json); + const output = instance.toJson(); + const reloaded = TurnStartPayload.fromJson(output); + expect(reloaded.agent).toEqual(instance.agent); + expect(reloaded.maxIterations).toEqual(instance.maxIterations); + }); + }); + + describe("YAML serialization", () => { + it("should load from YAML - example 1", () => { + const yaml = `agent: weather-agent\nmaxIterations: 10\n`; + const instance = TurnStartPayload.fromYaml(yaml); + expect(instance).toBeDefined(); + expect(instance.agent).toEqual("weather-agent"); + expect(instance.maxIterations).toEqual(10); + }); + + it("should round-trip YAML - example 1", () => { + const yaml = `agent: weather-agent\nmaxIterations: 10\n`; + const instance = TurnStartPayload.fromYaml(yaml); + const output = instance.toYaml(); + const reloaded = TurnStartPayload.fromYaml(output); + expect(reloaded.agent).toEqual(instance.agent); + expect(reloaded.maxIterations).toEqual(instance.maxIterations); + }); + }); + + describe("load and save", () => { + it("should load from dictionary", () => { + const data: Record = {}; + const instance = TurnStartPayload.load(data); + expect(instance).toBeDefined(); + }); + + it("should save to dictionary", () => { + const instance = new TurnStartPayload(); + const data = instance.save(); + expect(data).toBeDefined(); + expect(typeof data).toBe("object"); + }); + }); +}); diff --git a/runtime/typescript/packages/core/tests/model/events/turn-summary.test.ts b/runtime/typescript/packages/core/tests/model/events/turn-summary.test.ts new file mode 100644 index 00000000..ea7e3ad5 --- /dev/null +++ b/runtime/typescript/packages/core/tests/model/events/turn-summary.test.ts @@ -0,0 +1,91 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { TurnSummary } from "../../../src/model/index"; + +describe("TurnSummary", () => { + describe("construction", () => { + it("should create a new instance with defaults", () => { + const instance = new TurnSummary(); + expect(instance).toBeDefined(); + }); + + it("should create a new instance with partial initialization", () => { + const instance = new TurnSummary({}); + expect(instance).toBeDefined(); + }); + }); + + describe("JSON serialization", () => { + it("should load from JSON - example 1", () => { + const json = `{\n "turnId": "turn_001",\n "status": "success",\n "iterations": 2,\n "llmCalls": 3,\n "toolCalls": 2,\n "retries": 1,\n "durationMs": 2500\n}`; + const instance = TurnSummary.fromJson(json); + expect(instance).toBeDefined(); + expect(instance.turnId).toEqual("turn_001"); + expect(instance.status).toEqual("success"); + expect(instance.iterations).toEqual(2); + expect(instance.llmCalls).toEqual(3); + expect(instance.toolCalls).toEqual(2); + expect(instance.retries).toEqual(1); + expect(instance.durationMs).toEqual(2500); + }); + + it("should round-trip JSON - example 1", () => { + const json = `{\n "turnId": "turn_001",\n "status": "success",\n "iterations": 2,\n "llmCalls": 3,\n "toolCalls": 2,\n "retries": 1,\n "durationMs": 2500\n}`; + const instance = TurnSummary.fromJson(json); + const output = instance.toJson(); + const reloaded = TurnSummary.fromJson(output); + expect(reloaded.turnId).toEqual(instance.turnId); + expect(reloaded.status).toEqual(instance.status); + expect(reloaded.iterations).toEqual(instance.iterations); + expect(reloaded.llmCalls).toEqual(instance.llmCalls); + expect(reloaded.toolCalls).toEqual(instance.toolCalls); + expect(reloaded.retries).toEqual(instance.retries); + expect(reloaded.durationMs).toEqual(instance.durationMs); + }); + }); + + describe("YAML serialization", () => { + it("should load from YAML - example 1", () => { + const yaml = `turnId: turn_001\nstatus: success\niterations: 2\nllmCalls: 3\ntoolCalls: 2\nretries: 1\ndurationMs: 2500\n`; + const instance = TurnSummary.fromYaml(yaml); + expect(instance).toBeDefined(); + expect(instance.turnId).toEqual("turn_001"); + expect(instance.status).toEqual("success"); + expect(instance.iterations).toEqual(2); + expect(instance.llmCalls).toEqual(3); + expect(instance.toolCalls).toEqual(2); + expect(instance.retries).toEqual(1); + expect(instance.durationMs).toEqual(2500); + }); + + it("should round-trip YAML - example 1", () => { + const yaml = `turnId: turn_001\nstatus: success\niterations: 2\nllmCalls: 3\ntoolCalls: 2\nretries: 1\ndurationMs: 2500\n`; + const instance = TurnSummary.fromYaml(yaml); + const output = instance.toYaml(); + const reloaded = TurnSummary.fromYaml(output); + expect(reloaded.turnId).toEqual(instance.turnId); + expect(reloaded.status).toEqual(instance.status); + expect(reloaded.iterations).toEqual(instance.iterations); + expect(reloaded.llmCalls).toEqual(instance.llmCalls); + expect(reloaded.toolCalls).toEqual(instance.toolCalls); + expect(reloaded.retries).toEqual(instance.retries); + expect(reloaded.durationMs).toEqual(instance.durationMs); + }); + }); + + describe("load and save", () => { + it("should load from dictionary", () => { + const data: Record = {}; + const instance = TurnSummary.load(data); + expect(instance).toBeDefined(); + }); + + it("should save to dictionary", () => { + const instance = new TurnSummary(); + const data = instance.save(); + expect(data).toBeDefined(); + expect(typeof data).toBe("object"); + }); + }); +}); diff --git a/runtime/typescript/packages/core/tests/model/events/turn-trace.test.ts b/runtime/typescript/packages/core/tests/model/events/turn-trace.test.ts new file mode 100644 index 00000000..af0f92fb --- /dev/null +++ b/runtime/typescript/packages/core/tests/model/events/turn-trace.test.ts @@ -0,0 +1,75 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { TurnTrace } from "../../../src/model/index"; + +describe("TurnTrace", () => { + describe("construction", () => { + it("should create a new instance with defaults", () => { + const instance = new TurnTrace(); + expect(instance).toBeDefined(); + }); + + it("should create a new instance with partial initialization", () => { + const instance = new TurnTrace({}); + expect(instance).toBeDefined(); + }); + }); + + describe("JSON serialization", () => { + it("should load from JSON - example 1", () => { + const json = `{\n "version": "1",\n "runtime": "typescript",\n "promptyVersion": "2.0.0"\n}`; + const instance = TurnTrace.fromJson(json); + expect(instance).toBeDefined(); + expect(instance.version).toEqual("1"); + expect(instance.runtime).toEqual("typescript"); + expect(instance.promptyVersion).toEqual("2.0.0"); + }); + + it("should round-trip JSON - example 1", () => { + const json = `{\n "version": "1",\n "runtime": "typescript",\n "promptyVersion": "2.0.0"\n}`; + const instance = TurnTrace.fromJson(json); + const output = instance.toJson(); + const reloaded = TurnTrace.fromJson(output); + expect(reloaded.version).toEqual(instance.version); + expect(reloaded.runtime).toEqual(instance.runtime); + expect(reloaded.promptyVersion).toEqual(instance.promptyVersion); + }); + }); + + describe("YAML serialization", () => { + it("should load from YAML - example 1", () => { + const yaml = `version: "1"\nruntime: typescript\npromptyVersion: 2.0.0\n`; + const instance = TurnTrace.fromYaml(yaml); + expect(instance).toBeDefined(); + expect(instance.version).toEqual("1"); + expect(instance.runtime).toEqual("typescript"); + expect(instance.promptyVersion).toEqual("2.0.0"); + }); + + it("should round-trip YAML - example 1", () => { + const yaml = `version: "1"\nruntime: typescript\npromptyVersion: 2.0.0\n`; + const instance = TurnTrace.fromYaml(yaml); + const output = instance.toYaml(); + const reloaded = TurnTrace.fromYaml(output); + expect(reloaded.version).toEqual(instance.version); + expect(reloaded.runtime).toEqual(instance.runtime); + expect(reloaded.promptyVersion).toEqual(instance.promptyVersion); + }); + }); + + describe("load and save", () => { + it("should load from dictionary", () => { + const data: Record = {}; + const instance = TurnTrace.load(data); + expect(instance).toBeDefined(); + }); + + it("should save to dictionary", () => { + const instance = new TurnTrace(); + const data = instance.save(); + expect(data).toBeDefined(); + expect(typeof data).toBe("object"); + }); + }); +}); diff --git a/schema/emitter/src/languages/csharp/emitter.ts b/schema/emitter/src/languages/csharp/emitter.ts index 54885174..8440dcce 100644 --- a/schema/emitter/src/languages/csharp/emitter.ts +++ b/schema/emitter/src/languages/csharp/emitter.ts @@ -158,7 +158,7 @@ export function emitCSharpEnum(enumDef: EnumDef, namespace: string): string { lines.push("{"); for (const value of enumDef.values) { - const memberName = value.charAt(0).toUpperCase() + value.slice(1); + const memberName = toPascalCase(value); // Add EnumMember attribute if the wire value doesn't match the member name exactly lines.push(` [JsonPropertyName("${value}")]`); lines.push(` ${memberName},`); @@ -226,14 +226,14 @@ function emitCSharpInterface(type: TypeDecl, namespace: string, lines: string[]) // Synchronous method if (method.optional) { // Return type already includes nullability — provide default body - lines.push(` ${ret} ${toPascalCase(method.name)}(${params}) => default;`); + lines.push(` ${ret} ${toPascalCase(method.name)}(${params}) => default!;`); } else { lines.push(` ${ret} ${toPascalCase(method.name)}(${params});`); } } else { // Async method if (method.optional) { - lines.push(` Task<${ret}> ${toPascalCase(method.name)}Async(${params}) => Task.FromResult<${ret}>(default);`); + lines.push(` Task<${ret}> ${toPascalCase(method.name)}Async(${params}) => Task.FromResult<${ret}>(default!);`); } else { lines.push(` Task<${ret}> ${toPascalCase(method.name)}Async(${params});`); } @@ -273,7 +273,7 @@ function emitXmlDocComment(description: string, indent: string, lines: string[]) lines.push(`${indent}/// ${descLines[i]}`); // Add empty /// line between paragraphs (if multiple lines and not the last) if (descLines.length > 1 && i < descLines.length - 1) { - lines.push(`${indent}/// `); + lines.push(`${indent}///`); } } lines.push(`${indent}/// `); @@ -873,7 +873,8 @@ function emitSaveAssignment(assign: SaveAssignment, lines: string[]): void { function getSaveExpression(assign: SaveAssignment, propName: string): string { // Named enum — serialize as string (skip open enums — they're already string) if (assign.enumName && !assign.isOpenEnum) { - return `result["${assign.targetName}"] = obj.${propName}.ToString().ToLowerInvariant();`; + const valueExpr = assign.isOptional ? `obj.${propName}.Value` : `obj.${propName}`; + return `result["${assign.targetName}"] = ${valueExpr}.ToString().ToLowerInvariant();`; } const cat = assign.category; switch (cat.kind) { diff --git a/schema/emitter/src/languages/python/test-emitter.ts b/schema/emitter/src/languages/python/test-emitter.ts index e8b6c944..e6a3c945 100644 --- a/schema/emitter/src/languages/python/test-emitter.ts +++ b/schema/emitter/src/languages/python/test-emitter.ts @@ -280,8 +280,8 @@ export function emitPythonTest(ctx: BaseTestContext & { classCtx: PythonClassCon for (let i = 0; i < examples.length; i++) { const sample = examples[i]; const suffix = i === 0 ? '' : `_${i}`; - const jsonBlock = sample.json.map(line => ` ${line}`).join('\n'); - const yamlBlock = sample.yaml.map(line => ` ${line}`).join('\n'); + const jsonBlock = sample.json.map(line => line.length > 0 ? ` ${line}` : '').join('\n'); + const yamlBlock = sample.yaml.map(line => line.length > 0 ? ` ${line}` : '').join('\n'); // test_load_json lines.push(`def test_load_json_${typeNameLower}${suffix}():`); diff --git a/schema/emitter/src/languages/rust/driver.ts b/schema/emitter/src/languages/rust/driver.ts index b0ade465..eeec574f 100644 --- a/schema/emitter/src/languages/rust/driver.ts +++ b/schema/emitter/src/languages/rust/driver.ts @@ -1,6 +1,6 @@ import { EmitContext, emitFile, resolvePath } from "@typespec/compiler"; import { execFileSync } from "child_process"; -import { existsSync, readdirSync, statSync, unlinkSync } from "fs"; +import { existsSync, readFileSync, readdirSync, statSync, unlinkSync, writeFileSync } from "fs"; import { resolve } from "path"; import { EmitTarget, PromptyEmitterOptions } from "../../lib.js"; import { @@ -212,12 +212,29 @@ function formatRustFiles(outputDir: string): void { stdio: 'pipe', encoding: 'utf-8' }); + normalizeRustFileEndings(resolve(outputDir, '..')); } catch (error) { console.warn(`Warning: cargo fmt failed. You may need to install Rust.`); } } } +function normalizeRustFileEndings(dir: string): void { + for (const entry of readdirSync(dir)) { + const fullPath = resolve(dir, entry); + const stat = statSync(fullPath); + if (stat.isDirectory()) { + normalizeRustFileEndings(fullPath); + continue; + } + if (!entry.endsWith(".rs")) { + continue; + } + const content = readFileSync(fullPath, "utf-8"); + writeFileSync(fullPath, `${content.trimEnd()}\n`, "utf-8"); + } +} + /** * Build context for rendering a test file. */ @@ -238,7 +255,7 @@ async function emitRustFile( const filePath = resolvePath(outputDir, filename); await emitFile(context.program, { path: filePath, - content, + content: `${content.trimEnd()}\n`, }); } @@ -435,7 +452,7 @@ function emitRustLib(rootModules: string[], groups: string[] = []): string { for (const group of groups) { out += `\npub mod ${group};\npub use ${group}::*;\n`; } - return out; + return `${out.trimEnd()}\n`; } /** diff --git a/schema/emitter/src/languages/rust/emitter.ts b/schema/emitter/src/languages/rust/emitter.ts index 4e5e9252..0db37eaf 100644 --- a/schema/emitter/src/languages/rust/emitter.ts +++ b/schema/emitter/src/languages/rust/emitter.ts @@ -62,6 +62,13 @@ function emitDocComment(description: string, indent: string, lines: string[]): v lines.push(`${indent}/// ${oneLine}`); } +function renderLines(lines: string[]): string { + while (lines.length > 0 && lines[lines.length - 1] === "") { + lines.pop(); + } + return `${lines.join("\n")}\n`; +} + /** * Convert a string literal value to a PascalCase Rust variant name. * e.g., "system" → "System", "tool" → "Tool", "text" → "Text" @@ -267,7 +274,7 @@ export function emitRustFile( if (baseType.isProtocol) { emitProtocolTrait(baseType, lines); lines.push(""); - return lines.join("\n"); + return renderLines(lines); } // Collect base field names for variant field extraction @@ -293,7 +300,7 @@ export function emitRustFile( } lines.push(""); - return lines.join("\n"); + return renderLines(lines); } // ============================================================================ diff --git a/schema/model/conversation/tool-invocation.tsp b/schema/model/conversation/tool-invocation.tsp index fb586ef0..7e78c6ff 100644 --- a/schema/model/conversation/tool-invocation.tsp +++ b/schema/model/conversation/tool-invocation.tsp @@ -3,6 +3,13 @@ import "./content.tsp"; namespace Prompty; +/** + * Normalized status for tool execution. The transport can complete while the + * tool itself fails, times out, or is cancelled; status captures the semantic + * outcome independently of callback delivery. + */ +alias ToolResultStatus = "success" | "error" | "cancelled" | "timeout"; + /** * A tool call requested by the LLM. Contains the function name and serialized * arguments that should be dispatched to the appropriate tool handler. @@ -38,4 +45,19 @@ model ToolResult { @doc("The content parts of the tool result") @sample(#{ parts: #[#{ kind: "text", value: "72°F and sunny" }] }) parts: ContentPart[]; + + @doc("Semantic execution status for the tool result") + status?: ToolResultStatus; + + @doc("Stable machine-readable error category when status is not success") + @sample(#{ errorKind: "missing_tool" }) + errorKind?: string; + + @doc("Human-readable error message when status is not success") + @sample(#{ errorMessage: "Tool 'get_weather' is not registered" }) + errorMessage?: string; + + @doc("Tool execution duration in milliseconds") + @sample(#{ durationMs: 42 }) + durationMs?: float64; } diff --git a/schema/model/events/payloads.tsp b/schema/model/events/payloads.tsp index d044524f..80774812 100644 --- a/schema/model/events/payloads.tsp +++ b/schema/model/events/payloads.tsp @@ -1,6 +1,7 @@ import "prompty-emitter"; import "../conversation/message.tsp"; import "../conversation/tool-invocation.tsp"; +import "../model/usage.tsp"; namespace Prompty; @@ -9,10 +10,18 @@ namespace Prompty; * real-time UIs, logging, and coordination without coupling the loop * to any particular output mechanism. */ -alias AgentEventType = +alias TurnEventType = + | "turn_start" + | "turn_end" + | "llm_start" + | "llm_complete" + | "retry" + | "permission_requested" + | "permission_completed" | "token" | "thinking" | "tool_call_start" + | "tool_call_complete" | "tool_result" | "status" | "messages_updated" @@ -23,6 +32,182 @@ alias AgentEventType = | "compaction_complete" | "compaction_failed"; +/** + * Final semantic status for a turn. + */ +alias TurnStatus = "success" | "error" | "cancelled"; + +/** + * A canonical event envelope emitted by the turn harness. The payload is kept + * JSON-shaped so runtimes can load all events even when newer payload types are + * added; event-specific typed payload models below define the canonical shapes. + */ +model TurnEvent { + @doc("Unique identifier for this event") + @sample(#{ id: "evt_abc123" }) + id: string; + + @doc("Event type discriminator") + type: TurnEventType; + + @doc("ISO 8601 UTC timestamp when the event was emitted") + @sample(#{ timestamp: "2026-06-09T20:00:00Z" }) + timestamp: string; + + @doc("Stable identifier for the outer turn") + @sample(#{ turnId: "turn_001" }) + turnId?: string; + + @doc("Zero-based agent-loop iteration associated with the event") + @sample(#{ iteration: 0 }) + iteration?: int32; + + @doc("Parent event or span identifier for reconstructing event hierarchy") + @sample(#{ parentId: "evt_parent" }) + parentId?: string; + + @doc("Trace span identifier associated with this event") + @sample(#{ spanId: "span_tool_001" }) + spanId?: string; + + @doc("Event-specific payload. Use the typed payload model matching 'type'.") + payload: Record = #{}; +} + +/** + * Payload for "turn_start" events — a turn is beginning. + */ +model TurnStartPayload { + @doc("Name of the loaded prompt/agent, when available") + @sample(#{ agent: "weather-agent" }) + agent?: string; + + @doc("Input values supplied to the turn after host-side sanitization") + inputs?: Record; + + @doc("Configured maximum tool-call iterations") + @sample(#{ maxIterations: 10 }) + maxIterations?: int32; +} + +/** + * Payload for "turn_end" events — a turn has completed. + */ +model TurnEndPayload { + @doc("Number of tool-call iterations performed") + @sample(#{ iterations: 2 }) + iterations?: int32; + + @doc("Final semantic status of the turn") + status?: TurnStatus; + + @doc("Final response after processing, if available") + response?: unknown; + + @doc("Total elapsed turn duration in milliseconds") + @sample(#{ durationMs: 1500 }) + durationMs?: float64; +} + +/** + * Payload for "llm_start" events — an LLM request is about to be sent. + */ +model LlmStartPayload { + @doc("Provider identifier used for the request") + @sample(#{ provider: "openai" }) + provider?: string; + + @doc("Model or deployment identifier used for the request") + @sample(#{ modelId: "gpt-4o-mini" }) + modelId?: string; + + @doc("Number of messages sent to the provider") + @sample(#{ messageCount: 4 }) + messageCount?: int32; + + @doc("Retry attempt number, zero for the initial attempt") + @sample(#{ attempt: 0 }) + attempt?: int32; +} + +/** + * Payload for "llm_complete" events — an LLM request completed. + */ +model LlmCompletePayload { + @doc("Provider request identifier, when supplied by the SDK/API") + @sample(#{ requestId: "req_abc123" }) + requestId?: string; + + @doc("Service request identifier, when supplied by the SDK/API") + @sample(#{ serviceRequestId: "srv_abc123" }) + serviceRequestId?: string; + + @doc("Token usage reported by the provider") + usage?: TokenUsage; + + @doc("LLM call duration in milliseconds") + @sample(#{ durationMs: 820 }) + durationMs?: float64; +} + +/** + * Payload for "retry" events — a transient operation will be retried. + */ +model RetryPayload { + @doc("Operation being retried") + @sample(#{ operation: "llm" }) + operation: string; + + @doc("Attempt number about to run") + @sample(#{ attempt: 2 }) + attempt: int32; + + @doc("Maximum configured attempts") + @sample(#{ maxAttempts: 3 }) + maxAttempts?: int32; + + @doc("Backoff delay before the next attempt in milliseconds") + @sample(#{ delayMs: 1250 }) + delayMs?: float64; + + @doc("Reason for the retry") + @sample(#{ reason: "rate_limit" }) + reason?: string; +} + +/** + * Payload for permission request events — a host is asked to approve an action. + */ +model PermissionRequestedPayload { + @doc("Permission/action name being requested") + @sample(#{ permission: "tool.execute" }) + permission: string; + + @doc("Resource or tool the permission applies to") + @sample(#{ target: "shell" }) + target?: string; + + @doc("Additional host-specific permission details") + details?: Record; +} + +/** + * Payload for permission completion events — an approval decision was made. + */ +model PermissionCompletedPayload { + @doc("Permission/action name that was decided") + @sample(#{ permission: "tool.execute" }) + permission: string; + + @doc("Whether the requested permission was approved") + @sample(#{ approved: true }) + approved: boolean; + + @doc("Decision reason, if available") + @sample(#{ reason: "user_approved" }) + reason?: string; +} + /** * Payload for "token" events — a single text token streamed from the LLM. */ @@ -45,6 +230,10 @@ model ThinkingEventPayload { * Payload for "tool_call_start" events — the LLM has requested a tool call. */ model ToolCallStartPayload { + @doc("The unique identifier of the tool call") + @sample(#{ id: "call_abc123" }) + id?: string; + @doc("The name of the tool being called") @sample(#{ name: "get_weather" }) name: string; @@ -54,6 +243,34 @@ model ToolCallStartPayload { arguments: string; } +/** + * Payload for "tool_call_complete" events — a tool dispatch finished. + */ +model ToolCallCompletePayload { + @doc("The unique identifier of the tool call") + @sample(#{ id: "call_abc123" }) + id?: string; + + @doc("The name of the tool that completed") + @sample(#{ name: "get_weather" }) + name: string; + + @doc("Whether the tool dispatch succeeded semantically") + @sample(#{ success: true }) + success: boolean; + + @doc("Normalized tool result") + result?: ToolResult; + + @doc("Tool execution duration in milliseconds") + @sample(#{ durationMs: 42 }) + durationMs?: float64; + + @doc("Machine-readable error category when success is false") + @sample(#{ errorKind: "timeout" }) + errorKind?: string; +} + /** * Payload for "tool_result" events — a tool has returned its result. */ @@ -83,16 +300,26 @@ model StatusEventPayload { */ model MessagesUpdatedPayload { @doc("The current full message list after the update") - messages: Message[]; + messages?: Message[]; + + @doc("Why the message list changed") + @sample(#{ reason: "tool_results" }) + reason?: string; + + @doc("Messages appended by this update, when available") + appended?: Message[]; + + @doc("Number of messages removed by this update, when available") + @sample(#{ removed: 2 }) + removed?: int32; } /** * Payload for "done" events — the agent loop completed successfully. */ model DoneEventPayload { - @doc("The final text response from the LLM") - @sample(#{ response: "The weather in Paris is 72°F and sunny." }) - response: string; + @doc("The final response from the LLM after processing") + response: unknown; @doc("The final conversation state including all messages") messages: Message[]; @@ -105,6 +332,23 @@ model ErrorEventPayload { @doc("Human-readable error description") @sample(#{ message: "Rate limit exceeded" }) message: string; + + @doc("Stable machine-readable error category") + @sample(#{ errorKind: "rate_limit" }) + errorKind?: string; + + @doc("Operation or phase where the error occurred") + @sample(#{ phase: "llm" }) + phase?: string; +} + +/** + * Payload for "compaction_start" events — context compaction is beginning. + */ +model CompactionStartPayload { + @doc("Number of messages selected for compaction") + @sample(#{ droppedCount: 5 }) + droppedCount: int32; } /** @@ -118,6 +362,10 @@ model CompactionCompletePayload { @doc("Number of messages remaining after compaction") @sample(#{ remaining: 3 }) remaining: int32; + + @doc("Length of the generated summary, when a summarization strategy is used") + @sample(#{ summaryLength: 1200 }) + summaryLength?: int32; } /** @@ -128,3 +376,62 @@ model CompactionFailedPayload { @sample(#{ message: "Summarization prompt exceeded context window" }) message: string; } + +/** + * Summary statistics for a completed turn trace. + */ +model TurnSummary { + @doc("Stable identifier for the outer turn") + @sample(#{ turnId: "turn_001" }) + turnId: string; + + @doc("Final turn status: 'success', 'error', or 'cancelled'") + @sample(#{ status: "success" }) + status: string; + + @doc("Number of agent-loop iterations") + @sample(#{ iterations: 2 }) + iterations: int32; + + @doc("Number of LLM calls made during the turn") + @sample(#{ llmCalls: 3 }) + llmCalls?: int32; + + @doc("Number of tool calls dispatched during the turn") + @sample(#{ toolCalls: 2 }) + toolCalls?: int32; + + @doc("Number of retry events during the turn") + @sample(#{ retries: 1 }) + retries?: int32; + + @doc("Aggregated token usage for the turn") + usage?: TokenUsage; + + @doc("Total elapsed turn duration in milliseconds") + @sample(#{ durationMs: 2500 }) + durationMs?: float64; +} + +/** + * Portable JSONL/replay container for a recorded turn harness run. + */ +model TurnTrace { + @doc("Trace schema version") + @sample(#{ version: "1" }) + version: string = "1"; + + @doc("Runtime name that produced the trace") + @sample(#{ runtime: "typescript" }) + runtime?: string; + + @doc("Prompty library version that produced the trace") + @sample(#{ promptyVersion: "2.0.0" }) + promptyVersion?: string; + + @doc("Recorded turn events in emission order") + events: TurnEvent[]; + + @doc("Optional summary computed from the event stream") + summary?: TurnSummary; +} diff --git a/vscode/prompty/schemas/CompactionCompletePayload.yaml b/vscode/prompty/schemas/CompactionCompletePayload.yaml index cdf0551f..0e1ecded 100644 --- a/vscode/prompty/schemas/CompactionCompletePayload.yaml +++ b/vscode/prompty/schemas/CompactionCompletePayload.yaml @@ -12,6 +12,11 @@ properties: minimum: -2147483648 maximum: 2147483647 description: Number of messages remaining after compaction + summaryLength: + type: integer + minimum: -2147483648 + maximum: 2147483647 + description: Length of the generated summary, when a summarization strategy is used required: - removed - remaining diff --git a/vscode/prompty/schemas/CompactionStartPayload.yaml b/vscode/prompty/schemas/CompactionStartPayload.yaml new file mode 100644 index 00000000..124f3c52 --- /dev/null +++ b/vscode/prompty/schemas/CompactionStartPayload.yaml @@ -0,0 +1,12 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: CompactionStartPayload.yaml +type: object +properties: + droppedCount: + type: integer + minimum: -2147483648 + maximum: 2147483647 + description: Number of messages selected for compaction +required: + - droppedCount +description: Payload for "compaction_start" events — context compaction is beginning. diff --git a/vscode/prompty/schemas/DoneEventPayload.yaml b/vscode/prompty/schemas/DoneEventPayload.yaml index e5275ae2..eaed7bb4 100644 --- a/vscode/prompty/schemas/DoneEventPayload.yaml +++ b/vscode/prompty/schemas/DoneEventPayload.yaml @@ -3,8 +3,7 @@ $id: DoneEventPayload.yaml type: object properties: response: - type: string - description: The final text response from the LLM + description: The final response from the LLM after processing messages: type: array items: diff --git a/vscode/prompty/schemas/ErrorEventPayload.yaml b/vscode/prompty/schemas/ErrorEventPayload.yaml index dd95d5d5..42538f12 100644 --- a/vscode/prompty/schemas/ErrorEventPayload.yaml +++ b/vscode/prompty/schemas/ErrorEventPayload.yaml @@ -5,6 +5,12 @@ properties: message: type: string description: Human-readable error description + errorKind: + type: string + description: Stable machine-readable error category + phase: + type: string + description: Operation or phase where the error occurred required: - message description: Payload for "error" events — an error occurred during the loop. diff --git a/vscode/prompty/schemas/LlmCompletePayload.yaml b/vscode/prompty/schemas/LlmCompletePayload.yaml new file mode 100644 index 00000000..b586f2ec --- /dev/null +++ b/vscode/prompty/schemas/LlmCompletePayload.yaml @@ -0,0 +1,17 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: LlmCompletePayload.yaml +type: object +properties: + requestId: + type: string + description: Provider request identifier, when supplied by the SDK/API + serviceRequestId: + type: string + description: Service request identifier, when supplied by the SDK/API + usage: + $ref: TokenUsage.yaml + description: Token usage reported by the provider + durationMs: + type: number + description: LLM call duration in milliseconds +description: Payload for "llm_complete" events — an LLM request completed. diff --git a/vscode/prompty/schemas/LlmStartPayload.yaml b/vscode/prompty/schemas/LlmStartPayload.yaml new file mode 100644 index 00000000..4f6adb80 --- /dev/null +++ b/vscode/prompty/schemas/LlmStartPayload.yaml @@ -0,0 +1,21 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: LlmStartPayload.yaml +type: object +properties: + provider: + type: string + description: Provider identifier used for the request + modelId: + type: string + description: Model or deployment identifier used for the request + messageCount: + type: integer + minimum: -2147483648 + maximum: 2147483647 + description: Number of messages sent to the provider + attempt: + type: integer + minimum: -2147483648 + maximum: 2147483647 + description: Retry attempt number, zero for the initial attempt +description: Payload for "llm_start" events — an LLM request is about to be sent. diff --git a/vscode/prompty/schemas/MessagesUpdatedPayload.yaml b/vscode/prompty/schemas/MessagesUpdatedPayload.yaml index ba647364..450f5748 100644 --- a/vscode/prompty/schemas/MessagesUpdatedPayload.yaml +++ b/vscode/prompty/schemas/MessagesUpdatedPayload.yaml @@ -7,6 +7,17 @@ properties: items: $ref: Message.yaml description: The current full message list after the update -required: - - messages + reason: + type: string + description: Why the message list changed + appended: + type: array + items: + $ref: Message.yaml + description: Messages appended by this update, when available + removed: + type: integer + minimum: -2147483648 + maximum: 2147483647 + description: Number of messages removed by this update, when available description: Payload for "messages_updated" events — the conversation state has changed. diff --git a/vscode/prompty/schemas/PermissionCompletedPayload.yaml b/vscode/prompty/schemas/PermissionCompletedPayload.yaml new file mode 100644 index 00000000..569c70e8 --- /dev/null +++ b/vscode/prompty/schemas/PermissionCompletedPayload.yaml @@ -0,0 +1,17 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: PermissionCompletedPayload.yaml +type: object +properties: + permission: + type: string + description: Permission/action name that was decided + approved: + type: boolean + description: Whether the requested permission was approved + reason: + type: string + description: Decision reason, if available +required: + - permission + - approved +description: Payload for permission completion events — an approval decision was made. diff --git a/vscode/prompty/schemas/PermissionRequestedPayload.yaml b/vscode/prompty/schemas/PermissionRequestedPayload.yaml new file mode 100644 index 00000000..b29983af --- /dev/null +++ b/vscode/prompty/schemas/PermissionRequestedPayload.yaml @@ -0,0 +1,16 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: PermissionRequestedPayload.yaml +type: object +properties: + permission: + type: string + description: Permission/action name being requested + target: + type: string + description: Resource or tool the permission applies to + details: + $ref: RecordUnknown.yaml + description: Additional host-specific permission details +required: + - permission +description: Payload for permission request events — a host is asked to approve an action. diff --git a/vscode/prompty/schemas/Prompty.yaml b/vscode/prompty/schemas/Prompty.yaml index 9cc19515..b5801063 100644 --- a/vscode/prompty/schemas/Prompty.yaml +++ b/vscode/prompty/schemas/Prompty.yaml @@ -196,4 +196,10 @@ description: |- This is the single root type for the Prompty schema — there is no abstract base class or kind discriminator. A .prompty file always produces a Prompty instance. + + Runtime loaders may resolve frontmatter references such as `${env:VAR}` and + `${file:relative/path}`. File references must be treated as a host-controlled + capability: by default they are scoped to the containing .prompty file's + directory tree after canonicalization, and any additional allowed roots must + be supplied by the host application's load options rather than frontmatter. additionalProperties: false diff --git a/vscode/prompty/schemas/RetryPayload.yaml b/vscode/prompty/schemas/RetryPayload.yaml new file mode 100644 index 00000000..edc88627 --- /dev/null +++ b/vscode/prompty/schemas/RetryPayload.yaml @@ -0,0 +1,27 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: RetryPayload.yaml +type: object +properties: + operation: + type: string + description: Operation being retried + attempt: + type: integer + minimum: -2147483648 + maximum: 2147483647 + description: Attempt number about to run + maxAttempts: + type: integer + minimum: -2147483648 + maximum: 2147483647 + description: Maximum configured attempts + delayMs: + type: number + description: Backoff delay before the next attempt in milliseconds + reason: + type: string + description: Reason for the retry +required: + - operation + - attempt +description: Payload for "retry" events — a transient operation will be retried. diff --git a/vscode/prompty/schemas/ToolCallCompletePayload.yaml b/vscode/prompty/schemas/ToolCallCompletePayload.yaml new file mode 100644 index 00000000..cb1e9903 --- /dev/null +++ b/vscode/prompty/schemas/ToolCallCompletePayload.yaml @@ -0,0 +1,26 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: ToolCallCompletePayload.yaml +type: object +properties: + id: + type: string + description: The unique identifier of the tool call + name: + type: string + description: The name of the tool that completed + success: + type: boolean + description: Whether the tool dispatch succeeded semantically + result: + $ref: ToolResult.yaml + description: Normalized tool result + durationMs: + type: number + description: Tool execution duration in milliseconds + errorKind: + type: string + description: Machine-readable error category when success is false +required: + - name + - success +description: Payload for "tool_call_complete" events — a tool dispatch finished. diff --git a/vscode/prompty/schemas/ToolCallStartPayload.yaml b/vscode/prompty/schemas/ToolCallStartPayload.yaml index d41ce044..0ce05515 100644 --- a/vscode/prompty/schemas/ToolCallStartPayload.yaml +++ b/vscode/prompty/schemas/ToolCallStartPayload.yaml @@ -2,6 +2,9 @@ $schema: https://json-schema.org/draft/2020-12/schema $id: ToolCallStartPayload.yaml type: object properties: + id: + type: string + description: The unique identifier of the tool call name: type: string description: The name of the tool being called diff --git a/vscode/prompty/schemas/ToolResult.yaml b/vscode/prompty/schemas/ToolResult.yaml index a4f3a2db..195e080d 100644 --- a/vscode/prompty/schemas/ToolResult.yaml +++ b/vscode/prompty/schemas/ToolResult.yaml @@ -7,6 +7,26 @@ properties: items: $ref: ContentPart.yaml description: The content parts of the tool result + status: + anyOf: + - type: string + const: success + - type: string + const: error + - type: string + const: cancelled + - type: string + const: timeout + description: Semantic execution status for the tool result + errorKind: + type: string + description: Stable machine-readable error category when status is not success + errorMessage: + type: string + description: Human-readable error message when status is not success + durationMs: + type: number + description: Tool execution duration in milliseconds required: - parts description: |- diff --git a/vscode/prompty/schemas/TurnEndPayload.yaml b/vscode/prompty/schemas/TurnEndPayload.yaml new file mode 100644 index 00000000..f9cb2c1a --- /dev/null +++ b/vscode/prompty/schemas/TurnEndPayload.yaml @@ -0,0 +1,24 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: TurnEndPayload.yaml +type: object +properties: + iterations: + type: integer + minimum: -2147483648 + maximum: 2147483647 + description: Number of tool-call iterations performed + status: + anyOf: + - type: string + const: success + - type: string + const: error + - type: string + const: cancelled + description: Final semantic status of the turn + response: + description: Final response after processing, if available + durationMs: + type: number + description: Total elapsed turn duration in milliseconds +description: Payload for "turn_end" events — a turn has completed. diff --git a/vscode/prompty/schemas/TurnEvent.yaml b/vscode/prompty/schemas/TurnEvent.yaml new file mode 100644 index 00000000..336ca438 --- /dev/null +++ b/vscode/prompty/schemas/TurnEvent.yaml @@ -0,0 +1,80 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: TurnEvent.yaml +type: object +properties: + id: + type: string + description: Unique identifier for this event + type: + anyOf: + - type: string + const: turn_start + - type: string + const: turn_end + - type: string + const: llm_start + - type: string + const: llm_complete + - type: string + const: retry + - type: string + const: permission_requested + - type: string + const: permission_completed + - type: string + const: token + - type: string + const: thinking + - type: string + const: tool_call_start + - type: string + const: tool_call_complete + - type: string + const: tool_result + - type: string + const: status + - type: string + const: messages_updated + - type: string + const: done + - type: string + const: error + - type: string + const: cancelled + - type: string + const: compaction_start + - type: string + const: compaction_complete + - type: string + const: compaction_failed + description: Event type discriminator + timestamp: + type: string + description: ISO 8601 UTC timestamp when the event was emitted + turnId: + type: string + description: Stable identifier for the outer turn + iteration: + type: integer + minimum: -2147483648 + maximum: 2147483647 + description: Zero-based agent-loop iteration associated with the event + parentId: + type: string + description: Parent event or span identifier for reconstructing event hierarchy + spanId: + type: string + description: Trace span identifier associated with this event + payload: + $ref: RecordUnknown.yaml + default: {} + description: Event-specific payload. Use the typed payload model matching 'type'. +required: + - id + - type + - timestamp + - payload +description: |- + A canonical event envelope emitted by the turn harness. The payload is kept + JSON-shaped so runtimes can load all events even when newer payload types are + added; event-specific typed payload models below define the canonical shapes. diff --git a/vscode/prompty/schemas/TurnStartPayload.yaml b/vscode/prompty/schemas/TurnStartPayload.yaml new file mode 100644 index 00000000..de6c6393 --- /dev/null +++ b/vscode/prompty/schemas/TurnStartPayload.yaml @@ -0,0 +1,16 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: TurnStartPayload.yaml +type: object +properties: + agent: + type: string + description: Name of the loaded prompt/agent, when available + inputs: + $ref: RecordUnknown.yaml + description: Input values supplied to the turn after host-side sanitization + maxIterations: + type: integer + minimum: -2147483648 + maximum: 2147483647 + description: Configured maximum tool-call iterations +description: Payload for "turn_start" events — a turn is beginning. diff --git a/vscode/prompty/schemas/TurnSummary.yaml b/vscode/prompty/schemas/TurnSummary.yaml new file mode 100644 index 00000000..ed3ff3b9 --- /dev/null +++ b/vscode/prompty/schemas/TurnSummary.yaml @@ -0,0 +1,41 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: TurnSummary.yaml +type: object +properties: + turnId: + type: string + description: Stable identifier for the outer turn + status: + type: string + description: "Final turn status: 'success', 'error', or 'cancelled'" + iterations: + type: integer + minimum: -2147483648 + maximum: 2147483647 + description: Number of agent-loop iterations + llmCalls: + type: integer + minimum: -2147483648 + maximum: 2147483647 + description: Number of LLM calls made during the turn + toolCalls: + type: integer + minimum: -2147483648 + maximum: 2147483647 + description: Number of tool calls dispatched during the turn + retries: + type: integer + minimum: -2147483648 + maximum: 2147483647 + description: Number of retry events during the turn + usage: + $ref: TokenUsage.yaml + description: Aggregated token usage for the turn + durationMs: + type: number + description: Total elapsed turn duration in milliseconds +required: + - turnId + - status + - iterations +description: Summary statistics for a completed turn trace. diff --git a/vscode/prompty/schemas/TurnTrace.yaml b/vscode/prompty/schemas/TurnTrace.yaml new file mode 100644 index 00000000..baeb5bef --- /dev/null +++ b/vscode/prompty/schemas/TurnTrace.yaml @@ -0,0 +1,26 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: TurnTrace.yaml +type: object +properties: + version: + type: string + default: "1" + description: Trace schema version + runtime: + type: string + description: Runtime name that produced the trace + promptyVersion: + type: string + description: Prompty library version that produced the trace + events: + type: array + items: + $ref: TurnEvent.yaml + description: Recorded turn events in emission order + summary: + $ref: TurnSummary.yaml + description: Optional summary computed from the event stream +required: + - version + - events +description: Portable JSONL/replay container for a recorded turn harness run. diff --git a/web/src/content/docs/reference/CompactionCompletePayload.md b/web/src/content/docs/reference/CompactionCompletePayload.md index a7b1a961..630fc012 100644 --- a/web/src/content/docs/reference/CompactionCompletePayload.md +++ b/web/src/content/docs/reference/CompactionCompletePayload.md @@ -21,6 +21,7 @@ classDiagram class CompactionCompletePayload { +int32 removed +int32 remaining + +int32 summaryLength } ``` @@ -29,6 +30,7 @@ classDiagram ```yaml removed: 5 remaining: 3 +summaryLength: 1200 ``` ## Properties @@ -37,3 +39,4 @@ remaining: 3 | ---- | ---- | ----------- | | removed | int32 | Number of messages removed during compaction | | remaining | int32 | Number of messages remaining after compaction | +| summaryLength | int32 | Length of the generated summary, when a summarization strategy is used | diff --git a/web/src/content/docs/reference/CompactionStartPayload.md b/web/src/content/docs/reference/CompactionStartPayload.md new file mode 100644 index 00000000..3d49c1d8 --- /dev/null +++ b/web/src/content/docs/reference/CompactionStartPayload.md @@ -0,0 +1,36 @@ +--- +title: "CompactionStartPayload" +description: "Documentation for the CompactionStartPayload type." +slug: "reference/compactionstartpayload" +--- + +Payload for "compaction_start" events — context compaction is beginning. + +## Class Diagram + +```mermaid +--- +title: CompactionStartPayload +config: + look: handDrawn + theme: colorful + class: + hideEmptyMembersBox: true +--- +classDiagram + class CompactionStartPayload { + +int32 droppedCount + } +``` + +## Yaml Example + +```yaml +droppedCount: 5 +``` + +## Properties + +| Name | Type | Description | +| ---- | ---- | ----------- | +| droppedCount | int32 | Number of messages selected for compaction | diff --git a/web/src/content/docs/reference/DoneEventPayload.md b/web/src/content/docs/reference/DoneEventPayload.md index 5c6f6fa8..5a426ec5 100644 --- a/web/src/content/docs/reference/DoneEventPayload.md +++ b/web/src/content/docs/reference/DoneEventPayload.md @@ -19,7 +19,7 @@ config: --- classDiagram class DoneEventPayload { - +string response + +unknown response +Message[] messages } class Message { @@ -32,17 +32,11 @@ classDiagram DoneEventPayload *-- Message ``` -## Yaml Example - -```yaml -response: The weather in Paris is 72°F and sunny. -``` - ## Properties | Name | Type | Description | | ---- | ---- | ----------- | -| response | string | The final text response from the LLM | +| response | unknown | The final response from the LLM after processing | | messages | [Message[]](../message/) | The final conversation state including all messages | ## Composed Types diff --git a/web/src/content/docs/reference/ErrorEventPayload.md b/web/src/content/docs/reference/ErrorEventPayload.md index a25b9dde..8784a307 100644 --- a/web/src/content/docs/reference/ErrorEventPayload.md +++ b/web/src/content/docs/reference/ErrorEventPayload.md @@ -20,6 +20,8 @@ config: classDiagram class ErrorEventPayload { +string message + +string errorKind + +string phase } ``` @@ -27,6 +29,8 @@ classDiagram ```yaml message: Rate limit exceeded +errorKind: rate_limit +phase: llm ``` ## Properties @@ -34,3 +38,5 @@ message: Rate limit exceeded | Name | Type | Description | | ---- | ---- | ----------- | | message | string | Human-readable error description | +| errorKind | string | Stable machine-readable error category | +| phase | string | Operation or phase where the error occurred | diff --git a/web/src/content/docs/reference/LlmCompletePayload.md b/web/src/content/docs/reference/LlmCompletePayload.md new file mode 100644 index 00000000..c64d0c9a --- /dev/null +++ b/web/src/content/docs/reference/LlmCompletePayload.md @@ -0,0 +1,56 @@ +--- +title: "LlmCompletePayload" +description: "Documentation for the LlmCompletePayload type." +slug: "reference/llmcompletepayload" +--- + +Payload for "llm_complete" events — an LLM request completed. + +## Class Diagram + +```mermaid +--- +title: LlmCompletePayload +config: + look: handDrawn + theme: colorful + class: + hideEmptyMembersBox: true +--- +classDiagram + class LlmCompletePayload { + +string requestId + +string serviceRequestId + +TokenUsage usage + +float64 durationMs + } + class TokenUsage { + +int32 promptTokens + +int32 completionTokens + +int32 totalTokens + } + LlmCompletePayload *-- TokenUsage +``` + +## Yaml Example + +```yaml +requestId: req_abc123 +serviceRequestId: srv_abc123 +durationMs: 820 +``` + +## Properties + +| Name | Type | Description | +| ---- | ---- | ----------- | +| requestId | string | Provider request identifier, when supplied by the SDK/API | +| serviceRequestId | string | Service request identifier, when supplied by the SDK/API | +| usage | [TokenUsage](../tokenusage/) | Token usage reported by the provider | +| durationMs | float64 | LLM call duration in milliseconds | + +## Composed Types + +The following types are composed within `LlmCompletePayload`: + +- [TokenUsage](../tokenusage/) diff --git a/web/src/content/docs/reference/LlmStartPayload.md b/web/src/content/docs/reference/LlmStartPayload.md new file mode 100644 index 00000000..c30ab423 --- /dev/null +++ b/web/src/content/docs/reference/LlmStartPayload.md @@ -0,0 +1,45 @@ +--- +title: "LlmStartPayload" +description: "Documentation for the LlmStartPayload type." +slug: "reference/llmstartpayload" +--- + +Payload for "llm_start" events — an LLM request is about to be sent. + +## Class Diagram + +```mermaid +--- +title: LlmStartPayload +config: + look: handDrawn + theme: colorful + class: + hideEmptyMembersBox: true +--- +classDiagram + class LlmStartPayload { + +string provider + +string modelId + +int32 messageCount + +int32 attempt + } +``` + +## Yaml Example + +```yaml +provider: openai +modelId: gpt-4o-mini +messageCount: 4 +attempt: 0 +``` + +## Properties + +| Name | Type | Description | +| ---- | ---- | ----------- | +| provider | string | Provider identifier used for the request | +| modelId | string | Model or deployment identifier used for the request | +| messageCount | int32 | Number of messages sent to the provider | +| attempt | int32 | Retry attempt number, zero for the initial attempt | diff --git a/web/src/content/docs/reference/MessagesUpdatedPayload.md b/web/src/content/docs/reference/MessagesUpdatedPayload.md index 7da2b2e7..00d6c458 100644 --- a/web/src/content/docs/reference/MessagesUpdatedPayload.md +++ b/web/src/content/docs/reference/MessagesUpdatedPayload.md @@ -20,6 +20,9 @@ config: classDiagram class MessagesUpdatedPayload { +Message[] messages + +string reason + +Message[] appended + +int32 removed } class Message { +string role @@ -29,6 +32,21 @@ classDiagram +text() string [async-capable] } MessagesUpdatedPayload *-- Message + class Message { + +string role + +ContentPart[] parts + +dictionary metadata + +toTextContent() unknown [async-capable] + +text() string [async-capable] + } + MessagesUpdatedPayload *-- Message +``` + +## Yaml Example + +```yaml +reason: tool_results +removed: 2 ``` ## Properties @@ -36,9 +54,13 @@ classDiagram | Name | Type | Description | | ---- | ---- | ----------- | | messages | [Message[]](../message/) | The current full message list after the update | +| reason | string | Why the message list changed | +| appended | [Message[]](../message/) | Messages appended by this update, when available | +| removed | int32 | Number of messages removed by this update, when available | ## Composed Types The following types are composed within `MessagesUpdatedPayload`: - [Message](../message/) +- [Message](../message/) diff --git a/web/src/content/docs/reference/PermissionCompletedPayload.md b/web/src/content/docs/reference/PermissionCompletedPayload.md new file mode 100644 index 00000000..16eaeffb --- /dev/null +++ b/web/src/content/docs/reference/PermissionCompletedPayload.md @@ -0,0 +1,42 @@ +--- +title: "PermissionCompletedPayload" +description: "Documentation for the PermissionCompletedPayload type." +slug: "reference/permissioncompletedpayload" +--- + +Payload for permission completion events — an approval decision was made. + +## Class Diagram + +```mermaid +--- +title: PermissionCompletedPayload +config: + look: handDrawn + theme: colorful + class: + hideEmptyMembersBox: true +--- +classDiagram + class PermissionCompletedPayload { + +string permission + +boolean approved + +string reason + } +``` + +## Yaml Example + +```yaml +permission: tool.execute +approved: true +reason: user_approved +``` + +## Properties + +| Name | Type | Description | +| ---- | ---- | ----------- | +| permission | string | Permission/action name that was decided | +| approved | boolean | Whether the requested permission was approved | +| reason | string | Decision reason, if available | diff --git a/web/src/content/docs/reference/PermissionRequestedPayload.md b/web/src/content/docs/reference/PermissionRequestedPayload.md new file mode 100644 index 00000000..a5832895 --- /dev/null +++ b/web/src/content/docs/reference/PermissionRequestedPayload.md @@ -0,0 +1,41 @@ +--- +title: "PermissionRequestedPayload" +description: "Documentation for the PermissionRequestedPayload type." +slug: "reference/permissionrequestedpayload" +--- + +Payload for permission request events — a host is asked to approve an action. + +## Class Diagram + +```mermaid +--- +title: PermissionRequestedPayload +config: + look: handDrawn + theme: colorful + class: + hideEmptyMembersBox: true +--- +classDiagram + class PermissionRequestedPayload { + +string permission + +string target + +dictionary details + } +``` + +## Yaml Example + +```yaml +permission: tool.execute +target: shell +``` + +## Properties + +| Name | Type | Description | +| ---- | ---- | ----------- | +| permission | string | Permission/action name being requested | +| target | string | Resource or tool the permission applies to | +| details | dictionary | Additional host-specific permission details | diff --git a/web/src/content/docs/reference/Prompty.md b/web/src/content/docs/reference/Prompty.md index 0bc439cb..409c9bd6 100644 --- a/web/src/content/docs/reference/Prompty.md +++ b/web/src/content/docs/reference/Prompty.md @@ -11,6 +11,12 @@ and template settings. The markdown body becomes the instructions. This is the single root type for the Prompty schema — there is no abstract base class or kind discriminator. A .prompty file always produces a Prompty instance. +Runtime loaders may resolve frontmatter references such as `${env:VAR}` and +`${file:relative/path}`. File references must be treated as a host-controlled +capability: by default they are scoped to the containing .prompty file's +directory tree after canonicalization, and any additional allowed roots must +be supplied by the host application's load options rather than frontmatter. + ## Class Diagram ```mermaid diff --git a/web/src/content/docs/reference/RetryPayload.md b/web/src/content/docs/reference/RetryPayload.md new file mode 100644 index 00000000..7ee2d488 --- /dev/null +++ b/web/src/content/docs/reference/RetryPayload.md @@ -0,0 +1,48 @@ +--- +title: "RetryPayload" +description: "Documentation for the RetryPayload type." +slug: "reference/retrypayload" +--- + +Payload for "retry" events — a transient operation will be retried. + +## Class Diagram + +```mermaid +--- +title: RetryPayload +config: + look: handDrawn + theme: colorful + class: + hideEmptyMembersBox: true +--- +classDiagram + class RetryPayload { + +string operation + +int32 attempt + +int32 maxAttempts + +float64 delayMs + +string reason + } +``` + +## Yaml Example + +```yaml +operation: llm +attempt: 2 +maxAttempts: 3 +delayMs: 1250 +reason: rate_limit +``` + +## Properties + +| Name | Type | Description | +| ---- | ---- | ----------- | +| operation | string | Operation being retried | +| attempt | int32 | Attempt number about to run | +| maxAttempts | int32 | Maximum configured attempts | +| delayMs | float64 | Backoff delay before the next attempt in milliseconds | +| reason | string | Reason for the retry | diff --git a/web/src/content/docs/reference/ToolCallCompletePayload.md b/web/src/content/docs/reference/ToolCallCompletePayload.md new file mode 100644 index 00000000..f4651659 --- /dev/null +++ b/web/src/content/docs/reference/ToolCallCompletePayload.md @@ -0,0 +1,65 @@ +--- +title: "ToolCallCompletePayload" +description: "Documentation for the ToolCallCompletePayload type." +slug: "reference/toolcallcompletepayload" +--- + +Payload for "tool_call_complete" events — a tool dispatch finished. + +## Class Diagram + +```mermaid +--- +title: ToolCallCompletePayload +config: + look: handDrawn + theme: colorful + class: + hideEmptyMembersBox: true +--- +classDiagram + class ToolCallCompletePayload { + +string id + +string name + +boolean success + +ToolResult result + +float64 durationMs + +string errorKind + } + class ToolResult { + +ContentPart[] parts + +string status + +string errorKind + +string errorMessage + +float64 durationMs + +text() string [async-capable] + } + ToolCallCompletePayload *-- ToolResult +``` + +## Yaml Example + +```yaml +id: call_abc123 +name: get_weather +success: true +durationMs: 42 +errorKind: timeout +``` + +## Properties + +| Name | Type | Description | +| ---- | ---- | ----------- | +| id | string | The unique identifier of the tool call | +| name | string | The name of the tool that completed | +| success | boolean | Whether the tool dispatch succeeded semantically | +| result | [ToolResult](../toolresult/) | Normalized tool result | +| durationMs | float64 | Tool execution duration in milliseconds | +| errorKind | string | Machine-readable error category when success is false | + +## Composed Types + +The following types are composed within `ToolCallCompletePayload`: + +- [ToolResult](../toolresult/) diff --git a/web/src/content/docs/reference/ToolCallStartPayload.md b/web/src/content/docs/reference/ToolCallStartPayload.md index f98a3e6f..c0b4920a 100644 --- a/web/src/content/docs/reference/ToolCallStartPayload.md +++ b/web/src/content/docs/reference/ToolCallStartPayload.md @@ -19,6 +19,7 @@ config: --- classDiagram class ToolCallStartPayload { + +string id +string name +string arguments } @@ -27,6 +28,7 @@ classDiagram ## Yaml Example ```yaml +id: call_abc123 name: get_weather arguments: '{"city": "Paris"}' ``` @@ -35,5 +37,6 @@ arguments: '{"city": "Paris"}' | Name | Type | Description | | ---- | ---- | ----------- | +| id | string | The unique identifier of the tool call | | name | string | The name of the tool being called | | arguments | string | The serialized JSON arguments for the tool call | diff --git a/web/src/content/docs/reference/ToolDispatchResult.md b/web/src/content/docs/reference/ToolDispatchResult.md index 7572475a..3e9a66bb 100644 --- a/web/src/content/docs/reference/ToolDispatchResult.md +++ b/web/src/content/docs/reference/ToolDispatchResult.md @@ -27,6 +27,10 @@ classDiagram } class ToolResult { +ContentPart[] parts + +string status + +string errorKind + +string errorMessage + +float64 durationMs +text() string [async-capable] } ToolDispatchResult *-- ToolResult diff --git a/web/src/content/docs/reference/ToolResult.md b/web/src/content/docs/reference/ToolResult.md index 7b0e07b1..e6717f78 100644 --- a/web/src/content/docs/reference/ToolResult.md +++ b/web/src/content/docs/reference/ToolResult.md @@ -24,6 +24,10 @@ config: classDiagram class ToolResult { +ContentPart[] parts + +string status + +string errorKind + +string errorMessage + +float64 durationMs +text() string [async-capable] } class ContentPart { @@ -39,6 +43,9 @@ classDiagram parts: - kind: text value: 72°F and sunny +errorKind: missing_tool +errorMessage: Tool 'get_weather' is not registered +durationMs: 42 ``` ## Properties @@ -46,6 +53,10 @@ parts: | Name | Type | Description | | ---- | ---- | ----------- | | parts | [ContentPart[]](../contentpart/) | The content parts of the tool result(Related Types: [TextPart](../textpart/), [ImagePart](../imagepart/), [FilePart](../filepart/), [AudioPart](../audiopart/)) | +| status | string | Semantic execution status for the tool result | +| errorKind | string | Stable machine-readable error category when status is not success | +| errorMessage | string | Human-readable error message when status is not success | +| durationMs | float64 | Tool execution duration in milliseconds | ## Helper Methods diff --git a/web/src/content/docs/reference/ToolResultPayload.md b/web/src/content/docs/reference/ToolResultPayload.md index a8585bfb..c1ba162f 100644 --- a/web/src/content/docs/reference/ToolResultPayload.md +++ b/web/src/content/docs/reference/ToolResultPayload.md @@ -24,6 +24,10 @@ classDiagram } class ToolResult { +ContentPart[] parts + +string status + +string errorKind + +string errorMessage + +float64 durationMs +text() string [async-capable] } ToolResultPayload *-- ToolResult diff --git a/web/src/content/docs/reference/TurnEndPayload.md b/web/src/content/docs/reference/TurnEndPayload.md new file mode 100644 index 00000000..ef3f6c83 --- /dev/null +++ b/web/src/content/docs/reference/TurnEndPayload.md @@ -0,0 +1,43 @@ +--- +title: "TurnEndPayload" +description: "Documentation for the TurnEndPayload type." +slug: "reference/turnendpayload" +--- + +Payload for "turn_end" events — a turn has completed. + +## Class Diagram + +```mermaid +--- +title: TurnEndPayload +config: + look: handDrawn + theme: colorful + class: + hideEmptyMembersBox: true +--- +classDiagram + class TurnEndPayload { + +int32 iterations + +string status + +unknown response + +float64 durationMs + } +``` + +## Yaml Example + +```yaml +iterations: 2 +durationMs: 1500 +``` + +## Properties + +| Name | Type | Description | +| ---- | ---- | ----------- | +| iterations | int32 | Number of tool-call iterations performed | +| status | string | Final semantic status of the turn | +| response | unknown | Final response after processing, if available | +| durationMs | float64 | Total elapsed turn duration in milliseconds | diff --git a/web/src/content/docs/reference/TurnEvent.md b/web/src/content/docs/reference/TurnEvent.md new file mode 100644 index 00000000..f0b1520d --- /dev/null +++ b/web/src/content/docs/reference/TurnEvent.md @@ -0,0 +1,57 @@ +--- +title: "TurnEvent" +description: "Documentation for the TurnEvent type." +slug: "reference/turnevent" +--- + +A canonical event envelope emitted by the turn harness. The payload is kept +JSON-shaped so runtimes can load all events even when newer payload types are +added; event-specific typed payload models below define the canonical shapes. + +## Class Diagram + +```mermaid +--- +title: TurnEvent +config: + look: handDrawn + theme: colorful + class: + hideEmptyMembersBox: true +--- +classDiagram + class TurnEvent { + +string id + +string type + +string timestamp + +string turnId + +int32 iteration + +string parentId + +string spanId + +dictionary payload + } +``` + +## Yaml Example + +```yaml +id: evt_abc123 +timestamp: 2026-06-09T20:00:00Z +turnId: turn_001 +iteration: 0 +parentId: evt_parent +spanId: span_tool_001 +``` + +## Properties + +| Name | Type | Description | +| ---- | ---- | ----------- | +| id | string | Unique identifier for this event | +| type | string | Event type discriminator | +| timestamp | string | ISO 8601 UTC timestamp when the event was emitted | +| turnId | string | Stable identifier for the outer turn | +| iteration | int32 | Zero-based agent-loop iteration associated with the event | +| parentId | string | Parent event or span identifier for reconstructing event hierarchy | +| spanId | string | Trace span identifier associated with this event | +| payload | dictionary | Event-specific payload. Use the typed payload model matching 'type'. | diff --git a/web/src/content/docs/reference/TurnStartPayload.md b/web/src/content/docs/reference/TurnStartPayload.md new file mode 100644 index 00000000..6f140bbf --- /dev/null +++ b/web/src/content/docs/reference/TurnStartPayload.md @@ -0,0 +1,41 @@ +--- +title: "TurnStartPayload" +description: "Documentation for the TurnStartPayload type." +slug: "reference/turnstartpayload" +--- + +Payload for "turn_start" events — a turn is beginning. + +## Class Diagram + +```mermaid +--- +title: TurnStartPayload +config: + look: handDrawn + theme: colorful + class: + hideEmptyMembersBox: true +--- +classDiagram + class TurnStartPayload { + +string agent + +dictionary inputs + +int32 maxIterations + } +``` + +## Yaml Example + +```yaml +agent: weather-agent +maxIterations: 10 +``` + +## Properties + +| Name | Type | Description | +| ---- | ---- | ----------- | +| agent | string | Name of the loaded prompt/agent, when available | +| inputs | dictionary | Input values supplied to the turn after host-side sanitization | +| maxIterations | int32 | Configured maximum tool-call iterations | diff --git a/web/src/content/docs/reference/TurnSummary.md b/web/src/content/docs/reference/TurnSummary.md new file mode 100644 index 00000000..b85e83e1 --- /dev/null +++ b/web/src/content/docs/reference/TurnSummary.md @@ -0,0 +1,68 @@ +--- +title: "TurnSummary" +description: "Documentation for the TurnSummary type." +slug: "reference/turnsummary" +--- + +Summary statistics for a completed turn trace. + +## Class Diagram + +```mermaid +--- +title: TurnSummary +config: + look: handDrawn + theme: colorful + class: + hideEmptyMembersBox: true +--- +classDiagram + class TurnSummary { + +string turnId + +string status + +int32 iterations + +int32 llmCalls + +int32 toolCalls + +int32 retries + +TokenUsage usage + +float64 durationMs + } + class TokenUsage { + +int32 promptTokens + +int32 completionTokens + +int32 totalTokens + } + TurnSummary *-- TokenUsage +``` + +## Yaml Example + +```yaml +turnId: turn_001 +status: success +iterations: 2 +llmCalls: 3 +toolCalls: 2 +retries: 1 +durationMs: 2500 +``` + +## Properties + +| Name | Type | Description | +| ---- | ---- | ----------- | +| turnId | string | Stable identifier for the outer turn | +| status | string | Final turn status: 'success', 'error', or 'cancelled' | +| iterations | int32 | Number of agent-loop iterations | +| llmCalls | int32 | Number of LLM calls made during the turn | +| toolCalls | int32 | Number of tool calls dispatched during the turn | +| retries | int32 | Number of retry events during the turn | +| usage | [TokenUsage](../tokenusage/) | Aggregated token usage for the turn | +| durationMs | float64 | Total elapsed turn duration in milliseconds | + +## Composed Types + +The following types are composed within `TurnSummary`: + +- [TokenUsage](../tokenusage/) diff --git a/web/src/content/docs/reference/TurnTrace.md b/web/src/content/docs/reference/TurnTrace.md new file mode 100644 index 00000000..87886e75 --- /dev/null +++ b/web/src/content/docs/reference/TurnTrace.md @@ -0,0 +1,75 @@ +--- +title: "TurnTrace" +description: "Documentation for the TurnTrace type." +slug: "reference/turntrace" +--- + +Portable JSONL/replay container for a recorded turn harness run. + +## Class Diagram + +```mermaid +--- +title: TurnTrace +config: + look: handDrawn + theme: colorful + class: + hideEmptyMembersBox: true +--- +classDiagram + class TurnTrace { + +string version + +string runtime + +string promptyVersion + +TurnEvent[] events + +TurnSummary summary + } + class TurnEvent { + +string id + +string type + +string timestamp + +string turnId + +int32 iteration + +string parentId + +string spanId + +dictionary payload + } + TurnTrace *-- TurnEvent + class TurnSummary { + +string turnId + +string status + +int32 iterations + +int32 llmCalls + +int32 toolCalls + +int32 retries + +TokenUsage usage + +float64 durationMs + } + TurnTrace *-- TurnSummary +``` + +## Yaml Example + +```yaml +version: "1" +runtime: typescript +promptyVersion: 2.0.0 +``` + +## Properties + +| Name | Type | Description | +| ---- | ---- | ----------- | +| version | string | Trace schema version | +| runtime | string | Runtime name that produced the trace | +| promptyVersion | string | Prompty library version that produced the trace | +| events | [TurnEvent[]](../turnevent/) | Recorded turn events in emission order | +| summary | [TurnSummary](../turnsummary/) | Optional summary computed from the event stream | + +## Composed Types + +The following types are composed within `TurnTrace`: + +- [TurnEvent](../turnevent/) +- [TurnSummary](../turnsummary/) diff --git a/web/src/content/docs/reference/index.md b/web/src/content/docs/reference/index.md index 47f974cd..ee145108 100644 --- a/web/src/content/docs/reference/index.md +++ b/web/src/content/docs/reference/index.md @@ -288,6 +288,10 @@ classDiagram } class ToolResult { +ContentPart[] parts + +string status + +string errorKind + +string errorMessage + +float64 durationMs +text() string [async-capable] } class ToolDispatchResult { @@ -370,6 +374,8 @@ classDiagram } class ErrorEventPayload { +string message + +string errorKind + +string phase } ``` @@ -378,6 +384,7 @@ classDiagram ```mermaid classDiagram class ToolCallStartPayload { + +string id +string name +string arguments } @@ -387,9 +394,16 @@ classDiagram } class MessagesUpdatedPayload { +Message[] messages + +string reason + +Message[] appended + +int32 removed } class ToolResult { +ContentPart[] parts + +string status + +string errorKind + +string errorMessage + +float64 durationMs +text() string [async-capable] } class Message { @@ -401,6 +415,7 @@ classDiagram } ToolResultPayload *-- ToolResult MessagesUpdatedPayload *-- Message + MessagesUpdatedPayload *-- Message ``` ## Turn Completion and Compaction Events @@ -408,12 +423,13 @@ classDiagram ```mermaid classDiagram class DoneEventPayload { - +string response + +unknown response +Message[] messages } class CompactionCompletePayload { +int32 removed +int32 remaining + +int32 summaryLength } class CompactionFailedPayload { +string message From f640f411b338ef7c27c6324063e54621b36f1428 Mon Sep 17 00:00:00 2001 From: Seth Juarez Date: Wed, 10 Jun 2026 10:15:20 -0700 Subject: [PATCH 02/22] Add agent harness contracts Define session-level harness events, checkpoint and trajectory records, host tool and permission protocol shapes, and generated runtime models across TypeScript, C#, Python, Rust, and Go. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Model/events/CheckpointConversionTests.cs | 162 ++++ .../events/HarnessContextConversionTests.cs | 122 +++ .../events/HookEndPayloadConversionTests.cs | 152 ++++ .../events/HookStartPayloadConversionTests.cs | 122 +++ .../events/HostToolRequestConversionTests.cs | 142 ++++ .../events/HostToolResultConversionTests.cs | 172 +++++ ...rmissionCompletedPayloadConversionTests.cs | 20 + .../PermissionDecisionConversionTests.cs | 152 ++++ .../PermissionRequestConversionTests.cs | 152 ++++ ...rmissionRequestedPayloadConversionTests.cs | 36 +- .../events/RedactedFieldConversionTests.cs | 132 ++++ .../RedactionMetadataConversionTests.cs | 122 +++ .../SessionEndPayloadConversionTests.cs | 142 ++++ .../events/SessionEventConversionTests.cs | 162 ++++ .../events/SessionFileRefConversionTests.cs | 152 ++++ .../Model/events/SessionRefConversionTests.cs | 152 ++++ .../SessionStartPayloadConversionTests.cs | 182 +++++ .../events/SessionSummaryConversionTests.cs | 152 ++++ .../events/SessionTraceConversionTests.cs | 142 ++++ .../SessionWarningPayloadConversionTests.cs | 122 +++ ...ExecutionCompletePayloadConversionTests.cs | 172 +++++ ...oolExecutionStartPayloadConversionTests.cs | 142 ++++ .../events/TrajectoryEventConversionTests.cs | 172 +++++ .../Prompty.Core/Model/events/Checkpoint.cs | 315 ++++++++ .../Model/events/HarnessContext.cs | 194 +++++ .../Model/events/HookEndPayload.cs | 245 ++++++ .../Model/events/HookStartPayload.cs | 200 +++++ .../Model/events/HostToolRequest.cs | 219 ++++++ .../Model/events/HostToolResult.cs | 280 +++++++ .../events/PermissionCompletedPayload.cs | 48 ++ .../Model/events/PermissionDecision.cs | 232 ++++++ .../Model/events/PermissionRequest.cs | 253 +++++++ .../events/PermissionRequestedPayload.cs | 80 ++ .../Model/events/RedactedField.cs | 184 +++++ .../Model/events/RedactionMetadata.cs | 257 +++++++ .../Model/events/RedactionMode.cs | 26 + .../Model/events/SessionEndPayload.cs | 206 +++++ .../Model/events/SessionEndStatus.cs | 23 + .../Prompty.Core/Model/events/SessionEvent.cs | 274 +++++++ .../Model/events/SessionEventType.cs | 32 + .../Model/events/SessionFileRef.cs | 219 ++++++ .../Prompty.Core/Model/events/SessionRef.cs | 216 ++++++ .../Model/events/SessionStartPayload.cs | 283 +++++++ .../Model/events/SessionSummary.cs | 235 ++++++ .../Model/events/SessionSummaryStatus.cs | 23 + .../Prompty.Core/Model/events/SessionTrace.cs | 714 ++++++++++++++++++ .../Model/events/SessionWarningPayload.cs | 184 +++++ .../events/ToolExecutionCompletePayload.cs | 296 ++++++++ .../Model/events/ToolExecutionStartPayload.cs | 239 ++++++ .../Model/events/TrajectoryEvent.cs | 283 +++++++ .../Model/events/TurnEventType.cs | 12 + .../Model/pipeline/CheckpointStore.cs | 24 + .../Prompty.Core/Model/pipeline/EventSink.cs | 20 + .../Model/pipeline/HostToolExecutor.cs | 16 + .../Model/pipeline/PermissionResolver.cs | 16 + .../Model/pipeline/TraceWriter.cs | 24 + runtime/go/prompty/model/checkpoint.go | 174 +++++ runtime/go/prompty/model/checkpoint_store.go | 15 + runtime/go/prompty/model/checkpoint_test.go | 210 ++++++ runtime/go/prompty/model/event_sink.go | 13 + runtime/go/prompty/model/harness_context.go | 102 +++ .../go/prompty/model/harness_context_test.go | 154 ++++ runtime/go/prompty/model/hook_end_payload.go | 137 ++++ .../go/prompty/model/hook_end_payload_test.go | 196 +++++ .../go/prompty/model/hook_start_payload.go | 104 +++ .../prompty/model/hook_start_payload_test.go | 154 ++++ .../go/prompty/model/host_tool_executor.go | 11 + runtime/go/prompty/model/host_tool_request.go | 113 +++ .../prompty/model/host_tool_request_test.go | 182 +++++ runtime/go/prompty/model/host_tool_result.go | 163 ++++ .../go/prompty/model/host_tool_result_test.go | 224 ++++++ .../model/permission_completed_payload.go | 31 +- .../permission_completed_payload_test.go | 28 + .../go/prompty/model/permission_decision.go | 118 +++ .../prompty/model/permission_decision_test.go | 196 +++++ .../go/prompty/model/permission_request.go | 131 ++++ .../prompty/model/permission_request_test.go | 196 +++++ .../model/permission_requested_payload.go | 49 +- .../permission_requested_payload_test.go | 50 +- .../go/prompty/model/permission_resolver.go | 11 + runtime/go/prompty/model/redacted_field.go | 104 +++ .../go/prompty/model/redacted_field_test.go | 168 +++++ .../go/prompty/model/redaction_metadata.go | 110 +++ .../prompty/model/redaction_metadata_test.go | 154 ++++ .../go/prompty/model/session_end_payload.go | 129 ++++ .../prompty/model/session_end_payload_test.go | 182 +++++ runtime/go/prompty/model/session_event.go | 152 ++++ .../go/prompty/model/session_event_test.go | 210 ++++++ runtime/go/prompty/model/session_file_ref.go | 122 +++ .../go/prompty/model/session_file_ref_test.go | 196 +++++ runtime/go/prompty/model/session_ref.go | 119 +++ runtime/go/prompty/model/session_ref_test.go | 196 +++++ .../go/prompty/model/session_start_payload.go | 156 ++++ .../model/session_start_payload_test.go | 238 ++++++ runtime/go/prompty/model/session_summary.go | 164 ++++ .../go/prompty/model/session_summary_test.go | 196 +++++ runtime/go/prompty/model/session_trace.go | 228 ++++++ .../go/prompty/model/session_trace_test.go | 182 +++++ .../prompty/model/session_warning_payload.go | 94 +++ .../model/session_warning_payload_test.go | 154 ++++ .../model/tool_execution_complete_payload.go | 173 +++++ .../tool_execution_complete_payload_test.go | 224 ++++++ .../model/tool_execution_start_payload.go | 126 ++++ .../tool_execution_start_payload_test.go | 182 +++++ runtime/go/prompty/model/trace_writer.go | 15 + runtime/go/prompty/model/trajectory_event.go | 157 ++++ .../go/prompty/model/trajectory_event_test.go | 224 ++++++ runtime/go/prompty/model/turn_event.go | 44 +- .../python/prompty/prompty/model/__init__.py | 52 ++ .../prompty/model/events/_Checkpoint.py | 168 +++++ .../prompty/model/events/_HarnessContext.py | 113 +++ .../prompty/model/events/_HookEndPayload.py | 140 ++++ .../prompty/model/events/_HookStartPayload.py | 119 +++ .../prompty/model/events/_HostToolRequest.py | 125 +++ .../prompty/model/events/_HostToolResult.py | 153 ++++ .../events/_PermissionCompletedPayload.py | 21 + .../model/events/_PermissionDecision.py | 132 ++++ .../model/events/_PermissionRequest.py | 140 ++++ .../events/_PermissionRequestedPayload.py | 36 + .../prompty/model/events/_RedactedField.py | 113 +++ .../model/events/_RedactionMetadata.py | 135 ++++ .../model/events/_SessionEndPayload.py | 120 +++ .../prompty/model/events/_SessionEvent.py | 164 ++++ .../prompty/model/events/_SessionFileRef.py | 125 +++ .../prompty/model/events/_SessionRef.py | 125 +++ .../model/events/_SessionStartPayload.py | 154 ++++ .../prompty/model/events/_SessionSummary.py | 135 ++++ .../prompty/model/events/_SessionTrace.py | 314 ++++++++ .../model/events/_SessionWarningPayload.py | 111 +++ .../events/_ToolExecutionCompletePayload.py | 161 ++++ .../events/_ToolExecutionStartPayload.py | 136 ++++ .../prompty/model/events/_TrajectoryEvent.py | 154 ++++ .../prompty/model/events/_TurnEvent.py | 4 + .../prompty/prompty/model/events/__init__.py | 42 ++ .../model/pipeline/_CheckpointStore.py | 38 + .../prompty/model/pipeline/_EventSink.py | 23 + .../model/pipeline/_HostToolExecutor.py | 23 + .../model/pipeline/_PermissionResolver.py | 23 + .../prompty/model/pipeline/_TraceWriter.py | 28 + .../prompty/model/pipeline/__init__.py | 10 + .../tests/model/events/test_checkpoint.py | 113 +++ .../model/events/test_harness_context.py | 81 ++ .../model/events/test_hook_end_payload.py | 105 +++ .../model/events/test_hook_start_payload.py | 81 ++ .../model/events/test_host_tool_request.py | 97 +++ .../model/events/test_host_tool_result.py | 121 +++ .../test_permission_completed_payload.py | 16 + .../model/events/test_permission_decision.py | 105 +++ .../model/events/test_permission_request.py | 105 +++ .../test_permission_requested_payload.py | 32 +- .../tests/model/events/test_redacted_field.py | 89 +++ .../model/events/test_redaction_metadata.py | 81 ++ .../model/events/test_session_end_payload.py | 97 +++ .../tests/model/events/test_session_event.py | 113 +++ .../model/events/test_session_file_ref.py | 105 +++ .../tests/model/events/test_session_ref.py | 105 +++ .../events/test_session_start_payload.py | 129 ++++ .../model/events/test_session_summary.py | 105 +++ .../tests/model/events/test_session_trace.py | 97 +++ .../events/test_session_warning_payload.py | 81 ++ .../test_tool_execution_complete_payload.py | 121 +++ .../test_tool_execution_start_payload.py | 97 +++ .../model/events/test_trajectory_event.py | 121 +++ .../prompty/src/model/events/checkpoint.rs | 140 ++++ .../src/model/events/harness_context.rs | 81 ++ .../src/model/events/hook_end_payload.rs | 108 +++ .../src/model/events/hook_start_payload.rs | 92 +++ .../src/model/events/host_tool_request.rs | 93 +++ .../src/model/events/host_tool_result.rs | 115 +++ runtime/rust/prompty/src/model/events/mod.rs | 63 ++ .../events/permission_completed_payload.rs | 24 + .../src/model/events/permission_decision.rs | 97 +++ .../src/model/events/permission_request.rs | 111 +++ .../events/permission_requested_payload.rs | 41 + .../src/model/events/redacted_field.rs | 123 +++ .../src/model/events/redaction_metadata.rs | 97 +++ .../src/model/events/session_end_payload.rs | 127 ++++ .../prompty/src/model/events/session_event.rs | 178 +++++ .../src/model/events/session_file_ref.rs | 87 +++ .../prompty/src/model/events/session_ref.rs | 87 +++ .../src/model/events/session_start_payload.rs | 116 +++ .../src/model/events/session_summary.rs | 144 ++++ .../prompty/src/model/events/session_trace.rs | 260 +++++++ .../model/events/session_warning_payload.rs | 81 ++ .../events/tool_execution_complete_payload.rs | 126 ++++ .../events/tool_execution_start_payload.rs | 104 +++ .../src/model/events/trajectory_event.rs | 122 +++ .../prompty/src/model/events/turn_event.rs | 16 + .../src/model/pipeline/checkpoint_store.rs | 17 + .../prompty/src/model/pipeline/event_sink.rs | 17 + .../src/model/pipeline/host_tool_executor.rs | 15 + .../rust/prompty/src/model/pipeline/mod.rs | 15 + .../src/model/pipeline/permission_resolver.rs | 15 + .../src/model/pipeline/trace_writer.rs | 21 + .../tests/model/events/checkpoint_test.rs | 79 ++ .../model/events/harness_context_test.rs | 56 ++ .../model/events/hook_end_payload_test.rs | 71 ++ .../model/events/hook_start_payload_test.rs | 54 ++ .../model/events/host_tool_request_test.rs | 67 ++ .../model/events/host_tool_result_test.rs | 84 +++ .../rust/prompty/tests/model/events/mod.rs | 21 + .../permission_completed_payload_test.rs | 12 + .../model/events/permission_decision_test.rs | 72 ++ .../model/events/permission_request_test.rs | 73 ++ .../permission_requested_payload_test.rs | 22 +- .../tests/model/events/redacted_field_test.rs | 61 ++ .../model/events/redaction_metadata_test.rs | 56 ++ .../model/events/session_end_payload_test.rs | 69 ++ .../tests/model/events/session_event_test.rs | 79 ++ .../model/events/session_file_ref_test.rs | 73 ++ .../tests/model/events/session_ref_test.rs | 72 ++ .../events/session_start_payload_test.rs | 91 +++ .../model/events/session_summary_test.rs | 74 ++ .../tests/model/events/session_trace_test.rs | 67 ++ .../events/session_warning_payload_test.rs | 54 ++ .../tool_execution_complete_payload_test.rs | 84 +++ .../tool_execution_start_payload_test.rs | 67 ++ .../model/events/trajectory_event_test.rs | 85 +++ .../core/src/model/events/checkpoint.ts | 188 +++++ .../core/src/model/events/harness-context.ts | 103 +++ .../core/src/model/events/hook-end-payload.ts | 144 ++++ .../src/model/events/hook-start-payload.ts | 116 +++ .../src/model/events/host-tool-request.ts | 124 +++ .../core/src/model/events/host-tool-result.ts | 159 ++++ .../packages/core/src/model/events/index.ts | 21 + .../events/permission-completed-payload.ts | 30 + .../src/model/events/permission-decision.ts | 129 ++++ .../src/model/events/permission-request.ts | 141 ++++ .../events/permission-requested-payload.ts | 54 ++ .../core/src/model/events/redacted-field.ts | 106 +++ .../src/model/events/redaction-metadata.ts | 140 ++++ .../src/model/events/session-end-payload.ts | 119 +++ .../core/src/model/events/session-event.ts | 168 +++++ .../core/src/model/events/session-file-ref.ts | 121 +++ .../core/src/model/events/session-ref.ts | 119 +++ .../src/model/events/session-start-payload.ts | 171 +++++ .../core/src/model/events/session-summary.ts | 141 ++++ .../core/src/model/events/session-trace.ts | 411 ++++++++++ .../model/events/session-warning-payload.ts | 99 +++ .../events/tool-execution-complete-payload.ts | 185 +++++ .../events/tool-execution-start-payload.ts | 150 ++++ .../core/src/model/events/trajectory-event.ts | 165 ++++ .../core/src/model/events/turn-event.ts | 4 + .../packages/core/src/model/index.ts | 26 + .../src/model/pipeline/checkpoint-store.ts | 14 + .../core/src/model/pipeline/event-sink.ts | 13 + .../src/model/pipeline/host-tool-executor.ts | 11 + .../packages/core/src/model/pipeline/index.ts | 5 + .../src/model/pipeline/permission-resolver.ts | 11 + .../core/src/model/pipeline/trace-writer.ts | 16 + .../tests/model/events/checkpoint.test.ts | 87 +++ .../model/events/harness-context.test.ts | 71 ++ .../model/events/hook-end-payload.test.ts | 83 ++ .../model/events/hook-start-payload.test.ts | 71 ++ .../model/events/host-tool-request.test.ts | 79 ++ .../model/events/host-tool-result.test.ts | 91 +++ .../permission-completed-payload.test.ts | 16 +- .../model/events/permission-decision.test.ts | 83 ++ .../model/events/permission-request.test.ts | 83 ++ .../permission-requested-payload.test.ts | 20 +- .../tests/model/events/redacted-field.test.ts | 75 ++ .../model/events/redaction-metadata.test.ts | 71 ++ .../model/events/session-end-payload.test.ts | 79 ++ .../tests/model/events/session-event.test.ts | 87 +++ .../model/events/session-file-ref.test.ts | 83 ++ .../tests/model/events/session-ref.test.ts | 83 ++ .../events/session-start-payload.test.ts | 95 +++ .../model/events/session-summary.test.ts | 83 ++ .../tests/model/events/session-trace.test.ts | 79 ++ .../events/session-warning-payload.test.ts | 71 ++ .../tool-execution-complete-payload.test.ts | 91 +++ .../tool-execution-start-payload.test.ts | 79 ++ .../model/events/trajectory-event.test.ts | 91 +++ schema/model/events/payloads.tsp | 316 ++++++++ schema/model/events/session.tsp | 368 +++++++++ schema/model/main.tsp | 2 + schema/model/pipeline/harness.tsp | 100 +++ vscode/prompty/schemas/Checkpoint.yaml | 42 ++ vscode/prompty/schemas/CheckpointStore.yaml | 5 + vscode/prompty/schemas/EventSink.yaml | 5 + vscode/prompty/schemas/HarnessContext.yaml | 17 + vscode/prompty/schemas/HookEndPayload.yaml | 30 + vscode/prompty/schemas/HookStartPayload.yaml | 20 + vscode/prompty/schemas/HostToolExecutor.yaml | 5 + vscode/prompty/schemas/HostToolRequest.yaml | 22 + vscode/prompty/schemas/HostToolResult.yaml | 36 + .../schemas/PermissionCompletedPayload.yaml | 9 + .../prompty/schemas/PermissionDecision.yaml | 26 + vscode/prompty/schemas/PermissionRequest.yaml | 30 + .../schemas/PermissionRequestedPayload.yaml | 15 + .../prompty/schemas/PermissionResolver.yaml | 5 + vscode/prompty/schemas/RedactedField.yaml | 27 + vscode/prompty/schemas/RedactionMetadata.yaml | 17 + vscode/prompty/schemas/SessionEndPayload.yaml | 25 + vscode/prompty/schemas/SessionEvent.yaml | 52 ++ vscode/prompty/schemas/SessionFileRef.yaml | 24 + vscode/prompty/schemas/SessionRef.yaml | 25 + .../prompty/schemas/SessionStartPayload.yaml | 37 + vscode/prompty/schemas/SessionSummary.yaml | 37 + vscode/prompty/schemas/SessionTrace.yaml | 54 ++ .../schemas/SessionWarningPayload.yaml | 17 + .../schemas/ToolExecutionCompletePayload.yaml | 39 + .../schemas/ToolExecutionStartPayload.yaml | 29 + vscode/prompty/schemas/TraceWriter.yaml | 5 + vscode/prompty/schemas/TrajectoryEvent.yaml | 36 + vscode/prompty/schemas/TurnEvent.yaml | 8 + web/src/content/docs/reference/Checkpoint.md | 73 ++ .../content/docs/reference/CheckpointStore.md | 37 + web/src/content/docs/reference/EventSink.md | 35 + .../content/docs/reference/HarnessContext.md | 43 ++ .../content/docs/reference/HookEndPayload.md | 64 ++ .../docs/reference/HookStartPayload.md | 55 ++ .../docs/reference/HostToolExecutor.md | 33 + .../content/docs/reference/HostToolRequest.md | 47 ++ .../content/docs/reference/HostToolResult.md | 58 ++ .../reference/PermissionCompletedPayload.md | 8 + .../docs/reference/PermissionDecision.md | 50 ++ .../docs/reference/PermissionRequest.md | 53 ++ .../reference/PermissionRequestedPayload.md | 25 + .../docs/reference/PermissionResolver.md | 33 + .../content/docs/reference/RedactedField.md | 42 ++ .../docs/reference/RedactionMetadata.md | 53 ++ .../docs/reference/SessionEndPayload.md | 45 ++ .../content/docs/reference/SessionEvent.md | 69 ++ .../content/docs/reference/SessionFileRef.md | 48 ++ web/src/content/docs/reference/SessionRef.md | 48 ++ .../docs/reference/SessionStartPayload.md | 71 ++ .../content/docs/reference/SessionSummary.md | 62 ++ .../content/docs/reference/SessionTrace.md | 142 ++++ .../docs/reference/SessionWarningPayload.md | 41 + .../reference/ToolExecutionCompletePayload.md | 72 ++ .../reference/ToolExecutionStartPayload.md | 64 ++ web/src/content/docs/reference/TraceWriter.md | 37 + .../content/docs/reference/TrajectoryEvent.md | 70 ++ 334 files changed, 34092 insertions(+), 47 deletions(-) create mode 100644 runtime/csharp/Prompty.Core.Tests/Model/events/CheckpointConversionTests.cs create mode 100644 runtime/csharp/Prompty.Core.Tests/Model/events/HarnessContextConversionTests.cs create mode 100644 runtime/csharp/Prompty.Core.Tests/Model/events/HookEndPayloadConversionTests.cs create mode 100644 runtime/csharp/Prompty.Core.Tests/Model/events/HookStartPayloadConversionTests.cs create mode 100644 runtime/csharp/Prompty.Core.Tests/Model/events/HostToolRequestConversionTests.cs create mode 100644 runtime/csharp/Prompty.Core.Tests/Model/events/HostToolResultConversionTests.cs create mode 100644 runtime/csharp/Prompty.Core.Tests/Model/events/PermissionDecisionConversionTests.cs create mode 100644 runtime/csharp/Prompty.Core.Tests/Model/events/PermissionRequestConversionTests.cs create mode 100644 runtime/csharp/Prompty.Core.Tests/Model/events/RedactedFieldConversionTests.cs create mode 100644 runtime/csharp/Prompty.Core.Tests/Model/events/RedactionMetadataConversionTests.cs create mode 100644 runtime/csharp/Prompty.Core.Tests/Model/events/SessionEndPayloadConversionTests.cs create mode 100644 runtime/csharp/Prompty.Core.Tests/Model/events/SessionEventConversionTests.cs create mode 100644 runtime/csharp/Prompty.Core.Tests/Model/events/SessionFileRefConversionTests.cs create mode 100644 runtime/csharp/Prompty.Core.Tests/Model/events/SessionRefConversionTests.cs create mode 100644 runtime/csharp/Prompty.Core.Tests/Model/events/SessionStartPayloadConversionTests.cs create mode 100644 runtime/csharp/Prompty.Core.Tests/Model/events/SessionSummaryConversionTests.cs create mode 100644 runtime/csharp/Prompty.Core.Tests/Model/events/SessionTraceConversionTests.cs create mode 100644 runtime/csharp/Prompty.Core.Tests/Model/events/SessionWarningPayloadConversionTests.cs create mode 100644 runtime/csharp/Prompty.Core.Tests/Model/events/ToolExecutionCompletePayloadConversionTests.cs create mode 100644 runtime/csharp/Prompty.Core.Tests/Model/events/ToolExecutionStartPayloadConversionTests.cs create mode 100644 runtime/csharp/Prompty.Core.Tests/Model/events/TrajectoryEventConversionTests.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/Checkpoint.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/HarnessContext.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/HookEndPayload.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/HookStartPayload.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/HostToolRequest.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/HostToolResult.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/PermissionDecision.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/PermissionRequest.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/RedactedField.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/RedactionMetadata.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/RedactionMode.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/SessionEndPayload.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/SessionEndStatus.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/SessionEvent.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/SessionEventType.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/SessionFileRef.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/SessionRef.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/SessionStartPayload.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/SessionSummary.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/SessionSummaryStatus.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/SessionTrace.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/SessionWarningPayload.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/ToolExecutionCompletePayload.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/ToolExecutionStartPayload.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/TrajectoryEvent.cs create mode 100644 runtime/csharp/Prompty.Core/Model/pipeline/CheckpointStore.cs create mode 100644 runtime/csharp/Prompty.Core/Model/pipeline/EventSink.cs create mode 100644 runtime/csharp/Prompty.Core/Model/pipeline/HostToolExecutor.cs create mode 100644 runtime/csharp/Prompty.Core/Model/pipeline/PermissionResolver.cs create mode 100644 runtime/csharp/Prompty.Core/Model/pipeline/TraceWriter.cs create mode 100644 runtime/go/prompty/model/checkpoint.go create mode 100644 runtime/go/prompty/model/checkpoint_store.go create mode 100644 runtime/go/prompty/model/checkpoint_test.go create mode 100644 runtime/go/prompty/model/event_sink.go create mode 100644 runtime/go/prompty/model/harness_context.go create mode 100644 runtime/go/prompty/model/harness_context_test.go create mode 100644 runtime/go/prompty/model/hook_end_payload.go create mode 100644 runtime/go/prompty/model/hook_end_payload_test.go create mode 100644 runtime/go/prompty/model/hook_start_payload.go create mode 100644 runtime/go/prompty/model/hook_start_payload_test.go create mode 100644 runtime/go/prompty/model/host_tool_executor.go create mode 100644 runtime/go/prompty/model/host_tool_request.go create mode 100644 runtime/go/prompty/model/host_tool_request_test.go create mode 100644 runtime/go/prompty/model/host_tool_result.go create mode 100644 runtime/go/prompty/model/host_tool_result_test.go create mode 100644 runtime/go/prompty/model/permission_decision.go create mode 100644 runtime/go/prompty/model/permission_decision_test.go create mode 100644 runtime/go/prompty/model/permission_request.go create mode 100644 runtime/go/prompty/model/permission_request_test.go create mode 100644 runtime/go/prompty/model/permission_resolver.go create mode 100644 runtime/go/prompty/model/redacted_field.go create mode 100644 runtime/go/prompty/model/redacted_field_test.go create mode 100644 runtime/go/prompty/model/redaction_metadata.go create mode 100644 runtime/go/prompty/model/redaction_metadata_test.go create mode 100644 runtime/go/prompty/model/session_end_payload.go create mode 100644 runtime/go/prompty/model/session_end_payload_test.go create mode 100644 runtime/go/prompty/model/session_event.go create mode 100644 runtime/go/prompty/model/session_event_test.go create mode 100644 runtime/go/prompty/model/session_file_ref.go create mode 100644 runtime/go/prompty/model/session_file_ref_test.go create mode 100644 runtime/go/prompty/model/session_ref.go create mode 100644 runtime/go/prompty/model/session_ref_test.go create mode 100644 runtime/go/prompty/model/session_start_payload.go create mode 100644 runtime/go/prompty/model/session_start_payload_test.go create mode 100644 runtime/go/prompty/model/session_summary.go create mode 100644 runtime/go/prompty/model/session_summary_test.go create mode 100644 runtime/go/prompty/model/session_trace.go create mode 100644 runtime/go/prompty/model/session_trace_test.go create mode 100644 runtime/go/prompty/model/session_warning_payload.go create mode 100644 runtime/go/prompty/model/session_warning_payload_test.go create mode 100644 runtime/go/prompty/model/tool_execution_complete_payload.go create mode 100644 runtime/go/prompty/model/tool_execution_complete_payload_test.go create mode 100644 runtime/go/prompty/model/tool_execution_start_payload.go create mode 100644 runtime/go/prompty/model/tool_execution_start_payload_test.go create mode 100644 runtime/go/prompty/model/trace_writer.go create mode 100644 runtime/go/prompty/model/trajectory_event.go create mode 100644 runtime/go/prompty/model/trajectory_event_test.go create mode 100644 runtime/python/prompty/prompty/model/events/_Checkpoint.py create mode 100644 runtime/python/prompty/prompty/model/events/_HarnessContext.py create mode 100644 runtime/python/prompty/prompty/model/events/_HookEndPayload.py create mode 100644 runtime/python/prompty/prompty/model/events/_HookStartPayload.py create mode 100644 runtime/python/prompty/prompty/model/events/_HostToolRequest.py create mode 100644 runtime/python/prompty/prompty/model/events/_HostToolResult.py create mode 100644 runtime/python/prompty/prompty/model/events/_PermissionDecision.py create mode 100644 runtime/python/prompty/prompty/model/events/_PermissionRequest.py create mode 100644 runtime/python/prompty/prompty/model/events/_RedactedField.py create mode 100644 runtime/python/prompty/prompty/model/events/_RedactionMetadata.py create mode 100644 runtime/python/prompty/prompty/model/events/_SessionEndPayload.py create mode 100644 runtime/python/prompty/prompty/model/events/_SessionEvent.py create mode 100644 runtime/python/prompty/prompty/model/events/_SessionFileRef.py create mode 100644 runtime/python/prompty/prompty/model/events/_SessionRef.py create mode 100644 runtime/python/prompty/prompty/model/events/_SessionStartPayload.py create mode 100644 runtime/python/prompty/prompty/model/events/_SessionSummary.py create mode 100644 runtime/python/prompty/prompty/model/events/_SessionTrace.py create mode 100644 runtime/python/prompty/prompty/model/events/_SessionWarningPayload.py create mode 100644 runtime/python/prompty/prompty/model/events/_ToolExecutionCompletePayload.py create mode 100644 runtime/python/prompty/prompty/model/events/_ToolExecutionStartPayload.py create mode 100644 runtime/python/prompty/prompty/model/events/_TrajectoryEvent.py create mode 100644 runtime/python/prompty/prompty/model/pipeline/_CheckpointStore.py create mode 100644 runtime/python/prompty/prompty/model/pipeline/_EventSink.py create mode 100644 runtime/python/prompty/prompty/model/pipeline/_HostToolExecutor.py create mode 100644 runtime/python/prompty/prompty/model/pipeline/_PermissionResolver.py create mode 100644 runtime/python/prompty/prompty/model/pipeline/_TraceWriter.py create mode 100644 runtime/python/prompty/tests/model/events/test_checkpoint.py create mode 100644 runtime/python/prompty/tests/model/events/test_harness_context.py create mode 100644 runtime/python/prompty/tests/model/events/test_hook_end_payload.py create mode 100644 runtime/python/prompty/tests/model/events/test_hook_start_payload.py create mode 100644 runtime/python/prompty/tests/model/events/test_host_tool_request.py create mode 100644 runtime/python/prompty/tests/model/events/test_host_tool_result.py create mode 100644 runtime/python/prompty/tests/model/events/test_permission_decision.py create mode 100644 runtime/python/prompty/tests/model/events/test_permission_request.py create mode 100644 runtime/python/prompty/tests/model/events/test_redacted_field.py create mode 100644 runtime/python/prompty/tests/model/events/test_redaction_metadata.py create mode 100644 runtime/python/prompty/tests/model/events/test_session_end_payload.py create mode 100644 runtime/python/prompty/tests/model/events/test_session_event.py create mode 100644 runtime/python/prompty/tests/model/events/test_session_file_ref.py create mode 100644 runtime/python/prompty/tests/model/events/test_session_ref.py create mode 100644 runtime/python/prompty/tests/model/events/test_session_start_payload.py create mode 100644 runtime/python/prompty/tests/model/events/test_session_summary.py create mode 100644 runtime/python/prompty/tests/model/events/test_session_trace.py create mode 100644 runtime/python/prompty/tests/model/events/test_session_warning_payload.py create mode 100644 runtime/python/prompty/tests/model/events/test_tool_execution_complete_payload.py create mode 100644 runtime/python/prompty/tests/model/events/test_tool_execution_start_payload.py create mode 100644 runtime/python/prompty/tests/model/events/test_trajectory_event.py create mode 100644 runtime/rust/prompty/src/model/events/checkpoint.rs create mode 100644 runtime/rust/prompty/src/model/events/harness_context.rs create mode 100644 runtime/rust/prompty/src/model/events/hook_end_payload.rs create mode 100644 runtime/rust/prompty/src/model/events/hook_start_payload.rs create mode 100644 runtime/rust/prompty/src/model/events/host_tool_request.rs create mode 100644 runtime/rust/prompty/src/model/events/host_tool_result.rs create mode 100644 runtime/rust/prompty/src/model/events/permission_decision.rs create mode 100644 runtime/rust/prompty/src/model/events/permission_request.rs create mode 100644 runtime/rust/prompty/src/model/events/redacted_field.rs create mode 100644 runtime/rust/prompty/src/model/events/redaction_metadata.rs create mode 100644 runtime/rust/prompty/src/model/events/session_end_payload.rs create mode 100644 runtime/rust/prompty/src/model/events/session_event.rs create mode 100644 runtime/rust/prompty/src/model/events/session_file_ref.rs create mode 100644 runtime/rust/prompty/src/model/events/session_ref.rs create mode 100644 runtime/rust/prompty/src/model/events/session_start_payload.rs create mode 100644 runtime/rust/prompty/src/model/events/session_summary.rs create mode 100644 runtime/rust/prompty/src/model/events/session_trace.rs create mode 100644 runtime/rust/prompty/src/model/events/session_warning_payload.rs create mode 100644 runtime/rust/prompty/src/model/events/tool_execution_complete_payload.rs create mode 100644 runtime/rust/prompty/src/model/events/tool_execution_start_payload.rs create mode 100644 runtime/rust/prompty/src/model/events/trajectory_event.rs create mode 100644 runtime/rust/prompty/src/model/pipeline/checkpoint_store.rs create mode 100644 runtime/rust/prompty/src/model/pipeline/event_sink.rs create mode 100644 runtime/rust/prompty/src/model/pipeline/host_tool_executor.rs create mode 100644 runtime/rust/prompty/src/model/pipeline/permission_resolver.rs create mode 100644 runtime/rust/prompty/src/model/pipeline/trace_writer.rs create mode 100644 runtime/rust/prompty/tests/model/events/checkpoint_test.rs create mode 100644 runtime/rust/prompty/tests/model/events/harness_context_test.rs create mode 100644 runtime/rust/prompty/tests/model/events/hook_end_payload_test.rs create mode 100644 runtime/rust/prompty/tests/model/events/hook_start_payload_test.rs create mode 100644 runtime/rust/prompty/tests/model/events/host_tool_request_test.rs create mode 100644 runtime/rust/prompty/tests/model/events/host_tool_result_test.rs create mode 100644 runtime/rust/prompty/tests/model/events/permission_decision_test.rs create mode 100644 runtime/rust/prompty/tests/model/events/permission_request_test.rs create mode 100644 runtime/rust/prompty/tests/model/events/redacted_field_test.rs create mode 100644 runtime/rust/prompty/tests/model/events/redaction_metadata_test.rs create mode 100644 runtime/rust/prompty/tests/model/events/session_end_payload_test.rs create mode 100644 runtime/rust/prompty/tests/model/events/session_event_test.rs create mode 100644 runtime/rust/prompty/tests/model/events/session_file_ref_test.rs create mode 100644 runtime/rust/prompty/tests/model/events/session_ref_test.rs create mode 100644 runtime/rust/prompty/tests/model/events/session_start_payload_test.rs create mode 100644 runtime/rust/prompty/tests/model/events/session_summary_test.rs create mode 100644 runtime/rust/prompty/tests/model/events/session_trace_test.rs create mode 100644 runtime/rust/prompty/tests/model/events/session_warning_payload_test.rs create mode 100644 runtime/rust/prompty/tests/model/events/tool_execution_complete_payload_test.rs create mode 100644 runtime/rust/prompty/tests/model/events/tool_execution_start_payload_test.rs create mode 100644 runtime/rust/prompty/tests/model/events/trajectory_event_test.rs create mode 100644 runtime/typescript/packages/core/src/model/events/checkpoint.ts create mode 100644 runtime/typescript/packages/core/src/model/events/harness-context.ts create mode 100644 runtime/typescript/packages/core/src/model/events/hook-end-payload.ts create mode 100644 runtime/typescript/packages/core/src/model/events/hook-start-payload.ts create mode 100644 runtime/typescript/packages/core/src/model/events/host-tool-request.ts create mode 100644 runtime/typescript/packages/core/src/model/events/host-tool-result.ts create mode 100644 runtime/typescript/packages/core/src/model/events/permission-decision.ts create mode 100644 runtime/typescript/packages/core/src/model/events/permission-request.ts create mode 100644 runtime/typescript/packages/core/src/model/events/redacted-field.ts create mode 100644 runtime/typescript/packages/core/src/model/events/redaction-metadata.ts create mode 100644 runtime/typescript/packages/core/src/model/events/session-end-payload.ts create mode 100644 runtime/typescript/packages/core/src/model/events/session-event.ts create mode 100644 runtime/typescript/packages/core/src/model/events/session-file-ref.ts create mode 100644 runtime/typescript/packages/core/src/model/events/session-ref.ts create mode 100644 runtime/typescript/packages/core/src/model/events/session-start-payload.ts create mode 100644 runtime/typescript/packages/core/src/model/events/session-summary.ts create mode 100644 runtime/typescript/packages/core/src/model/events/session-trace.ts create mode 100644 runtime/typescript/packages/core/src/model/events/session-warning-payload.ts create mode 100644 runtime/typescript/packages/core/src/model/events/tool-execution-complete-payload.ts create mode 100644 runtime/typescript/packages/core/src/model/events/tool-execution-start-payload.ts create mode 100644 runtime/typescript/packages/core/src/model/events/trajectory-event.ts create mode 100644 runtime/typescript/packages/core/src/model/pipeline/checkpoint-store.ts create mode 100644 runtime/typescript/packages/core/src/model/pipeline/event-sink.ts create mode 100644 runtime/typescript/packages/core/src/model/pipeline/host-tool-executor.ts create mode 100644 runtime/typescript/packages/core/src/model/pipeline/permission-resolver.ts create mode 100644 runtime/typescript/packages/core/src/model/pipeline/trace-writer.ts create mode 100644 runtime/typescript/packages/core/tests/model/events/checkpoint.test.ts create mode 100644 runtime/typescript/packages/core/tests/model/events/harness-context.test.ts create mode 100644 runtime/typescript/packages/core/tests/model/events/hook-end-payload.test.ts create mode 100644 runtime/typescript/packages/core/tests/model/events/hook-start-payload.test.ts create mode 100644 runtime/typescript/packages/core/tests/model/events/host-tool-request.test.ts create mode 100644 runtime/typescript/packages/core/tests/model/events/host-tool-result.test.ts create mode 100644 runtime/typescript/packages/core/tests/model/events/permission-decision.test.ts create mode 100644 runtime/typescript/packages/core/tests/model/events/permission-request.test.ts create mode 100644 runtime/typescript/packages/core/tests/model/events/redacted-field.test.ts create mode 100644 runtime/typescript/packages/core/tests/model/events/redaction-metadata.test.ts create mode 100644 runtime/typescript/packages/core/tests/model/events/session-end-payload.test.ts create mode 100644 runtime/typescript/packages/core/tests/model/events/session-event.test.ts create mode 100644 runtime/typescript/packages/core/tests/model/events/session-file-ref.test.ts create mode 100644 runtime/typescript/packages/core/tests/model/events/session-ref.test.ts create mode 100644 runtime/typescript/packages/core/tests/model/events/session-start-payload.test.ts create mode 100644 runtime/typescript/packages/core/tests/model/events/session-summary.test.ts create mode 100644 runtime/typescript/packages/core/tests/model/events/session-trace.test.ts create mode 100644 runtime/typescript/packages/core/tests/model/events/session-warning-payload.test.ts create mode 100644 runtime/typescript/packages/core/tests/model/events/tool-execution-complete-payload.test.ts create mode 100644 runtime/typescript/packages/core/tests/model/events/tool-execution-start-payload.test.ts create mode 100644 runtime/typescript/packages/core/tests/model/events/trajectory-event.test.ts create mode 100644 schema/model/events/session.tsp create mode 100644 schema/model/pipeline/harness.tsp create mode 100644 vscode/prompty/schemas/Checkpoint.yaml create mode 100644 vscode/prompty/schemas/CheckpointStore.yaml create mode 100644 vscode/prompty/schemas/EventSink.yaml create mode 100644 vscode/prompty/schemas/HarnessContext.yaml create mode 100644 vscode/prompty/schemas/HookEndPayload.yaml create mode 100644 vscode/prompty/schemas/HookStartPayload.yaml create mode 100644 vscode/prompty/schemas/HostToolExecutor.yaml create mode 100644 vscode/prompty/schemas/HostToolRequest.yaml create mode 100644 vscode/prompty/schemas/HostToolResult.yaml create mode 100644 vscode/prompty/schemas/PermissionDecision.yaml create mode 100644 vscode/prompty/schemas/PermissionRequest.yaml create mode 100644 vscode/prompty/schemas/PermissionResolver.yaml create mode 100644 vscode/prompty/schemas/RedactedField.yaml create mode 100644 vscode/prompty/schemas/RedactionMetadata.yaml create mode 100644 vscode/prompty/schemas/SessionEndPayload.yaml create mode 100644 vscode/prompty/schemas/SessionEvent.yaml create mode 100644 vscode/prompty/schemas/SessionFileRef.yaml create mode 100644 vscode/prompty/schemas/SessionRef.yaml create mode 100644 vscode/prompty/schemas/SessionStartPayload.yaml create mode 100644 vscode/prompty/schemas/SessionSummary.yaml create mode 100644 vscode/prompty/schemas/SessionTrace.yaml create mode 100644 vscode/prompty/schemas/SessionWarningPayload.yaml create mode 100644 vscode/prompty/schemas/ToolExecutionCompletePayload.yaml create mode 100644 vscode/prompty/schemas/ToolExecutionStartPayload.yaml create mode 100644 vscode/prompty/schemas/TraceWriter.yaml create mode 100644 vscode/prompty/schemas/TrajectoryEvent.yaml create mode 100644 web/src/content/docs/reference/Checkpoint.md create mode 100644 web/src/content/docs/reference/CheckpointStore.md create mode 100644 web/src/content/docs/reference/EventSink.md create mode 100644 web/src/content/docs/reference/HarnessContext.md create mode 100644 web/src/content/docs/reference/HookEndPayload.md create mode 100644 web/src/content/docs/reference/HookStartPayload.md create mode 100644 web/src/content/docs/reference/HostToolExecutor.md create mode 100644 web/src/content/docs/reference/HostToolRequest.md create mode 100644 web/src/content/docs/reference/HostToolResult.md create mode 100644 web/src/content/docs/reference/PermissionDecision.md create mode 100644 web/src/content/docs/reference/PermissionRequest.md create mode 100644 web/src/content/docs/reference/PermissionResolver.md create mode 100644 web/src/content/docs/reference/RedactedField.md create mode 100644 web/src/content/docs/reference/RedactionMetadata.md create mode 100644 web/src/content/docs/reference/SessionEndPayload.md create mode 100644 web/src/content/docs/reference/SessionEvent.md create mode 100644 web/src/content/docs/reference/SessionFileRef.md create mode 100644 web/src/content/docs/reference/SessionRef.md create mode 100644 web/src/content/docs/reference/SessionStartPayload.md create mode 100644 web/src/content/docs/reference/SessionSummary.md create mode 100644 web/src/content/docs/reference/SessionTrace.md create mode 100644 web/src/content/docs/reference/SessionWarningPayload.md create mode 100644 web/src/content/docs/reference/ToolExecutionCompletePayload.md create mode 100644 web/src/content/docs/reference/ToolExecutionStartPayload.md create mode 100644 web/src/content/docs/reference/TraceWriter.md create mode 100644 web/src/content/docs/reference/TrajectoryEvent.md diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/CheckpointConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/CheckpointConversionTests.cs new file mode 100644 index 00000000..acc514d5 --- /dev/null +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/CheckpointConversionTests.cs @@ -0,0 +1,162 @@ +using Xunit; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + + +public class CheckpointConversionTests +{ + [Fact] + public void LoadYamlInput() + { + string yamlData = """ +id: chk_abc123 +sessionId: sess_abc123 +turnId: turn_001 +checkpointNumber: 3 +title: Added harness contracts +createdAt: "2026-06-09T20:00:00Z" + +"""; + + var instance = Checkpoint.FromYaml(yamlData); + + Assert.NotNull(instance); + Assert.Equal("chk_abc123", instance.Id); + Assert.Equal("sess_abc123", instance.SessionId); + Assert.Equal("turn_001", instance.TurnId); + Assert.Equal(3, instance.CheckpointNumber); + Assert.Equal("Added harness contracts", instance.Title); + Assert.Equal("2026-06-09T20:00:00Z", instance.CreatedAt); + } + + [Fact] + public void LoadJsonInput() + { + string jsonData = """ +{ + "id": "chk_abc123", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "checkpointNumber": 3, + "title": "Added harness contracts", + "createdAt": "2026-06-09T20:00:00Z" +} +"""; + + var instance = Checkpoint.FromJson(jsonData); + Assert.NotNull(instance); + Assert.Equal("chk_abc123", instance.Id); + Assert.Equal("sess_abc123", instance.SessionId); + Assert.Equal("turn_001", instance.TurnId); + Assert.Equal(3, instance.CheckpointNumber); + Assert.Equal("Added harness contracts", instance.Title); + Assert.Equal("2026-06-09T20:00:00Z", instance.CreatedAt); + } + + [Fact] + public void RoundtripJson() + { + // Test that FromJson -> ToJson -> FromJson produces equivalent data + string jsonData = """ +{ + "id": "chk_abc123", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "checkpointNumber": 3, + "title": "Added harness contracts", + "createdAt": "2026-06-09T20:00:00Z" +} +"""; + + var original = Checkpoint.FromJson(jsonData); + Assert.NotNull(original); + + var json = original.ToJson(); + Assert.False(string.IsNullOrEmpty(json)); + + var reloaded = Checkpoint.FromJson(json); + Assert.NotNull(reloaded); + Assert.Equal("chk_abc123", reloaded.Id); + Assert.Equal("sess_abc123", reloaded.SessionId); + Assert.Equal("turn_001", reloaded.TurnId); + Assert.Equal(3, reloaded.CheckpointNumber); + Assert.Equal("Added harness contracts", reloaded.Title); + Assert.Equal("2026-06-09T20:00:00Z", reloaded.CreatedAt); + } + + [Fact] + public void RoundtripYaml() + { + // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data + string yamlData = """ +id: chk_abc123 +sessionId: sess_abc123 +turnId: turn_001 +checkpointNumber: 3 +title: Added harness contracts +createdAt: "2026-06-09T20:00:00Z" + +"""; + + var original = Checkpoint.FromYaml(yamlData); + Assert.NotNull(original); + + var yaml = original.ToYaml(); + Assert.False(string.IsNullOrEmpty(yaml)); + + var reloaded = Checkpoint.FromYaml(yaml); + Assert.NotNull(reloaded); + Assert.Equal("chk_abc123", reloaded.Id); + Assert.Equal("sess_abc123", reloaded.SessionId); + Assert.Equal("turn_001", reloaded.TurnId); + Assert.Equal(3, reloaded.CheckpointNumber); + Assert.Equal("Added harness contracts", reloaded.Title); + Assert.Equal("2026-06-09T20:00:00Z", reloaded.CreatedAt); + } + + [Fact] + public void ToJsonProducesValidJson() + { + string jsonData = """ +{ + "id": "chk_abc123", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "checkpointNumber": 3, + "title": "Added harness contracts", + "createdAt": "2026-06-09T20:00:00Z" +} +"""; + + var instance = Checkpoint.FromJson(jsonData); + var json = instance.ToJson(); + + // Verify it's valid JSON by parsing it + var parsed = System.Text.Json.JsonDocument.Parse(json); + Assert.NotNull(parsed); + } + + [Fact] + public void ToYamlProducesValidYaml() + { + string yamlData = """ +id: chk_abc123 +sessionId: sess_abc123 +turnId: turn_001 +checkpointNumber: 3 +title: Added harness contracts +createdAt: "2026-06-09T20:00:00Z" + +"""; + + var instance = Checkpoint.FromYaml(yamlData); + var yaml = instance.ToYaml(); + + // Verify it's valid YAML by parsing it + var deserializer = new YamlDotNet.Serialization.DeserializerBuilder().Build(); + var parsed = deserializer.Deserialize(yaml); + Assert.NotNull(parsed); + } +} diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/HarnessContextConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/HarnessContextConversionTests.cs new file mode 100644 index 00000000..456b09e6 --- /dev/null +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/HarnessContextConversionTests.cs @@ -0,0 +1,122 @@ +using Xunit; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + + +public class HarnessContextConversionTests +{ + [Fact] + public void LoadYamlInput() + { + string yamlData = """ +cwd: /workspace/project +gitRoot: /workspace/project + +"""; + + var instance = HarnessContext.FromYaml(yamlData); + + Assert.NotNull(instance); + Assert.Equal("/workspace/project", instance.Cwd); + Assert.Equal("/workspace/project", instance.GitRoot); + } + + [Fact] + public void LoadJsonInput() + { + string jsonData = """ +{ + "cwd": "/workspace/project", + "gitRoot": "/workspace/project" +} +"""; + + var instance = HarnessContext.FromJson(jsonData); + Assert.NotNull(instance); + Assert.Equal("/workspace/project", instance.Cwd); + Assert.Equal("/workspace/project", instance.GitRoot); + } + + [Fact] + public void RoundtripJson() + { + // Test that FromJson -> ToJson -> FromJson produces equivalent data + string jsonData = """ +{ + "cwd": "/workspace/project", + "gitRoot": "/workspace/project" +} +"""; + + var original = HarnessContext.FromJson(jsonData); + Assert.NotNull(original); + + var json = original.ToJson(); + Assert.False(string.IsNullOrEmpty(json)); + + var reloaded = HarnessContext.FromJson(json); + Assert.NotNull(reloaded); + Assert.Equal("/workspace/project", reloaded.Cwd); + Assert.Equal("/workspace/project", reloaded.GitRoot); + } + + [Fact] + public void RoundtripYaml() + { + // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data + string yamlData = """ +cwd: /workspace/project +gitRoot: /workspace/project + +"""; + + var original = HarnessContext.FromYaml(yamlData); + Assert.NotNull(original); + + var yaml = original.ToYaml(); + Assert.False(string.IsNullOrEmpty(yaml)); + + var reloaded = HarnessContext.FromYaml(yaml); + Assert.NotNull(reloaded); + Assert.Equal("/workspace/project", reloaded.Cwd); + Assert.Equal("/workspace/project", reloaded.GitRoot); + } + + [Fact] + public void ToJsonProducesValidJson() + { + string jsonData = """ +{ + "cwd": "/workspace/project", + "gitRoot": "/workspace/project" +} +"""; + + var instance = HarnessContext.FromJson(jsonData); + var json = instance.ToJson(); + + // Verify it's valid JSON by parsing it + var parsed = System.Text.Json.JsonDocument.Parse(json); + Assert.NotNull(parsed); + } + + [Fact] + public void ToYamlProducesValidYaml() + { + string yamlData = """ +cwd: /workspace/project +gitRoot: /workspace/project + +"""; + + var instance = HarnessContext.FromYaml(yamlData); + var yaml = instance.ToYaml(); + + // Verify it's valid YAML by parsing it + var deserializer = new YamlDotNet.Serialization.DeserializerBuilder().Build(); + var parsed = deserializer.Deserialize(yaml); + Assert.NotNull(parsed); + } +} diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/HookEndPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/HookEndPayloadConversionTests.cs new file mode 100644 index 00000000..1db0fbf4 --- /dev/null +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/HookEndPayloadConversionTests.cs @@ -0,0 +1,152 @@ +using Xunit; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + + +public class HookEndPayloadConversionTests +{ + [Fact] + public void LoadYamlInput() + { + string yamlData = """ +hookInvocationId: hook_abc123 +hookType: preToolUse +success: true +durationMs: 12 +error: hook failed + +"""; + + var instance = HookEndPayload.FromYaml(yamlData); + + Assert.NotNull(instance); + Assert.Equal("hook_abc123", instance.HookInvocationId); + Assert.Equal("preToolUse", instance.HookType); + Assert.True(instance.Success); + Assert.Equal(12, instance.DurationMs); + Assert.Equal("hook failed", instance.Error); + } + + [Fact] + public void LoadJsonInput() + { + string jsonData = """ +{ + "hookInvocationId": "hook_abc123", + "hookType": "preToolUse", + "success": true, + "durationMs": 12, + "error": "hook failed" +} +"""; + + var instance = HookEndPayload.FromJson(jsonData); + Assert.NotNull(instance); + Assert.Equal("hook_abc123", instance.HookInvocationId); + Assert.Equal("preToolUse", instance.HookType); + Assert.True(instance.Success); + Assert.Equal(12, instance.DurationMs); + Assert.Equal("hook failed", instance.Error); + } + + [Fact] + public void RoundtripJson() + { + // Test that FromJson -> ToJson -> FromJson produces equivalent data + string jsonData = """ +{ + "hookInvocationId": "hook_abc123", + "hookType": "preToolUse", + "success": true, + "durationMs": 12, + "error": "hook failed" +} +"""; + + var original = HookEndPayload.FromJson(jsonData); + Assert.NotNull(original); + + var json = original.ToJson(); + Assert.False(string.IsNullOrEmpty(json)); + + var reloaded = HookEndPayload.FromJson(json); + Assert.NotNull(reloaded); + Assert.Equal("hook_abc123", reloaded.HookInvocationId); + Assert.Equal("preToolUse", reloaded.HookType); + Assert.True(reloaded.Success); + Assert.Equal(12, reloaded.DurationMs); + Assert.Equal("hook failed", reloaded.Error); + } + + [Fact] + public void RoundtripYaml() + { + // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data + string yamlData = """ +hookInvocationId: hook_abc123 +hookType: preToolUse +success: true +durationMs: 12 +error: hook failed + +"""; + + var original = HookEndPayload.FromYaml(yamlData); + Assert.NotNull(original); + + var yaml = original.ToYaml(); + Assert.False(string.IsNullOrEmpty(yaml)); + + var reloaded = HookEndPayload.FromYaml(yaml); + Assert.NotNull(reloaded); + Assert.Equal("hook_abc123", reloaded.HookInvocationId); + Assert.Equal("preToolUse", reloaded.HookType); + Assert.True(reloaded.Success); + Assert.Equal(12, reloaded.DurationMs); + Assert.Equal("hook failed", reloaded.Error); + } + + [Fact] + public void ToJsonProducesValidJson() + { + string jsonData = """ +{ + "hookInvocationId": "hook_abc123", + "hookType": "preToolUse", + "success": true, + "durationMs": 12, + "error": "hook failed" +} +"""; + + var instance = HookEndPayload.FromJson(jsonData); + var json = instance.ToJson(); + + // Verify it's valid JSON by parsing it + var parsed = System.Text.Json.JsonDocument.Parse(json); + Assert.NotNull(parsed); + } + + [Fact] + public void ToYamlProducesValidYaml() + { + string yamlData = """ +hookInvocationId: hook_abc123 +hookType: preToolUse +success: true +durationMs: 12 +error: hook failed + +"""; + + var instance = HookEndPayload.FromYaml(yamlData); + var yaml = instance.ToYaml(); + + // Verify it's valid YAML by parsing it + var deserializer = new YamlDotNet.Serialization.DeserializerBuilder().Build(); + var parsed = deserializer.Deserialize(yaml); + Assert.NotNull(parsed); + } +} diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/HookStartPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/HookStartPayloadConversionTests.cs new file mode 100644 index 00000000..eea9705f --- /dev/null +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/HookStartPayloadConversionTests.cs @@ -0,0 +1,122 @@ +using Xunit; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + + +public class HookStartPayloadConversionTests +{ + [Fact] + public void LoadYamlInput() + { + string yamlData = """ +hookInvocationId: hook_abc123 +hookType: preToolUse + +"""; + + var instance = HookStartPayload.FromYaml(yamlData); + + Assert.NotNull(instance); + Assert.Equal("hook_abc123", instance.HookInvocationId); + Assert.Equal("preToolUse", instance.HookType); + } + + [Fact] + public void LoadJsonInput() + { + string jsonData = """ +{ + "hookInvocationId": "hook_abc123", + "hookType": "preToolUse" +} +"""; + + var instance = HookStartPayload.FromJson(jsonData); + Assert.NotNull(instance); + Assert.Equal("hook_abc123", instance.HookInvocationId); + Assert.Equal("preToolUse", instance.HookType); + } + + [Fact] + public void RoundtripJson() + { + // Test that FromJson -> ToJson -> FromJson produces equivalent data + string jsonData = """ +{ + "hookInvocationId": "hook_abc123", + "hookType": "preToolUse" +} +"""; + + var original = HookStartPayload.FromJson(jsonData); + Assert.NotNull(original); + + var json = original.ToJson(); + Assert.False(string.IsNullOrEmpty(json)); + + var reloaded = HookStartPayload.FromJson(json); + Assert.NotNull(reloaded); + Assert.Equal("hook_abc123", reloaded.HookInvocationId); + Assert.Equal("preToolUse", reloaded.HookType); + } + + [Fact] + public void RoundtripYaml() + { + // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data + string yamlData = """ +hookInvocationId: hook_abc123 +hookType: preToolUse + +"""; + + var original = HookStartPayload.FromYaml(yamlData); + Assert.NotNull(original); + + var yaml = original.ToYaml(); + Assert.False(string.IsNullOrEmpty(yaml)); + + var reloaded = HookStartPayload.FromYaml(yaml); + Assert.NotNull(reloaded); + Assert.Equal("hook_abc123", reloaded.HookInvocationId); + Assert.Equal("preToolUse", reloaded.HookType); + } + + [Fact] + public void ToJsonProducesValidJson() + { + string jsonData = """ +{ + "hookInvocationId": "hook_abc123", + "hookType": "preToolUse" +} +"""; + + var instance = HookStartPayload.FromJson(jsonData); + var json = instance.ToJson(); + + // Verify it's valid JSON by parsing it + var parsed = System.Text.Json.JsonDocument.Parse(json); + Assert.NotNull(parsed); + } + + [Fact] + public void ToYamlProducesValidYaml() + { + string yamlData = """ +hookInvocationId: hook_abc123 +hookType: preToolUse + +"""; + + var instance = HookStartPayload.FromYaml(yamlData); + var yaml = instance.ToYaml(); + + // Verify it's valid YAML by parsing it + var deserializer = new YamlDotNet.Serialization.DeserializerBuilder().Build(); + var parsed = deserializer.Deserialize(yaml); + Assert.NotNull(parsed); + } +} diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/HostToolRequestConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/HostToolRequestConversionTests.cs new file mode 100644 index 00000000..1aa26c39 --- /dev/null +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/HostToolRequestConversionTests.cs @@ -0,0 +1,142 @@ +using Xunit; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + + +public class HostToolRequestConversionTests +{ + [Fact] + public void LoadYamlInput() + { + string yamlData = """ +requestId: exec_abc123 +toolCallId: call_abc123 +toolName: powershell +workingDirectory: /workspace/project + +"""; + + var instance = HostToolRequest.FromYaml(yamlData); + + Assert.NotNull(instance); + Assert.Equal("exec_abc123", instance.RequestId); + Assert.Equal("call_abc123", instance.ToolCallId); + Assert.Equal("powershell", instance.ToolName); + Assert.Equal("/workspace/project", instance.WorkingDirectory); + } + + [Fact] + public void LoadJsonInput() + { + string jsonData = """ +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "workingDirectory": "/workspace/project" +} +"""; + + var instance = HostToolRequest.FromJson(jsonData); + Assert.NotNull(instance); + Assert.Equal("exec_abc123", instance.RequestId); + Assert.Equal("call_abc123", instance.ToolCallId); + Assert.Equal("powershell", instance.ToolName); + Assert.Equal("/workspace/project", instance.WorkingDirectory); + } + + [Fact] + public void RoundtripJson() + { + // Test that FromJson -> ToJson -> FromJson produces equivalent data + string jsonData = """ +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "workingDirectory": "/workspace/project" +} +"""; + + var original = HostToolRequest.FromJson(jsonData); + Assert.NotNull(original); + + var json = original.ToJson(); + Assert.False(string.IsNullOrEmpty(json)); + + var reloaded = HostToolRequest.FromJson(json); + Assert.NotNull(reloaded); + Assert.Equal("exec_abc123", reloaded.RequestId); + Assert.Equal("call_abc123", reloaded.ToolCallId); + Assert.Equal("powershell", reloaded.ToolName); + Assert.Equal("/workspace/project", reloaded.WorkingDirectory); + } + + [Fact] + public void RoundtripYaml() + { + // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data + string yamlData = """ +requestId: exec_abc123 +toolCallId: call_abc123 +toolName: powershell +workingDirectory: /workspace/project + +"""; + + var original = HostToolRequest.FromYaml(yamlData); + Assert.NotNull(original); + + var yaml = original.ToYaml(); + Assert.False(string.IsNullOrEmpty(yaml)); + + var reloaded = HostToolRequest.FromYaml(yaml); + Assert.NotNull(reloaded); + Assert.Equal("exec_abc123", reloaded.RequestId); + Assert.Equal("call_abc123", reloaded.ToolCallId); + Assert.Equal("powershell", reloaded.ToolName); + Assert.Equal("/workspace/project", reloaded.WorkingDirectory); + } + + [Fact] + public void ToJsonProducesValidJson() + { + string jsonData = """ +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "workingDirectory": "/workspace/project" +} +"""; + + var instance = HostToolRequest.FromJson(jsonData); + var json = instance.ToJson(); + + // Verify it's valid JSON by parsing it + var parsed = System.Text.Json.JsonDocument.Parse(json); + Assert.NotNull(parsed); + } + + [Fact] + public void ToYamlProducesValidYaml() + { + string yamlData = """ +requestId: exec_abc123 +toolCallId: call_abc123 +toolName: powershell +workingDirectory: /workspace/project + +"""; + + var instance = HostToolRequest.FromYaml(yamlData); + var yaml = instance.ToYaml(); + + // Verify it's valid YAML by parsing it + var deserializer = new YamlDotNet.Serialization.DeserializerBuilder().Build(); + var parsed = deserializer.Deserialize(yaml); + Assert.NotNull(parsed); + } +} diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/HostToolResultConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/HostToolResultConversionTests.cs new file mode 100644 index 00000000..babf8990 --- /dev/null +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/HostToolResultConversionTests.cs @@ -0,0 +1,172 @@ +using Xunit; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + + +public class HostToolResultConversionTests +{ + [Fact] + public void LoadYamlInput() + { + string yamlData = """ +requestId: exec_abc123 +toolCallId: call_abc123 +toolName: powershell +success: true +exitCode: 0 +durationMs: 250 +errorKind: timeout + +"""; + + var instance = HostToolResult.FromYaml(yamlData); + + Assert.NotNull(instance); + Assert.Equal("exec_abc123", instance.RequestId); + Assert.Equal("call_abc123", instance.ToolCallId); + Assert.Equal("powershell", instance.ToolName); + Assert.True(instance.Success); + Assert.Equal(0, instance.ExitCode); + Assert.Equal(250, instance.DurationMs); + Assert.Equal("timeout", instance.ErrorKind); + } + + [Fact] + public void LoadJsonInput() + { + string jsonData = """ +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "success": true, + "exitCode": 0, + "durationMs": 250, + "errorKind": "timeout" +} +"""; + + var instance = HostToolResult.FromJson(jsonData); + Assert.NotNull(instance); + Assert.Equal("exec_abc123", instance.RequestId); + Assert.Equal("call_abc123", instance.ToolCallId); + Assert.Equal("powershell", instance.ToolName); + Assert.True(instance.Success); + Assert.Equal(0, instance.ExitCode); + Assert.Equal(250, instance.DurationMs); + Assert.Equal("timeout", instance.ErrorKind); + } + + [Fact] + public void RoundtripJson() + { + // Test that FromJson -> ToJson -> FromJson produces equivalent data + string jsonData = """ +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "success": true, + "exitCode": 0, + "durationMs": 250, + "errorKind": "timeout" +} +"""; + + var original = HostToolResult.FromJson(jsonData); + Assert.NotNull(original); + + var json = original.ToJson(); + Assert.False(string.IsNullOrEmpty(json)); + + var reloaded = HostToolResult.FromJson(json); + Assert.NotNull(reloaded); + Assert.Equal("exec_abc123", reloaded.RequestId); + Assert.Equal("call_abc123", reloaded.ToolCallId); + Assert.Equal("powershell", reloaded.ToolName); + Assert.True(reloaded.Success); + Assert.Equal(0, reloaded.ExitCode); + Assert.Equal(250, reloaded.DurationMs); + Assert.Equal("timeout", reloaded.ErrorKind); + } + + [Fact] + public void RoundtripYaml() + { + // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data + string yamlData = """ +requestId: exec_abc123 +toolCallId: call_abc123 +toolName: powershell +success: true +exitCode: 0 +durationMs: 250 +errorKind: timeout + +"""; + + var original = HostToolResult.FromYaml(yamlData); + Assert.NotNull(original); + + var yaml = original.ToYaml(); + Assert.False(string.IsNullOrEmpty(yaml)); + + var reloaded = HostToolResult.FromYaml(yaml); + Assert.NotNull(reloaded); + Assert.Equal("exec_abc123", reloaded.RequestId); + Assert.Equal("call_abc123", reloaded.ToolCallId); + Assert.Equal("powershell", reloaded.ToolName); + Assert.True(reloaded.Success); + Assert.Equal(0, reloaded.ExitCode); + Assert.Equal(250, reloaded.DurationMs); + Assert.Equal("timeout", reloaded.ErrorKind); + } + + [Fact] + public void ToJsonProducesValidJson() + { + string jsonData = """ +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "success": true, + "exitCode": 0, + "durationMs": 250, + "errorKind": "timeout" +} +"""; + + var instance = HostToolResult.FromJson(jsonData); + var json = instance.ToJson(); + + // Verify it's valid JSON by parsing it + var parsed = System.Text.Json.JsonDocument.Parse(json); + Assert.NotNull(parsed); + } + + [Fact] + public void ToYamlProducesValidYaml() + { + string yamlData = """ +requestId: exec_abc123 +toolCallId: call_abc123 +toolName: powershell +success: true +exitCode: 0 +durationMs: 250 +errorKind: timeout + +"""; + + var instance = HostToolResult.FromYaml(yamlData); + var yaml = instance.ToYaml(); + + // Verify it's valid YAML by parsing it + var deserializer = new YamlDotNet.Serialization.DeserializerBuilder().Build(); + var parsed = deserializer.Deserialize(yaml); + Assert.NotNull(parsed); + } +} diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/PermissionCompletedPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/PermissionCompletedPayloadConversionTests.cs index e64a1470..a99391bd 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/PermissionCompletedPayloadConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/PermissionCompletedPayloadConversionTests.cs @@ -11,6 +11,8 @@ public class PermissionCompletedPayloadConversionTests public void LoadYamlInput() { string yamlData = """ +requestId: perm_abc123 +toolCallId: call_abc123 permission: tool.execute approved: true reason: user_approved @@ -20,6 +22,8 @@ public void LoadYamlInput() var instance = PermissionCompletedPayload.FromYaml(yamlData); Assert.NotNull(instance); + Assert.Equal("perm_abc123", instance.RequestId); + Assert.Equal("call_abc123", instance.ToolCallId); Assert.Equal("tool.execute", instance.Permission); Assert.True(instance.Approved); Assert.Equal("user_approved", instance.Reason); @@ -30,6 +34,8 @@ public void LoadJsonInput() { string jsonData = """ { + "requestId": "perm_abc123", + "toolCallId": "call_abc123", "permission": "tool.execute", "approved": true, "reason": "user_approved" @@ -38,6 +44,8 @@ public void LoadJsonInput() var instance = PermissionCompletedPayload.FromJson(jsonData); Assert.NotNull(instance); + Assert.Equal("perm_abc123", instance.RequestId); + Assert.Equal("call_abc123", instance.ToolCallId); Assert.Equal("tool.execute", instance.Permission); Assert.True(instance.Approved); Assert.Equal("user_approved", instance.Reason); @@ -49,6 +57,8 @@ public void RoundtripJson() // Test that FromJson -> ToJson -> FromJson produces equivalent data string jsonData = """ { + "requestId": "perm_abc123", + "toolCallId": "call_abc123", "permission": "tool.execute", "approved": true, "reason": "user_approved" @@ -63,6 +73,8 @@ public void RoundtripJson() var reloaded = PermissionCompletedPayload.FromJson(json); Assert.NotNull(reloaded); + Assert.Equal("perm_abc123", reloaded.RequestId); + Assert.Equal("call_abc123", reloaded.ToolCallId); Assert.Equal("tool.execute", reloaded.Permission); Assert.True(reloaded.Approved); Assert.Equal("user_approved", reloaded.Reason); @@ -73,6 +85,8 @@ public void RoundtripYaml() { // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data string yamlData = """ +requestId: perm_abc123 +toolCallId: call_abc123 permission: tool.execute approved: true reason: user_approved @@ -87,6 +101,8 @@ public void RoundtripYaml() var reloaded = PermissionCompletedPayload.FromYaml(yaml); Assert.NotNull(reloaded); + Assert.Equal("perm_abc123", reloaded.RequestId); + Assert.Equal("call_abc123", reloaded.ToolCallId); Assert.Equal("tool.execute", reloaded.Permission); Assert.True(reloaded.Approved); Assert.Equal("user_approved", reloaded.Reason); @@ -97,6 +113,8 @@ public void ToJsonProducesValidJson() { string jsonData = """ { + "requestId": "perm_abc123", + "toolCallId": "call_abc123", "permission": "tool.execute", "approved": true, "reason": "user_approved" @@ -115,6 +133,8 @@ public void ToJsonProducesValidJson() public void ToYamlProducesValidYaml() { string yamlData = """ +requestId: perm_abc123 +toolCallId: call_abc123 permission: tool.execute approved: true reason: user_approved diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/PermissionDecisionConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/PermissionDecisionConversionTests.cs new file mode 100644 index 00000000..4b7c5d0f --- /dev/null +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/PermissionDecisionConversionTests.cs @@ -0,0 +1,152 @@ +using Xunit; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + + +public class PermissionDecisionConversionTests +{ + [Fact] + public void LoadYamlInput() + { + string yamlData = """ +requestId: perm_abc123 +toolCallId: call_abc123 +permission: tool.execute +approved: true +reason: user_approved + +"""; + + var instance = PermissionDecision.FromYaml(yamlData); + + Assert.NotNull(instance); + Assert.Equal("perm_abc123", instance.RequestId); + Assert.Equal("call_abc123", instance.ToolCallId); + Assert.Equal("tool.execute", instance.Permission); + Assert.True(instance.Approved); + Assert.Equal("user_approved", instance.Reason); + } + + [Fact] + public void LoadJsonInput() + { + string jsonData = """ +{ + "requestId": "perm_abc123", + "toolCallId": "call_abc123", + "permission": "tool.execute", + "approved": true, + "reason": "user_approved" +} +"""; + + var instance = PermissionDecision.FromJson(jsonData); + Assert.NotNull(instance); + Assert.Equal("perm_abc123", instance.RequestId); + Assert.Equal("call_abc123", instance.ToolCallId); + Assert.Equal("tool.execute", instance.Permission); + Assert.True(instance.Approved); + Assert.Equal("user_approved", instance.Reason); + } + + [Fact] + public void RoundtripJson() + { + // Test that FromJson -> ToJson -> FromJson produces equivalent data + string jsonData = """ +{ + "requestId": "perm_abc123", + "toolCallId": "call_abc123", + "permission": "tool.execute", + "approved": true, + "reason": "user_approved" +} +"""; + + var original = PermissionDecision.FromJson(jsonData); + Assert.NotNull(original); + + var json = original.ToJson(); + Assert.False(string.IsNullOrEmpty(json)); + + var reloaded = PermissionDecision.FromJson(json); + Assert.NotNull(reloaded); + Assert.Equal("perm_abc123", reloaded.RequestId); + Assert.Equal("call_abc123", reloaded.ToolCallId); + Assert.Equal("tool.execute", reloaded.Permission); + Assert.True(reloaded.Approved); + Assert.Equal("user_approved", reloaded.Reason); + } + + [Fact] + public void RoundtripYaml() + { + // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data + string yamlData = """ +requestId: perm_abc123 +toolCallId: call_abc123 +permission: tool.execute +approved: true +reason: user_approved + +"""; + + var original = PermissionDecision.FromYaml(yamlData); + Assert.NotNull(original); + + var yaml = original.ToYaml(); + Assert.False(string.IsNullOrEmpty(yaml)); + + var reloaded = PermissionDecision.FromYaml(yaml); + Assert.NotNull(reloaded); + Assert.Equal("perm_abc123", reloaded.RequestId); + Assert.Equal("call_abc123", reloaded.ToolCallId); + Assert.Equal("tool.execute", reloaded.Permission); + Assert.True(reloaded.Approved); + Assert.Equal("user_approved", reloaded.Reason); + } + + [Fact] + public void ToJsonProducesValidJson() + { + string jsonData = """ +{ + "requestId": "perm_abc123", + "toolCallId": "call_abc123", + "permission": "tool.execute", + "approved": true, + "reason": "user_approved" +} +"""; + + var instance = PermissionDecision.FromJson(jsonData); + var json = instance.ToJson(); + + // Verify it's valid JSON by parsing it + var parsed = System.Text.Json.JsonDocument.Parse(json); + Assert.NotNull(parsed); + } + + [Fact] + public void ToYamlProducesValidYaml() + { + string yamlData = """ +requestId: perm_abc123 +toolCallId: call_abc123 +permission: tool.execute +approved: true +reason: user_approved + +"""; + + var instance = PermissionDecision.FromYaml(yamlData); + var yaml = instance.ToYaml(); + + // Verify it's valid YAML by parsing it + var deserializer = new YamlDotNet.Serialization.DeserializerBuilder().Build(); + var parsed = deserializer.Deserialize(yaml); + Assert.NotNull(parsed); + } +} diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/PermissionRequestConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/PermissionRequestConversionTests.cs new file mode 100644 index 00000000..b12e6dcb --- /dev/null +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/PermissionRequestConversionTests.cs @@ -0,0 +1,152 @@ +using Xunit; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + + +public class PermissionRequestConversionTests +{ + [Fact] + public void LoadYamlInput() + { + string yamlData = """ +requestId: perm_abc123 +toolCallId: call_abc123 +permission: tool.execute +target: shell +promptRequest: Allow shell to run tests? + +"""; + + var instance = PermissionRequest.FromYaml(yamlData); + + Assert.NotNull(instance); + Assert.Equal("perm_abc123", instance.RequestId); + Assert.Equal("call_abc123", instance.ToolCallId); + Assert.Equal("tool.execute", instance.Permission); + Assert.Equal("shell", instance.Target); + Assert.Equal("Allow shell to run tests?", instance.PromptRequest); + } + + [Fact] + public void LoadJsonInput() + { + string jsonData = """ +{ + "requestId": "perm_abc123", + "toolCallId": "call_abc123", + "permission": "tool.execute", + "target": "shell", + "promptRequest": "Allow shell to run tests?" +} +"""; + + var instance = PermissionRequest.FromJson(jsonData); + Assert.NotNull(instance); + Assert.Equal("perm_abc123", instance.RequestId); + Assert.Equal("call_abc123", instance.ToolCallId); + Assert.Equal("tool.execute", instance.Permission); + Assert.Equal("shell", instance.Target); + Assert.Equal("Allow shell to run tests?", instance.PromptRequest); + } + + [Fact] + public void RoundtripJson() + { + // Test that FromJson -> ToJson -> FromJson produces equivalent data + string jsonData = """ +{ + "requestId": "perm_abc123", + "toolCallId": "call_abc123", + "permission": "tool.execute", + "target": "shell", + "promptRequest": "Allow shell to run tests?" +} +"""; + + var original = PermissionRequest.FromJson(jsonData); + Assert.NotNull(original); + + var json = original.ToJson(); + Assert.False(string.IsNullOrEmpty(json)); + + var reloaded = PermissionRequest.FromJson(json); + Assert.NotNull(reloaded); + Assert.Equal("perm_abc123", reloaded.RequestId); + Assert.Equal("call_abc123", reloaded.ToolCallId); + Assert.Equal("tool.execute", reloaded.Permission); + Assert.Equal("shell", reloaded.Target); + Assert.Equal("Allow shell to run tests?", reloaded.PromptRequest); + } + + [Fact] + public void RoundtripYaml() + { + // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data + string yamlData = """ +requestId: perm_abc123 +toolCallId: call_abc123 +permission: tool.execute +target: shell +promptRequest: Allow shell to run tests? + +"""; + + var original = PermissionRequest.FromYaml(yamlData); + Assert.NotNull(original); + + var yaml = original.ToYaml(); + Assert.False(string.IsNullOrEmpty(yaml)); + + var reloaded = PermissionRequest.FromYaml(yaml); + Assert.NotNull(reloaded); + Assert.Equal("perm_abc123", reloaded.RequestId); + Assert.Equal("call_abc123", reloaded.ToolCallId); + Assert.Equal("tool.execute", reloaded.Permission); + Assert.Equal("shell", reloaded.Target); + Assert.Equal("Allow shell to run tests?", reloaded.PromptRequest); + } + + [Fact] + public void ToJsonProducesValidJson() + { + string jsonData = """ +{ + "requestId": "perm_abc123", + "toolCallId": "call_abc123", + "permission": "tool.execute", + "target": "shell", + "promptRequest": "Allow shell to run tests?" +} +"""; + + var instance = PermissionRequest.FromJson(jsonData); + var json = instance.ToJson(); + + // Verify it's valid JSON by parsing it + var parsed = System.Text.Json.JsonDocument.Parse(json); + Assert.NotNull(parsed); + } + + [Fact] + public void ToYamlProducesValidYaml() + { + string yamlData = """ +requestId: perm_abc123 +toolCallId: call_abc123 +permission: tool.execute +target: shell +promptRequest: Allow shell to run tests? + +"""; + + var instance = PermissionRequest.FromYaml(yamlData); + var yaml = instance.ToYaml(); + + // Verify it's valid YAML by parsing it + var deserializer = new YamlDotNet.Serialization.DeserializerBuilder().Build(); + var parsed = deserializer.Deserialize(yaml); + Assert.NotNull(parsed); + } +} diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/PermissionRequestedPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/PermissionRequestedPayloadConversionTests.cs index cbcef536..64cd5d0d 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/PermissionRequestedPayloadConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/PermissionRequestedPayloadConversionTests.cs @@ -11,16 +11,22 @@ public class PermissionRequestedPayloadConversionTests public void LoadYamlInput() { string yamlData = """ +requestId: perm_abc123 +toolCallId: call_abc123 permission: tool.execute target: shell +promptRequest: Allow shell to run tests? """; var instance = PermissionRequestedPayload.FromYaml(yamlData); Assert.NotNull(instance); + Assert.Equal("perm_abc123", instance.RequestId); + Assert.Equal("call_abc123", instance.ToolCallId); Assert.Equal("tool.execute", instance.Permission); Assert.Equal("shell", instance.Target); + Assert.Equal("Allow shell to run tests?", instance.PromptRequest); } [Fact] @@ -28,15 +34,21 @@ public void LoadJsonInput() { string jsonData = """ { + "requestId": "perm_abc123", + "toolCallId": "call_abc123", "permission": "tool.execute", - "target": "shell" + "target": "shell", + "promptRequest": "Allow shell to run tests?" } """; var instance = PermissionRequestedPayload.FromJson(jsonData); Assert.NotNull(instance); + Assert.Equal("perm_abc123", instance.RequestId); + Assert.Equal("call_abc123", instance.ToolCallId); Assert.Equal("tool.execute", instance.Permission); Assert.Equal("shell", instance.Target); + Assert.Equal("Allow shell to run tests?", instance.PromptRequest); } [Fact] @@ -45,8 +57,11 @@ public void RoundtripJson() // Test that FromJson -> ToJson -> FromJson produces equivalent data string jsonData = """ { + "requestId": "perm_abc123", + "toolCallId": "call_abc123", "permission": "tool.execute", - "target": "shell" + "target": "shell", + "promptRequest": "Allow shell to run tests?" } """; @@ -58,8 +73,11 @@ public void RoundtripJson() var reloaded = PermissionRequestedPayload.FromJson(json); Assert.NotNull(reloaded); + Assert.Equal("perm_abc123", reloaded.RequestId); + Assert.Equal("call_abc123", reloaded.ToolCallId); Assert.Equal("tool.execute", reloaded.Permission); Assert.Equal("shell", reloaded.Target); + Assert.Equal("Allow shell to run tests?", reloaded.PromptRequest); } [Fact] @@ -67,8 +85,11 @@ public void RoundtripYaml() { // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data string yamlData = """ +requestId: perm_abc123 +toolCallId: call_abc123 permission: tool.execute target: shell +promptRequest: Allow shell to run tests? """; @@ -80,8 +101,11 @@ public void RoundtripYaml() var reloaded = PermissionRequestedPayload.FromYaml(yaml); Assert.NotNull(reloaded); + Assert.Equal("perm_abc123", reloaded.RequestId); + Assert.Equal("call_abc123", reloaded.ToolCallId); Assert.Equal("tool.execute", reloaded.Permission); Assert.Equal("shell", reloaded.Target); + Assert.Equal("Allow shell to run tests?", reloaded.PromptRequest); } [Fact] @@ -89,8 +113,11 @@ public void ToJsonProducesValidJson() { string jsonData = """ { + "requestId": "perm_abc123", + "toolCallId": "call_abc123", "permission": "tool.execute", - "target": "shell" + "target": "shell", + "promptRequest": "Allow shell to run tests?" } """; @@ -106,8 +133,11 @@ public void ToJsonProducesValidJson() public void ToYamlProducesValidYaml() { string yamlData = """ +requestId: perm_abc123 +toolCallId: call_abc123 permission: tool.execute target: shell +promptRequest: Allow shell to run tests? """; diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/RedactedFieldConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/RedactedFieldConversionTests.cs new file mode 100644 index 00000000..64bedd49 --- /dev/null +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/RedactedFieldConversionTests.cs @@ -0,0 +1,132 @@ +using Xunit; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + + +public class RedactedFieldConversionTests +{ + [Fact] + public void LoadYamlInput() + { + string yamlData = """ +path: $.arguments.apiKey +mode: redacted +reason: secret + +"""; + + var instance = RedactedField.FromYaml(yamlData); + + Assert.NotNull(instance); + Assert.Equal("$.arguments.apiKey", instance.Path); + Assert.Equal(RedactionMode.Redacted, instance.Mode); + Assert.Equal("secret", instance.Reason); + } + + [Fact] + public void LoadJsonInput() + { + string jsonData = """ +{ + "path": "$.arguments.apiKey", + "mode": "redacted", + "reason": "secret" +} +"""; + + var instance = RedactedField.FromJson(jsonData); + Assert.NotNull(instance); + Assert.Equal("$.arguments.apiKey", instance.Path); + Assert.Equal(RedactionMode.Redacted, instance.Mode); + Assert.Equal("secret", instance.Reason); + } + + [Fact] + public void RoundtripJson() + { + // Test that FromJson -> ToJson -> FromJson produces equivalent data + string jsonData = """ +{ + "path": "$.arguments.apiKey", + "mode": "redacted", + "reason": "secret" +} +"""; + + var original = RedactedField.FromJson(jsonData); + Assert.NotNull(original); + + var json = original.ToJson(); + Assert.False(string.IsNullOrEmpty(json)); + + var reloaded = RedactedField.FromJson(json); + Assert.NotNull(reloaded); + Assert.Equal("$.arguments.apiKey", reloaded.Path); + Assert.Equal(RedactionMode.Redacted, reloaded.Mode); + Assert.Equal("secret", reloaded.Reason); + } + + [Fact] + public void RoundtripYaml() + { + // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data + string yamlData = """ +path: $.arguments.apiKey +mode: redacted +reason: secret + +"""; + + var original = RedactedField.FromYaml(yamlData); + Assert.NotNull(original); + + var yaml = original.ToYaml(); + Assert.False(string.IsNullOrEmpty(yaml)); + + var reloaded = RedactedField.FromYaml(yaml); + Assert.NotNull(reloaded); + Assert.Equal("$.arguments.apiKey", reloaded.Path); + Assert.Equal(RedactionMode.Redacted, reloaded.Mode); + Assert.Equal("secret", reloaded.Reason); + } + + [Fact] + public void ToJsonProducesValidJson() + { + string jsonData = """ +{ + "path": "$.arguments.apiKey", + "mode": "redacted", + "reason": "secret" +} +"""; + + var instance = RedactedField.FromJson(jsonData); + var json = instance.ToJson(); + + // Verify it's valid JSON by parsing it + var parsed = System.Text.Json.JsonDocument.Parse(json); + Assert.NotNull(parsed); + } + + [Fact] + public void ToYamlProducesValidYaml() + { + string yamlData = """ +path: $.arguments.apiKey +mode: redacted +reason: secret + +"""; + + var instance = RedactedField.FromYaml(yamlData); + var yaml = instance.ToYaml(); + + // Verify it's valid YAML by parsing it + var deserializer = new YamlDotNet.Serialization.DeserializerBuilder().Build(); + var parsed = deserializer.Deserialize(yaml); + Assert.NotNull(parsed); + } +} diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/RedactionMetadataConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/RedactionMetadataConversionTests.cs new file mode 100644 index 00000000..26ad0a68 --- /dev/null +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/RedactionMetadataConversionTests.cs @@ -0,0 +1,122 @@ +using Xunit; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + + +public class RedactionMetadataConversionTests +{ + [Fact] + public void LoadYamlInput() + { + string yamlData = """ +sanitized: true +policy: default-v1 + +"""; + + var instance = RedactionMetadata.FromYaml(yamlData); + + Assert.NotNull(instance); + Assert.True(instance.Sanitized); + Assert.Equal("default-v1", instance.Policy); + } + + [Fact] + public void LoadJsonInput() + { + string jsonData = """ +{ + "sanitized": true, + "policy": "default-v1" +} +"""; + + var instance = RedactionMetadata.FromJson(jsonData); + Assert.NotNull(instance); + Assert.True(instance.Sanitized); + Assert.Equal("default-v1", instance.Policy); + } + + [Fact] + public void RoundtripJson() + { + // Test that FromJson -> ToJson -> FromJson produces equivalent data + string jsonData = """ +{ + "sanitized": true, + "policy": "default-v1" +} +"""; + + var original = RedactionMetadata.FromJson(jsonData); + Assert.NotNull(original); + + var json = original.ToJson(); + Assert.False(string.IsNullOrEmpty(json)); + + var reloaded = RedactionMetadata.FromJson(json); + Assert.NotNull(reloaded); + Assert.True(reloaded.Sanitized); + Assert.Equal("default-v1", reloaded.Policy); + } + + [Fact] + public void RoundtripYaml() + { + // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data + string yamlData = """ +sanitized: true +policy: default-v1 + +"""; + + var original = RedactionMetadata.FromYaml(yamlData); + Assert.NotNull(original); + + var yaml = original.ToYaml(); + Assert.False(string.IsNullOrEmpty(yaml)); + + var reloaded = RedactionMetadata.FromYaml(yaml); + Assert.NotNull(reloaded); + Assert.True(reloaded.Sanitized); + Assert.Equal("default-v1", reloaded.Policy); + } + + [Fact] + public void ToJsonProducesValidJson() + { + string jsonData = """ +{ + "sanitized": true, + "policy": "default-v1" +} +"""; + + var instance = RedactionMetadata.FromJson(jsonData); + var json = instance.ToJson(); + + // Verify it's valid JSON by parsing it + var parsed = System.Text.Json.JsonDocument.Parse(json); + Assert.NotNull(parsed); + } + + [Fact] + public void ToYamlProducesValidYaml() + { + string yamlData = """ +sanitized: true +policy: default-v1 + +"""; + + var instance = RedactionMetadata.FromYaml(yamlData); + var yaml = instance.ToYaml(); + + // Verify it's valid YAML by parsing it + var deserializer = new YamlDotNet.Serialization.DeserializerBuilder().Build(); + var parsed = deserializer.Deserialize(yaml); + Assert.NotNull(parsed); + } +} diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/SessionEndPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/SessionEndPayloadConversionTests.cs new file mode 100644 index 00000000..81e97c98 --- /dev/null +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/SessionEndPayloadConversionTests.cs @@ -0,0 +1,142 @@ +using Xunit; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + + +public class SessionEndPayloadConversionTests +{ + [Fact] + public void LoadYamlInput() + { + string yamlData = """ +sessionId: sess_abc123 +status: success +reason: complete +durationMs: 12500 + +"""; + + var instance = SessionEndPayload.FromYaml(yamlData); + + Assert.NotNull(instance); + Assert.Equal("sess_abc123", instance.SessionId); + Assert.Equal(SessionEndStatus.Success, instance.Status); + Assert.Equal("complete", instance.Reason); + Assert.Equal(12500, instance.DurationMs); + } + + [Fact] + public void LoadJsonInput() + { + string jsonData = """ +{ + "sessionId": "sess_abc123", + "status": "success", + "reason": "complete", + "durationMs": 12500 +} +"""; + + var instance = SessionEndPayload.FromJson(jsonData); + Assert.NotNull(instance); + Assert.Equal("sess_abc123", instance.SessionId); + Assert.Equal(SessionEndStatus.Success, instance.Status); + Assert.Equal("complete", instance.Reason); + Assert.Equal(12500, instance.DurationMs); + } + + [Fact] + public void RoundtripJson() + { + // Test that FromJson -> ToJson -> FromJson produces equivalent data + string jsonData = """ +{ + "sessionId": "sess_abc123", + "status": "success", + "reason": "complete", + "durationMs": 12500 +} +"""; + + var original = SessionEndPayload.FromJson(jsonData); + Assert.NotNull(original); + + var json = original.ToJson(); + Assert.False(string.IsNullOrEmpty(json)); + + var reloaded = SessionEndPayload.FromJson(json); + Assert.NotNull(reloaded); + Assert.Equal("sess_abc123", reloaded.SessionId); + Assert.Equal(SessionEndStatus.Success, reloaded.Status); + Assert.Equal("complete", reloaded.Reason); + Assert.Equal(12500, reloaded.DurationMs); + } + + [Fact] + public void RoundtripYaml() + { + // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data + string yamlData = """ +sessionId: sess_abc123 +status: success +reason: complete +durationMs: 12500 + +"""; + + var original = SessionEndPayload.FromYaml(yamlData); + Assert.NotNull(original); + + var yaml = original.ToYaml(); + Assert.False(string.IsNullOrEmpty(yaml)); + + var reloaded = SessionEndPayload.FromYaml(yaml); + Assert.NotNull(reloaded); + Assert.Equal("sess_abc123", reloaded.SessionId); + Assert.Equal(SessionEndStatus.Success, reloaded.Status); + Assert.Equal("complete", reloaded.Reason); + Assert.Equal(12500, reloaded.DurationMs); + } + + [Fact] + public void ToJsonProducesValidJson() + { + string jsonData = """ +{ + "sessionId": "sess_abc123", + "status": "success", + "reason": "complete", + "durationMs": 12500 +} +"""; + + var instance = SessionEndPayload.FromJson(jsonData); + var json = instance.ToJson(); + + // Verify it's valid JSON by parsing it + var parsed = System.Text.Json.JsonDocument.Parse(json); + Assert.NotNull(parsed); + } + + [Fact] + public void ToYamlProducesValidYaml() + { + string yamlData = """ +sessionId: sess_abc123 +status: success +reason: complete +durationMs: 12500 + +"""; + + var instance = SessionEndPayload.FromYaml(yamlData); + var yaml = instance.ToYaml(); + + // Verify it's valid YAML by parsing it + var deserializer = new YamlDotNet.Serialization.DeserializerBuilder().Build(); + var parsed = deserializer.Deserialize(yaml); + Assert.NotNull(parsed); + } +} diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/SessionEventConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/SessionEventConversionTests.cs new file mode 100644 index 00000000..5dfc5057 --- /dev/null +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/SessionEventConversionTests.cs @@ -0,0 +1,162 @@ +using Xunit; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + + +public class SessionEventConversionTests +{ + [Fact] + public void LoadYamlInput() + { + string yamlData = """ +id: evt_abc123 +timestamp: "2026-06-09T20:00:00Z" +sessionId: sess_abc123 +turnId: turn_001 +parentId: evt_parent +spanId: span_hook_001 + +"""; + + var instance = SessionEvent.FromYaml(yamlData); + + Assert.NotNull(instance); + Assert.Equal("evt_abc123", instance.Id); + Assert.Equal("2026-06-09T20:00:00Z", instance.Timestamp); + Assert.Equal("sess_abc123", instance.SessionId); + Assert.Equal("turn_001", instance.TurnId); + Assert.Equal("evt_parent", instance.ParentId); + Assert.Equal("span_hook_001", instance.SpanId); + } + + [Fact] + public void LoadJsonInput() + { + string jsonData = """ +{ + "id": "evt_abc123", + "timestamp": "2026-06-09T20:00:00Z", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "parentId": "evt_parent", + "spanId": "span_hook_001" +} +"""; + + var instance = SessionEvent.FromJson(jsonData); + Assert.NotNull(instance); + Assert.Equal("evt_abc123", instance.Id); + Assert.Equal("2026-06-09T20:00:00Z", instance.Timestamp); + Assert.Equal("sess_abc123", instance.SessionId); + Assert.Equal("turn_001", instance.TurnId); + Assert.Equal("evt_parent", instance.ParentId); + Assert.Equal("span_hook_001", instance.SpanId); + } + + [Fact] + public void RoundtripJson() + { + // Test that FromJson -> ToJson -> FromJson produces equivalent data + string jsonData = """ +{ + "id": "evt_abc123", + "timestamp": "2026-06-09T20:00:00Z", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "parentId": "evt_parent", + "spanId": "span_hook_001" +} +"""; + + var original = SessionEvent.FromJson(jsonData); + Assert.NotNull(original); + + var json = original.ToJson(); + Assert.False(string.IsNullOrEmpty(json)); + + var reloaded = SessionEvent.FromJson(json); + Assert.NotNull(reloaded); + Assert.Equal("evt_abc123", reloaded.Id); + Assert.Equal("2026-06-09T20:00:00Z", reloaded.Timestamp); + Assert.Equal("sess_abc123", reloaded.SessionId); + Assert.Equal("turn_001", reloaded.TurnId); + Assert.Equal("evt_parent", reloaded.ParentId); + Assert.Equal("span_hook_001", reloaded.SpanId); + } + + [Fact] + public void RoundtripYaml() + { + // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data + string yamlData = """ +id: evt_abc123 +timestamp: "2026-06-09T20:00:00Z" +sessionId: sess_abc123 +turnId: turn_001 +parentId: evt_parent +spanId: span_hook_001 + +"""; + + var original = SessionEvent.FromYaml(yamlData); + Assert.NotNull(original); + + var yaml = original.ToYaml(); + Assert.False(string.IsNullOrEmpty(yaml)); + + var reloaded = SessionEvent.FromYaml(yaml); + Assert.NotNull(reloaded); + Assert.Equal("evt_abc123", reloaded.Id); + Assert.Equal("2026-06-09T20:00:00Z", reloaded.Timestamp); + Assert.Equal("sess_abc123", reloaded.SessionId); + Assert.Equal("turn_001", reloaded.TurnId); + Assert.Equal("evt_parent", reloaded.ParentId); + Assert.Equal("span_hook_001", reloaded.SpanId); + } + + [Fact] + public void ToJsonProducesValidJson() + { + string jsonData = """ +{ + "id": "evt_abc123", + "timestamp": "2026-06-09T20:00:00Z", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "parentId": "evt_parent", + "spanId": "span_hook_001" +} +"""; + + var instance = SessionEvent.FromJson(jsonData); + var json = instance.ToJson(); + + // Verify it's valid JSON by parsing it + var parsed = System.Text.Json.JsonDocument.Parse(json); + Assert.NotNull(parsed); + } + + [Fact] + public void ToYamlProducesValidYaml() + { + string yamlData = """ +id: evt_abc123 +timestamp: "2026-06-09T20:00:00Z" +sessionId: sess_abc123 +turnId: turn_001 +parentId: evt_parent +spanId: span_hook_001 + +"""; + + var instance = SessionEvent.FromYaml(yamlData); + var yaml = instance.ToYaml(); + + // Verify it's valid YAML by parsing it + var deserializer = new YamlDotNet.Serialization.DeserializerBuilder().Build(); + var parsed = deserializer.Deserialize(yaml); + Assert.NotNull(parsed); + } +} diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/SessionFileRefConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/SessionFileRefConversionTests.cs new file mode 100644 index 00000000..87ade592 --- /dev/null +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/SessionFileRefConversionTests.cs @@ -0,0 +1,152 @@ +using Xunit; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + + +public class SessionFileRefConversionTests +{ + [Fact] + public void LoadYamlInput() + { + string yamlData = """ +sessionId: sess_abc123 +path: src/index.ts +toolName: view +turnIndex: 2 +firstSeenAt: "2026-06-09T20:00:00Z" + +"""; + + var instance = SessionFileRef.FromYaml(yamlData); + + Assert.NotNull(instance); + Assert.Equal("sess_abc123", instance.SessionId); + Assert.Equal("src/index.ts", instance.Path); + Assert.Equal("view", instance.ToolName); + Assert.Equal(2, instance.TurnIndex); + Assert.Equal("2026-06-09T20:00:00Z", instance.FirstSeenAt); + } + + [Fact] + public void LoadJsonInput() + { + string jsonData = """ +{ + "sessionId": "sess_abc123", + "path": "src/index.ts", + "toolName": "view", + "turnIndex": 2, + "firstSeenAt": "2026-06-09T20:00:00Z" +} +"""; + + var instance = SessionFileRef.FromJson(jsonData); + Assert.NotNull(instance); + Assert.Equal("sess_abc123", instance.SessionId); + Assert.Equal("src/index.ts", instance.Path); + Assert.Equal("view", instance.ToolName); + Assert.Equal(2, instance.TurnIndex); + Assert.Equal("2026-06-09T20:00:00Z", instance.FirstSeenAt); + } + + [Fact] + public void RoundtripJson() + { + // Test that FromJson -> ToJson -> FromJson produces equivalent data + string jsonData = """ +{ + "sessionId": "sess_abc123", + "path": "src/index.ts", + "toolName": "view", + "turnIndex": 2, + "firstSeenAt": "2026-06-09T20:00:00Z" +} +"""; + + var original = SessionFileRef.FromJson(jsonData); + Assert.NotNull(original); + + var json = original.ToJson(); + Assert.False(string.IsNullOrEmpty(json)); + + var reloaded = SessionFileRef.FromJson(json); + Assert.NotNull(reloaded); + Assert.Equal("sess_abc123", reloaded.SessionId); + Assert.Equal("src/index.ts", reloaded.Path); + Assert.Equal("view", reloaded.ToolName); + Assert.Equal(2, reloaded.TurnIndex); + Assert.Equal("2026-06-09T20:00:00Z", reloaded.FirstSeenAt); + } + + [Fact] + public void RoundtripYaml() + { + // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data + string yamlData = """ +sessionId: sess_abc123 +path: src/index.ts +toolName: view +turnIndex: 2 +firstSeenAt: "2026-06-09T20:00:00Z" + +"""; + + var original = SessionFileRef.FromYaml(yamlData); + Assert.NotNull(original); + + var yaml = original.ToYaml(); + Assert.False(string.IsNullOrEmpty(yaml)); + + var reloaded = SessionFileRef.FromYaml(yaml); + Assert.NotNull(reloaded); + Assert.Equal("sess_abc123", reloaded.SessionId); + Assert.Equal("src/index.ts", reloaded.Path); + Assert.Equal("view", reloaded.ToolName); + Assert.Equal(2, reloaded.TurnIndex); + Assert.Equal("2026-06-09T20:00:00Z", reloaded.FirstSeenAt); + } + + [Fact] + public void ToJsonProducesValidJson() + { + string jsonData = """ +{ + "sessionId": "sess_abc123", + "path": "src/index.ts", + "toolName": "view", + "turnIndex": 2, + "firstSeenAt": "2026-06-09T20:00:00Z" +} +"""; + + var instance = SessionFileRef.FromJson(jsonData); + var json = instance.ToJson(); + + // Verify it's valid JSON by parsing it + var parsed = System.Text.Json.JsonDocument.Parse(json); + Assert.NotNull(parsed); + } + + [Fact] + public void ToYamlProducesValidYaml() + { + string yamlData = """ +sessionId: sess_abc123 +path: src/index.ts +toolName: view +turnIndex: 2 +firstSeenAt: "2026-06-09T20:00:00Z" + +"""; + + var instance = SessionFileRef.FromYaml(yamlData); + var yaml = instance.ToYaml(); + + // Verify it's valid YAML by parsing it + var deserializer = new YamlDotNet.Serialization.DeserializerBuilder().Build(); + var parsed = deserializer.Deserialize(yaml); + Assert.NotNull(parsed); + } +} diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/SessionRefConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/SessionRefConversionTests.cs new file mode 100644 index 00000000..7ce209fa --- /dev/null +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/SessionRefConversionTests.cs @@ -0,0 +1,152 @@ +using Xunit; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + + +public class SessionRefConversionTests +{ + [Fact] + public void LoadYamlInput() + { + string yamlData = """ +sessionId: sess_abc123 +refType: issue +refValue: "owner/repo#123" +turnIndex: 2 +createdAt: "2026-06-09T20:00:00Z" + +"""; + + var instance = SessionRef.FromYaml(yamlData); + + Assert.NotNull(instance); + Assert.Equal("sess_abc123", instance.SessionId); + Assert.Equal("issue", instance.RefType); + Assert.Equal("owner/repo#123", instance.RefValue); + Assert.Equal(2, instance.TurnIndex); + Assert.Equal("2026-06-09T20:00:00Z", instance.CreatedAt); + } + + [Fact] + public void LoadJsonInput() + { + string jsonData = """ +{ + "sessionId": "sess_abc123", + "refType": "issue", + "refValue": "owner/repo#123", + "turnIndex": 2, + "createdAt": "2026-06-09T20:00:00Z" +} +"""; + + var instance = SessionRef.FromJson(jsonData); + Assert.NotNull(instance); + Assert.Equal("sess_abc123", instance.SessionId); + Assert.Equal("issue", instance.RefType); + Assert.Equal("owner/repo#123", instance.RefValue); + Assert.Equal(2, instance.TurnIndex); + Assert.Equal("2026-06-09T20:00:00Z", instance.CreatedAt); + } + + [Fact] + public void RoundtripJson() + { + // Test that FromJson -> ToJson -> FromJson produces equivalent data + string jsonData = """ +{ + "sessionId": "sess_abc123", + "refType": "issue", + "refValue": "owner/repo#123", + "turnIndex": 2, + "createdAt": "2026-06-09T20:00:00Z" +} +"""; + + var original = SessionRef.FromJson(jsonData); + Assert.NotNull(original); + + var json = original.ToJson(); + Assert.False(string.IsNullOrEmpty(json)); + + var reloaded = SessionRef.FromJson(json); + Assert.NotNull(reloaded); + Assert.Equal("sess_abc123", reloaded.SessionId); + Assert.Equal("issue", reloaded.RefType); + Assert.Equal("owner/repo#123", reloaded.RefValue); + Assert.Equal(2, reloaded.TurnIndex); + Assert.Equal("2026-06-09T20:00:00Z", reloaded.CreatedAt); + } + + [Fact] + public void RoundtripYaml() + { + // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data + string yamlData = """ +sessionId: sess_abc123 +refType: issue +refValue: "owner/repo#123" +turnIndex: 2 +createdAt: "2026-06-09T20:00:00Z" + +"""; + + var original = SessionRef.FromYaml(yamlData); + Assert.NotNull(original); + + var yaml = original.ToYaml(); + Assert.False(string.IsNullOrEmpty(yaml)); + + var reloaded = SessionRef.FromYaml(yaml); + Assert.NotNull(reloaded); + Assert.Equal("sess_abc123", reloaded.SessionId); + Assert.Equal("issue", reloaded.RefType); + Assert.Equal("owner/repo#123", reloaded.RefValue); + Assert.Equal(2, reloaded.TurnIndex); + Assert.Equal("2026-06-09T20:00:00Z", reloaded.CreatedAt); + } + + [Fact] + public void ToJsonProducesValidJson() + { + string jsonData = """ +{ + "sessionId": "sess_abc123", + "refType": "issue", + "refValue": "owner/repo#123", + "turnIndex": 2, + "createdAt": "2026-06-09T20:00:00Z" +} +"""; + + var instance = SessionRef.FromJson(jsonData); + var json = instance.ToJson(); + + // Verify it's valid JSON by parsing it + var parsed = System.Text.Json.JsonDocument.Parse(json); + Assert.NotNull(parsed); + } + + [Fact] + public void ToYamlProducesValidYaml() + { + string yamlData = """ +sessionId: sess_abc123 +refType: issue +refValue: "owner/repo#123" +turnIndex: 2 +createdAt: "2026-06-09T20:00:00Z" + +"""; + + var instance = SessionRef.FromYaml(yamlData); + var yaml = instance.ToYaml(); + + // Verify it's valid YAML by parsing it + var deserializer = new YamlDotNet.Serialization.DeserializerBuilder().Build(); + var parsed = deserializer.Deserialize(yaml); + Assert.NotNull(parsed); + } +} diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/SessionStartPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/SessionStartPayloadConversionTests.cs new file mode 100644 index 00000000..0b86fb08 --- /dev/null +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/SessionStartPayloadConversionTests.cs @@ -0,0 +1,182 @@ +using Xunit; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + + +public class SessionStartPayloadConversionTests +{ + [Fact] + public void LoadYamlInput() + { + string yamlData = """ +sessionId: sess_abc123 +version: 1 +producer: prompty-agent +runtime: typescript +promptyVersion: 2.0.0 +startTime: "2026-06-09T20:00:00Z" +selectedModel: gpt-4o-mini +reasoningEffort: medium + +"""; + + var instance = SessionStartPayload.FromYaml(yamlData); + + Assert.NotNull(instance); + Assert.Equal("sess_abc123", instance.SessionId); + Assert.Equal(1, instance.Version); + Assert.Equal("prompty-agent", instance.Producer); + Assert.Equal("typescript", instance.Runtime); + Assert.Equal("2.0.0", instance.PromptyVersion); + Assert.Equal("2026-06-09T20:00:00Z", instance.StartTime); + Assert.Equal("gpt-4o-mini", instance.SelectedModel); + Assert.Equal("medium", instance.ReasoningEffort); + } + + [Fact] + public void LoadJsonInput() + { + string jsonData = """ +{ + "sessionId": "sess_abc123", + "version": 1, + "producer": "prompty-agent", + "runtime": "typescript", + "promptyVersion": "2.0.0", + "startTime": "2026-06-09T20:00:00Z", + "selectedModel": "gpt-4o-mini", + "reasoningEffort": "medium" +} +"""; + + var instance = SessionStartPayload.FromJson(jsonData); + Assert.NotNull(instance); + Assert.Equal("sess_abc123", instance.SessionId); + Assert.Equal(1, instance.Version); + Assert.Equal("prompty-agent", instance.Producer); + Assert.Equal("typescript", instance.Runtime); + Assert.Equal("2.0.0", instance.PromptyVersion); + Assert.Equal("2026-06-09T20:00:00Z", instance.StartTime); + Assert.Equal("gpt-4o-mini", instance.SelectedModel); + Assert.Equal("medium", instance.ReasoningEffort); + } + + [Fact] + public void RoundtripJson() + { + // Test that FromJson -> ToJson -> FromJson produces equivalent data + string jsonData = """ +{ + "sessionId": "sess_abc123", + "version": 1, + "producer": "prompty-agent", + "runtime": "typescript", + "promptyVersion": "2.0.0", + "startTime": "2026-06-09T20:00:00Z", + "selectedModel": "gpt-4o-mini", + "reasoningEffort": "medium" +} +"""; + + var original = SessionStartPayload.FromJson(jsonData); + Assert.NotNull(original); + + var json = original.ToJson(); + Assert.False(string.IsNullOrEmpty(json)); + + var reloaded = SessionStartPayload.FromJson(json); + Assert.NotNull(reloaded); + Assert.Equal("sess_abc123", reloaded.SessionId); + Assert.Equal(1, reloaded.Version); + Assert.Equal("prompty-agent", reloaded.Producer); + Assert.Equal("typescript", reloaded.Runtime); + Assert.Equal("2.0.0", reloaded.PromptyVersion); + Assert.Equal("2026-06-09T20:00:00Z", reloaded.StartTime); + Assert.Equal("gpt-4o-mini", reloaded.SelectedModel); + Assert.Equal("medium", reloaded.ReasoningEffort); + } + + [Fact] + public void RoundtripYaml() + { + // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data + string yamlData = """ +sessionId: sess_abc123 +version: 1 +producer: prompty-agent +runtime: typescript +promptyVersion: 2.0.0 +startTime: "2026-06-09T20:00:00Z" +selectedModel: gpt-4o-mini +reasoningEffort: medium + +"""; + + var original = SessionStartPayload.FromYaml(yamlData); + Assert.NotNull(original); + + var yaml = original.ToYaml(); + Assert.False(string.IsNullOrEmpty(yaml)); + + var reloaded = SessionStartPayload.FromYaml(yaml); + Assert.NotNull(reloaded); + Assert.Equal("sess_abc123", reloaded.SessionId); + Assert.Equal(1, reloaded.Version); + Assert.Equal("prompty-agent", reloaded.Producer); + Assert.Equal("typescript", reloaded.Runtime); + Assert.Equal("2.0.0", reloaded.PromptyVersion); + Assert.Equal("2026-06-09T20:00:00Z", reloaded.StartTime); + Assert.Equal("gpt-4o-mini", reloaded.SelectedModel); + Assert.Equal("medium", reloaded.ReasoningEffort); + } + + [Fact] + public void ToJsonProducesValidJson() + { + string jsonData = """ +{ + "sessionId": "sess_abc123", + "version": 1, + "producer": "prompty-agent", + "runtime": "typescript", + "promptyVersion": "2.0.0", + "startTime": "2026-06-09T20:00:00Z", + "selectedModel": "gpt-4o-mini", + "reasoningEffort": "medium" +} +"""; + + var instance = SessionStartPayload.FromJson(jsonData); + var json = instance.ToJson(); + + // Verify it's valid JSON by parsing it + var parsed = System.Text.Json.JsonDocument.Parse(json); + Assert.NotNull(parsed); + } + + [Fact] + public void ToYamlProducesValidYaml() + { + string yamlData = """ +sessionId: sess_abc123 +version: 1 +producer: prompty-agent +runtime: typescript +promptyVersion: 2.0.0 +startTime: "2026-06-09T20:00:00Z" +selectedModel: gpt-4o-mini +reasoningEffort: medium + +"""; + + var instance = SessionStartPayload.FromYaml(yamlData); + var yaml = instance.ToYaml(); + + // Verify it's valid YAML by parsing it + var deserializer = new YamlDotNet.Serialization.DeserializerBuilder().Build(); + var parsed = deserializer.Deserialize(yaml); + Assert.NotNull(parsed); + } +} diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/SessionSummaryConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/SessionSummaryConversionTests.cs new file mode 100644 index 00000000..e491a160 --- /dev/null +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/SessionSummaryConversionTests.cs @@ -0,0 +1,152 @@ +using Xunit; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + + +public class SessionSummaryConversionTests +{ + [Fact] + public void LoadYamlInput() + { + string yamlData = """ +sessionId: sess_abc123 +status: success +turns: 5 +checkpoints: 2 +durationMs: 12500 + +"""; + + var instance = SessionSummary.FromYaml(yamlData); + + Assert.NotNull(instance); + Assert.Equal("sess_abc123", instance.SessionId); + Assert.Equal(SessionSummaryStatus.Success, instance.Status); + Assert.Equal(5, instance.Turns); + Assert.Equal(2, instance.Checkpoints); + Assert.Equal(12500, instance.DurationMs); + } + + [Fact] + public void LoadJsonInput() + { + string jsonData = """ +{ + "sessionId": "sess_abc123", + "status": "success", + "turns": 5, + "checkpoints": 2, + "durationMs": 12500 +} +"""; + + var instance = SessionSummary.FromJson(jsonData); + Assert.NotNull(instance); + Assert.Equal("sess_abc123", instance.SessionId); + Assert.Equal(SessionSummaryStatus.Success, instance.Status); + Assert.Equal(5, instance.Turns); + Assert.Equal(2, instance.Checkpoints); + Assert.Equal(12500, instance.DurationMs); + } + + [Fact] + public void RoundtripJson() + { + // Test that FromJson -> ToJson -> FromJson produces equivalent data + string jsonData = """ +{ + "sessionId": "sess_abc123", + "status": "success", + "turns": 5, + "checkpoints": 2, + "durationMs": 12500 +} +"""; + + var original = SessionSummary.FromJson(jsonData); + Assert.NotNull(original); + + var json = original.ToJson(); + Assert.False(string.IsNullOrEmpty(json)); + + var reloaded = SessionSummary.FromJson(json); + Assert.NotNull(reloaded); + Assert.Equal("sess_abc123", reloaded.SessionId); + Assert.Equal(SessionSummaryStatus.Success, reloaded.Status); + Assert.Equal(5, reloaded.Turns); + Assert.Equal(2, reloaded.Checkpoints); + Assert.Equal(12500, reloaded.DurationMs); + } + + [Fact] + public void RoundtripYaml() + { + // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data + string yamlData = """ +sessionId: sess_abc123 +status: success +turns: 5 +checkpoints: 2 +durationMs: 12500 + +"""; + + var original = SessionSummary.FromYaml(yamlData); + Assert.NotNull(original); + + var yaml = original.ToYaml(); + Assert.False(string.IsNullOrEmpty(yaml)); + + var reloaded = SessionSummary.FromYaml(yaml); + Assert.NotNull(reloaded); + Assert.Equal("sess_abc123", reloaded.SessionId); + Assert.Equal(SessionSummaryStatus.Success, reloaded.Status); + Assert.Equal(5, reloaded.Turns); + Assert.Equal(2, reloaded.Checkpoints); + Assert.Equal(12500, reloaded.DurationMs); + } + + [Fact] + public void ToJsonProducesValidJson() + { + string jsonData = """ +{ + "sessionId": "sess_abc123", + "status": "success", + "turns": 5, + "checkpoints": 2, + "durationMs": 12500 +} +"""; + + var instance = SessionSummary.FromJson(jsonData); + var json = instance.ToJson(); + + // Verify it's valid JSON by parsing it + var parsed = System.Text.Json.JsonDocument.Parse(json); + Assert.NotNull(parsed); + } + + [Fact] + public void ToYamlProducesValidYaml() + { + string yamlData = """ +sessionId: sess_abc123 +status: success +turns: 5 +checkpoints: 2 +durationMs: 12500 + +"""; + + var instance = SessionSummary.FromYaml(yamlData); + var yaml = instance.ToYaml(); + + // Verify it's valid YAML by parsing it + var deserializer = new YamlDotNet.Serialization.DeserializerBuilder().Build(); + var parsed = deserializer.Deserialize(yaml); + Assert.NotNull(parsed); + } +} diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/SessionTraceConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/SessionTraceConversionTests.cs new file mode 100644 index 00000000..48e12014 --- /dev/null +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/SessionTraceConversionTests.cs @@ -0,0 +1,142 @@ +using Xunit; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + + +public class SessionTraceConversionTests +{ + [Fact] + public void LoadYamlInput() + { + string yamlData = """ +version: "1" +runtime: typescript +promptyVersion: 2.0.0 +sessionId: sess_abc123 + +"""; + + var instance = SessionTrace.FromYaml(yamlData); + + Assert.NotNull(instance); + Assert.Equal("1", instance.Version); + Assert.Equal("typescript", instance.Runtime); + Assert.Equal("2.0.0", instance.PromptyVersion); + Assert.Equal("sess_abc123", instance.SessionId); + } + + [Fact] + public void LoadJsonInput() + { + string jsonData = """ +{ + "version": "1", + "runtime": "typescript", + "promptyVersion": "2.0.0", + "sessionId": "sess_abc123" +} +"""; + + var instance = SessionTrace.FromJson(jsonData); + Assert.NotNull(instance); + Assert.Equal("1", instance.Version); + Assert.Equal("typescript", instance.Runtime); + Assert.Equal("2.0.0", instance.PromptyVersion); + Assert.Equal("sess_abc123", instance.SessionId); + } + + [Fact] + public void RoundtripJson() + { + // Test that FromJson -> ToJson -> FromJson produces equivalent data + string jsonData = """ +{ + "version": "1", + "runtime": "typescript", + "promptyVersion": "2.0.0", + "sessionId": "sess_abc123" +} +"""; + + var original = SessionTrace.FromJson(jsonData); + Assert.NotNull(original); + + var json = original.ToJson(); + Assert.False(string.IsNullOrEmpty(json)); + + var reloaded = SessionTrace.FromJson(json); + Assert.NotNull(reloaded); + Assert.Equal("1", reloaded.Version); + Assert.Equal("typescript", reloaded.Runtime); + Assert.Equal("2.0.0", reloaded.PromptyVersion); + Assert.Equal("sess_abc123", reloaded.SessionId); + } + + [Fact] + public void RoundtripYaml() + { + // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data + string yamlData = """ +version: "1" +runtime: typescript +promptyVersion: 2.0.0 +sessionId: sess_abc123 + +"""; + + var original = SessionTrace.FromYaml(yamlData); + Assert.NotNull(original); + + var yaml = original.ToYaml(); + Assert.False(string.IsNullOrEmpty(yaml)); + + var reloaded = SessionTrace.FromYaml(yaml); + Assert.NotNull(reloaded); + Assert.Equal("1", reloaded.Version); + Assert.Equal("typescript", reloaded.Runtime); + Assert.Equal("2.0.0", reloaded.PromptyVersion); + Assert.Equal("sess_abc123", reloaded.SessionId); + } + + [Fact] + public void ToJsonProducesValidJson() + { + string jsonData = """ +{ + "version": "1", + "runtime": "typescript", + "promptyVersion": "2.0.0", + "sessionId": "sess_abc123" +} +"""; + + var instance = SessionTrace.FromJson(jsonData); + var json = instance.ToJson(); + + // Verify it's valid JSON by parsing it + var parsed = System.Text.Json.JsonDocument.Parse(json); + Assert.NotNull(parsed); + } + + [Fact] + public void ToYamlProducesValidYaml() + { + string yamlData = """ +version: "1" +runtime: typescript +promptyVersion: 2.0.0 +sessionId: sess_abc123 + +"""; + + var instance = SessionTrace.FromYaml(yamlData); + var yaml = instance.ToYaml(); + + // Verify it's valid YAML by parsing it + var deserializer = new YamlDotNet.Serialization.DeserializerBuilder().Build(); + var parsed = deserializer.Deserialize(yaml); + Assert.NotNull(parsed); + } +} diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/SessionWarningPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/SessionWarningPayloadConversionTests.cs new file mode 100644 index 00000000..fecbf3b0 --- /dev/null +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/SessionWarningPayloadConversionTests.cs @@ -0,0 +1,122 @@ +using Xunit; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + + +public class SessionWarningPayloadConversionTests +{ + [Fact] + public void LoadYamlInput() + { + string yamlData = """ +warningType: remote +message: Remote session disabled + +"""; + + var instance = SessionWarningPayload.FromYaml(yamlData); + + Assert.NotNull(instance); + Assert.Equal("remote", instance.WarningType); + Assert.Equal("Remote session disabled", instance.Message); + } + + [Fact] + public void LoadJsonInput() + { + string jsonData = """ +{ + "warningType": "remote", + "message": "Remote session disabled" +} +"""; + + var instance = SessionWarningPayload.FromJson(jsonData); + Assert.NotNull(instance); + Assert.Equal("remote", instance.WarningType); + Assert.Equal("Remote session disabled", instance.Message); + } + + [Fact] + public void RoundtripJson() + { + // Test that FromJson -> ToJson -> FromJson produces equivalent data + string jsonData = """ +{ + "warningType": "remote", + "message": "Remote session disabled" +} +"""; + + var original = SessionWarningPayload.FromJson(jsonData); + Assert.NotNull(original); + + var json = original.ToJson(); + Assert.False(string.IsNullOrEmpty(json)); + + var reloaded = SessionWarningPayload.FromJson(json); + Assert.NotNull(reloaded); + Assert.Equal("remote", reloaded.WarningType); + Assert.Equal("Remote session disabled", reloaded.Message); + } + + [Fact] + public void RoundtripYaml() + { + // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data + string yamlData = """ +warningType: remote +message: Remote session disabled + +"""; + + var original = SessionWarningPayload.FromYaml(yamlData); + Assert.NotNull(original); + + var yaml = original.ToYaml(); + Assert.False(string.IsNullOrEmpty(yaml)); + + var reloaded = SessionWarningPayload.FromYaml(yaml); + Assert.NotNull(reloaded); + Assert.Equal("remote", reloaded.WarningType); + Assert.Equal("Remote session disabled", reloaded.Message); + } + + [Fact] + public void ToJsonProducesValidJson() + { + string jsonData = """ +{ + "warningType": "remote", + "message": "Remote session disabled" +} +"""; + + var instance = SessionWarningPayload.FromJson(jsonData); + var json = instance.ToJson(); + + // Verify it's valid JSON by parsing it + var parsed = System.Text.Json.JsonDocument.Parse(json); + Assert.NotNull(parsed); + } + + [Fact] + public void ToYamlProducesValidYaml() + { + string yamlData = """ +warningType: remote +message: Remote session disabled + +"""; + + var instance = SessionWarningPayload.FromYaml(yamlData); + var yaml = instance.ToYaml(); + + // Verify it's valid YAML by parsing it + var deserializer = new YamlDotNet.Serialization.DeserializerBuilder().Build(); + var parsed = deserializer.Deserialize(yaml); + Assert.NotNull(parsed); + } +} diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/ToolExecutionCompletePayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/ToolExecutionCompletePayloadConversionTests.cs new file mode 100644 index 00000000..d4186cd9 --- /dev/null +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/ToolExecutionCompletePayloadConversionTests.cs @@ -0,0 +1,172 @@ +using Xunit; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + + +public class ToolExecutionCompletePayloadConversionTests +{ + [Fact] + public void LoadYamlInput() + { + string yamlData = """ +requestId: exec_abc123 +toolCallId: call_abc123 +toolName: powershell +success: true +exitCode: 0 +durationMs: 250 +errorKind: timeout + +"""; + + var instance = ToolExecutionCompletePayload.FromYaml(yamlData); + + Assert.NotNull(instance); + Assert.Equal("exec_abc123", instance.RequestId); + Assert.Equal("call_abc123", instance.ToolCallId); + Assert.Equal("powershell", instance.ToolName); + Assert.True(instance.Success); + Assert.Equal(0, instance.ExitCode); + Assert.Equal(250, instance.DurationMs); + Assert.Equal("timeout", instance.ErrorKind); + } + + [Fact] + public void LoadJsonInput() + { + string jsonData = """ +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "success": true, + "exitCode": 0, + "durationMs": 250, + "errorKind": "timeout" +} +"""; + + var instance = ToolExecutionCompletePayload.FromJson(jsonData); + Assert.NotNull(instance); + Assert.Equal("exec_abc123", instance.RequestId); + Assert.Equal("call_abc123", instance.ToolCallId); + Assert.Equal("powershell", instance.ToolName); + Assert.True(instance.Success); + Assert.Equal(0, instance.ExitCode); + Assert.Equal(250, instance.DurationMs); + Assert.Equal("timeout", instance.ErrorKind); + } + + [Fact] + public void RoundtripJson() + { + // Test that FromJson -> ToJson -> FromJson produces equivalent data + string jsonData = """ +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "success": true, + "exitCode": 0, + "durationMs": 250, + "errorKind": "timeout" +} +"""; + + var original = ToolExecutionCompletePayload.FromJson(jsonData); + Assert.NotNull(original); + + var json = original.ToJson(); + Assert.False(string.IsNullOrEmpty(json)); + + var reloaded = ToolExecutionCompletePayload.FromJson(json); + Assert.NotNull(reloaded); + Assert.Equal("exec_abc123", reloaded.RequestId); + Assert.Equal("call_abc123", reloaded.ToolCallId); + Assert.Equal("powershell", reloaded.ToolName); + Assert.True(reloaded.Success); + Assert.Equal(0, reloaded.ExitCode); + Assert.Equal(250, reloaded.DurationMs); + Assert.Equal("timeout", reloaded.ErrorKind); + } + + [Fact] + public void RoundtripYaml() + { + // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data + string yamlData = """ +requestId: exec_abc123 +toolCallId: call_abc123 +toolName: powershell +success: true +exitCode: 0 +durationMs: 250 +errorKind: timeout + +"""; + + var original = ToolExecutionCompletePayload.FromYaml(yamlData); + Assert.NotNull(original); + + var yaml = original.ToYaml(); + Assert.False(string.IsNullOrEmpty(yaml)); + + var reloaded = ToolExecutionCompletePayload.FromYaml(yaml); + Assert.NotNull(reloaded); + Assert.Equal("exec_abc123", reloaded.RequestId); + Assert.Equal("call_abc123", reloaded.ToolCallId); + Assert.Equal("powershell", reloaded.ToolName); + Assert.True(reloaded.Success); + Assert.Equal(0, reloaded.ExitCode); + Assert.Equal(250, reloaded.DurationMs); + Assert.Equal("timeout", reloaded.ErrorKind); + } + + [Fact] + public void ToJsonProducesValidJson() + { + string jsonData = """ +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "success": true, + "exitCode": 0, + "durationMs": 250, + "errorKind": "timeout" +} +"""; + + var instance = ToolExecutionCompletePayload.FromJson(jsonData); + var json = instance.ToJson(); + + // Verify it's valid JSON by parsing it + var parsed = System.Text.Json.JsonDocument.Parse(json); + Assert.NotNull(parsed); + } + + [Fact] + public void ToYamlProducesValidYaml() + { + string yamlData = """ +requestId: exec_abc123 +toolCallId: call_abc123 +toolName: powershell +success: true +exitCode: 0 +durationMs: 250 +errorKind: timeout + +"""; + + var instance = ToolExecutionCompletePayload.FromYaml(yamlData); + var yaml = instance.ToYaml(); + + // Verify it's valid YAML by parsing it + var deserializer = new YamlDotNet.Serialization.DeserializerBuilder().Build(); + var parsed = deserializer.Deserialize(yaml); + Assert.NotNull(parsed); + } +} diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/ToolExecutionStartPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/ToolExecutionStartPayloadConversionTests.cs new file mode 100644 index 00000000..57da4380 --- /dev/null +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/ToolExecutionStartPayloadConversionTests.cs @@ -0,0 +1,142 @@ +using Xunit; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + + +public class ToolExecutionStartPayloadConversionTests +{ + [Fact] + public void LoadYamlInput() + { + string yamlData = """ +requestId: exec_abc123 +toolCallId: call_abc123 +toolName: powershell +workingDirectory: /workspace/project + +"""; + + var instance = ToolExecutionStartPayload.FromYaml(yamlData); + + Assert.NotNull(instance); + Assert.Equal("exec_abc123", instance.RequestId); + Assert.Equal("call_abc123", instance.ToolCallId); + Assert.Equal("powershell", instance.ToolName); + Assert.Equal("/workspace/project", instance.WorkingDirectory); + } + + [Fact] + public void LoadJsonInput() + { + string jsonData = """ +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "workingDirectory": "/workspace/project" +} +"""; + + var instance = ToolExecutionStartPayload.FromJson(jsonData); + Assert.NotNull(instance); + Assert.Equal("exec_abc123", instance.RequestId); + Assert.Equal("call_abc123", instance.ToolCallId); + Assert.Equal("powershell", instance.ToolName); + Assert.Equal("/workspace/project", instance.WorkingDirectory); + } + + [Fact] + public void RoundtripJson() + { + // Test that FromJson -> ToJson -> FromJson produces equivalent data + string jsonData = """ +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "workingDirectory": "/workspace/project" +} +"""; + + var original = ToolExecutionStartPayload.FromJson(jsonData); + Assert.NotNull(original); + + var json = original.ToJson(); + Assert.False(string.IsNullOrEmpty(json)); + + var reloaded = ToolExecutionStartPayload.FromJson(json); + Assert.NotNull(reloaded); + Assert.Equal("exec_abc123", reloaded.RequestId); + Assert.Equal("call_abc123", reloaded.ToolCallId); + Assert.Equal("powershell", reloaded.ToolName); + Assert.Equal("/workspace/project", reloaded.WorkingDirectory); + } + + [Fact] + public void RoundtripYaml() + { + // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data + string yamlData = """ +requestId: exec_abc123 +toolCallId: call_abc123 +toolName: powershell +workingDirectory: /workspace/project + +"""; + + var original = ToolExecutionStartPayload.FromYaml(yamlData); + Assert.NotNull(original); + + var yaml = original.ToYaml(); + Assert.False(string.IsNullOrEmpty(yaml)); + + var reloaded = ToolExecutionStartPayload.FromYaml(yaml); + Assert.NotNull(reloaded); + Assert.Equal("exec_abc123", reloaded.RequestId); + Assert.Equal("call_abc123", reloaded.ToolCallId); + Assert.Equal("powershell", reloaded.ToolName); + Assert.Equal("/workspace/project", reloaded.WorkingDirectory); + } + + [Fact] + public void ToJsonProducesValidJson() + { + string jsonData = """ +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "workingDirectory": "/workspace/project" +} +"""; + + var instance = ToolExecutionStartPayload.FromJson(jsonData); + var json = instance.ToJson(); + + // Verify it's valid JSON by parsing it + var parsed = System.Text.Json.JsonDocument.Parse(json); + Assert.NotNull(parsed); + } + + [Fact] + public void ToYamlProducesValidYaml() + { + string yamlData = """ +requestId: exec_abc123 +toolCallId: call_abc123 +toolName: powershell +workingDirectory: /workspace/project + +"""; + + var instance = ToolExecutionStartPayload.FromYaml(yamlData); + var yaml = instance.ToYaml(); + + // Verify it's valid YAML by parsing it + var deserializer = new YamlDotNet.Serialization.DeserializerBuilder().Build(); + var parsed = deserializer.Deserialize(yaml); + Assert.NotNull(parsed); + } +} diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/TrajectoryEventConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/TrajectoryEventConversionTests.cs new file mode 100644 index 00000000..95fc31de --- /dev/null +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/TrajectoryEventConversionTests.cs @@ -0,0 +1,172 @@ +using Xunit; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + + +public class TrajectoryEventConversionTests +{ + [Fact] + public void LoadYamlInput() + { + string yamlData = """ +id: traj_abc123 +sessionId: sess_abc123 +turnId: turn_001 +toolCallId: call_abc123 +turnIndex: 4 +eventType: command +createdAt: "2026-06-09T20:00:00Z" + +"""; + + var instance = TrajectoryEvent.FromYaml(yamlData); + + Assert.NotNull(instance); + Assert.Equal("traj_abc123", instance.Id); + Assert.Equal("sess_abc123", instance.SessionId); + Assert.Equal("turn_001", instance.TurnId); + Assert.Equal("call_abc123", instance.ToolCallId); + Assert.Equal(4, instance.TurnIndex); + Assert.Equal("command", instance.EventType); + Assert.Equal("2026-06-09T20:00:00Z", instance.CreatedAt); + } + + [Fact] + public void LoadJsonInput() + { + string jsonData = """ +{ + "id": "traj_abc123", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "toolCallId": "call_abc123", + "turnIndex": 4, + "eventType": "command", + "createdAt": "2026-06-09T20:00:00Z" +} +"""; + + var instance = TrajectoryEvent.FromJson(jsonData); + Assert.NotNull(instance); + Assert.Equal("traj_abc123", instance.Id); + Assert.Equal("sess_abc123", instance.SessionId); + Assert.Equal("turn_001", instance.TurnId); + Assert.Equal("call_abc123", instance.ToolCallId); + Assert.Equal(4, instance.TurnIndex); + Assert.Equal("command", instance.EventType); + Assert.Equal("2026-06-09T20:00:00Z", instance.CreatedAt); + } + + [Fact] + public void RoundtripJson() + { + // Test that FromJson -> ToJson -> FromJson produces equivalent data + string jsonData = """ +{ + "id": "traj_abc123", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "toolCallId": "call_abc123", + "turnIndex": 4, + "eventType": "command", + "createdAt": "2026-06-09T20:00:00Z" +} +"""; + + var original = TrajectoryEvent.FromJson(jsonData); + Assert.NotNull(original); + + var json = original.ToJson(); + Assert.False(string.IsNullOrEmpty(json)); + + var reloaded = TrajectoryEvent.FromJson(json); + Assert.NotNull(reloaded); + Assert.Equal("traj_abc123", reloaded.Id); + Assert.Equal("sess_abc123", reloaded.SessionId); + Assert.Equal("turn_001", reloaded.TurnId); + Assert.Equal("call_abc123", reloaded.ToolCallId); + Assert.Equal(4, reloaded.TurnIndex); + Assert.Equal("command", reloaded.EventType); + Assert.Equal("2026-06-09T20:00:00Z", reloaded.CreatedAt); + } + + [Fact] + public void RoundtripYaml() + { + // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data + string yamlData = """ +id: traj_abc123 +sessionId: sess_abc123 +turnId: turn_001 +toolCallId: call_abc123 +turnIndex: 4 +eventType: command +createdAt: "2026-06-09T20:00:00Z" + +"""; + + var original = TrajectoryEvent.FromYaml(yamlData); + Assert.NotNull(original); + + var yaml = original.ToYaml(); + Assert.False(string.IsNullOrEmpty(yaml)); + + var reloaded = TrajectoryEvent.FromYaml(yaml); + Assert.NotNull(reloaded); + Assert.Equal("traj_abc123", reloaded.Id); + Assert.Equal("sess_abc123", reloaded.SessionId); + Assert.Equal("turn_001", reloaded.TurnId); + Assert.Equal("call_abc123", reloaded.ToolCallId); + Assert.Equal(4, reloaded.TurnIndex); + Assert.Equal("command", reloaded.EventType); + Assert.Equal("2026-06-09T20:00:00Z", reloaded.CreatedAt); + } + + [Fact] + public void ToJsonProducesValidJson() + { + string jsonData = """ +{ + "id": "traj_abc123", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "toolCallId": "call_abc123", + "turnIndex": 4, + "eventType": "command", + "createdAt": "2026-06-09T20:00:00Z" +} +"""; + + var instance = TrajectoryEvent.FromJson(jsonData); + var json = instance.ToJson(); + + // Verify it's valid JSON by parsing it + var parsed = System.Text.Json.JsonDocument.Parse(json); + Assert.NotNull(parsed); + } + + [Fact] + public void ToYamlProducesValidYaml() + { + string yamlData = """ +id: traj_abc123 +sessionId: sess_abc123 +turnId: turn_001 +toolCallId: call_abc123 +turnIndex: 4 +eventType: command +createdAt: "2026-06-09T20:00:00Z" + +"""; + + var instance = TrajectoryEvent.FromYaml(yamlData); + var yaml = instance.ToYaml(); + + // Verify it's valid YAML by parsing it + var deserializer = new YamlDotNet.Serialization.DeserializerBuilder().Build(); + var parsed = deserializer.Deserialize(yaml); + Assert.NotNull(parsed); + } +} diff --git a/runtime/csharp/Prompty.Core/Model/events/Checkpoint.cs b/runtime/csharp/Prompty.Core/Model/events/Checkpoint.cs new file mode 100644 index 00000000..4c74ad8c --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/Checkpoint.cs @@ -0,0 +1,315 @@ +// Copyright (c) Microsoft. All rights reserved. +using System.Text.Json; +using YamlDotNet.Serialization; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + +/// +/// A persisted handoff point for a harness session. +/// +public partial class Checkpoint +{ + /// + /// The shorthand property name for this type, if any. + /// + public static string? ShorthandProperty => null; + + /// + /// Initializes a new instance of . + /// +#pragma warning disable CS8618 + public Checkpoint() + { + } +#pragma warning restore CS8618 + + /// + /// Stable checkpoint identifier + /// + public string? Id { get; set; } + + /// + /// Stable session identifier + /// + public string? SessionId { get; set; } + + /// + /// Associated turn identifier, when the checkpoint was created inside a turn + /// + public string? TurnId { get; set; } + + /// + /// Monotonic checkpoint number within the session + /// + public int? CheckpointNumber { get; set; } + + /// + /// Short checkpoint title + /// + public string Title { get; set; } = string.Empty; + + /// + /// Short human-readable overview + /// + public string? Overview { get; set; } + + /// + /// Portable checkpoint state needed to resume or hand off the session + /// + public IDictionary? State { get; set; } + + /// + /// Optional host-authored summary or handoff note + /// + public string? Summary { get; set; } + + /// + /// Host-defined checkpoint metadata + /// + public IDictionary? Metadata { get; set; } + + /// + /// ISO 8601 UTC timestamp when the checkpoint was created + /// + public string? CreatedAt { get; set; } + + /// + /// Redaction state for sensitive checkpoint fields + /// + public RedactionMetadata? Redaction { get; set; } + + + + #region Load Methods + + /// + /// Load a Checkpoint instance from a dictionary. + /// + /// The dictionary containing the data. + /// Optional context with pre/post processing callbacks. + /// The loaded Checkpoint instance. + public static Checkpoint Load(Dictionary data, LoadContext? context = null) + { + if (context is not null) + { + data = context.ProcessInput(data); + } + + + // Create new instance + var instance = new Checkpoint(); + + + if (data.TryGetValue("id", out var idValue) && idValue is not null) + { + instance.Id = idValue?.ToString()!; + } + + if (data.TryGetValue("sessionId", out var sessionIdValue) && sessionIdValue is not null) + { + instance.SessionId = sessionIdValue?.ToString()!; + } + + if (data.TryGetValue("turnId", out var turnIdValue) && turnIdValue is not null) + { + instance.TurnId = turnIdValue?.ToString()!; + } + + if (data.TryGetValue("checkpointNumber", out var checkpointNumberValue) && checkpointNumberValue is not null) + { + instance.CheckpointNumber = Convert.ToInt32(checkpointNumberValue); + } + + if (data.TryGetValue("title", out var titleValue) && titleValue is not null) + { + instance.Title = titleValue?.ToString()!; + } + + if (data.TryGetValue("overview", out var overviewValue) && overviewValue is not null) + { + instance.Overview = overviewValue?.ToString()!; + } + + if (data.TryGetValue("state", out var stateValue) && stateValue is not null) + { + instance.State = stateValue.GetDictionary()!; + } + + if (data.TryGetValue("summary", out var summaryValue) && summaryValue is not null) + { + instance.Summary = summaryValue?.ToString()!; + } + + if (data.TryGetValue("metadata", out var metadataValue) && metadataValue is not null) + { + instance.Metadata = metadataValue.GetDictionary()!; + } + + if (data.TryGetValue("createdAt", out var createdAtValue) && createdAtValue is not null) + { + instance.CreatedAt = createdAtValue?.ToString()!; + } + + if (data.TryGetValue("redaction", out var redactionValue) && redactionValue is not null) + { + instance.Redaction = RedactionMetadata.Load(redactionValue.GetDictionary(RedactionMetadata.ShorthandProperty), context); + } + + if (context is not null) + { + instance = context.ProcessOutput(instance); + } + return instance; + } + + + #endregion + + #region Save Methods + + /// + /// Save the Checkpoint instance to a dictionary. + /// + /// Optional context with pre/post processing callbacks. + /// The dictionary representation of this instance. + public Dictionary Save(SaveContext? context = null) + { + var obj = this; + if (context is not null) + { + obj = context.ProcessObject(obj); + } + + + var result = new Dictionary(); + + + if (obj.Id is not null) + { + result["id"] = obj.Id; + } + + + if (obj.SessionId is not null) + { + result["sessionId"] = obj.SessionId; + } + + + if (obj.TurnId is not null) + { + result["turnId"] = obj.TurnId; + } + + + if (obj.CheckpointNumber is not null) + { + result["checkpointNumber"] = obj.CheckpointNumber; + } + + + result["title"] = obj.Title; + + + if (obj.Overview is not null) + { + result["overview"] = obj.Overview; + } + + + if (obj.State is not null) + { + result["state"] = obj.State; + } + + + if (obj.Summary is not null) + { + result["summary"] = obj.Summary; + } + + + if (obj.Metadata is not null) + { + result["metadata"] = obj.Metadata; + } + + + if (obj.CreatedAt is not null) + { + result["createdAt"] = obj.CreatedAt; + } + + + if (obj.Redaction is not null) + { + result["redaction"] = obj.Redaction?.Save(context); + } + + + if (context is not null) + { + result = context.ProcessDict(result); + } + + return result; + } + + + /// + /// Convert the Checkpoint instance to a YAML string. + /// + /// Optional context with pre/post processing callbacks. + /// The YAML string representation of this instance. + public string ToYaml(SaveContext? context = null) + { + context ??= new SaveContext(); + return context.ToYaml(Save(context)); + } + + /// + /// Convert the Checkpoint instance to a JSON string. + /// + /// Optional context with pre/post processing callbacks. + /// Whether to indent the output. Defaults to true. + /// The JSON string representation of this instance. + public string ToJson(SaveContext? context = null, bool indent = true) + { + context ??= new SaveContext(); + return context.ToJson(Save(context), indent); + } + + /// + /// Load a Checkpoint instance from a JSON string. + /// + /// The JSON string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded Checkpoint instance. + public static Checkpoint FromJson(string json, LoadContext? context = null) + { + using var doc = JsonDocument.Parse(json); + Dictionary dict; + dict = JsonSerializer.Deserialize>(json, JsonUtils.Options) + ?? throw new ArgumentException("Failed to parse JSON as dictionary"); + + return Load(dict, context); + } + + /// + /// Load a Checkpoint instance from a YAML string. + /// + /// The YAML string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded Checkpoint instance. + public static Checkpoint FromYaml(string yaml, LoadContext? context = null) + { + var dict = YamlUtils.Deserializer.Deserialize>(yaml) + ?? throw new ArgumentException("Failed to parse YAML as dictionary"); + + return Load(dict, context); + } + + #endregion +} diff --git a/runtime/csharp/Prompty.Core/Model/events/HarnessContext.cs b/runtime/csharp/Prompty.Core/Model/events/HarnessContext.cs new file mode 100644 index 00000000..9371853b --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/HarnessContext.cs @@ -0,0 +1,194 @@ +// Copyright (c) Microsoft. All rights reserved. +using System.Text.Json; +using YamlDotNet.Serialization; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + +/// +/// Execution context associated with a harness session. Host-specific +/// +/// environments can store detailed profiles in metadata without making the core +/// +/// contract depend on one source-control provider or workspace shape. +/// +public partial class HarnessContext +{ + /// + /// The shorthand property name for this type, if any. + /// + public static string? ShorthandProperty => null; + + /// + /// Initializes a new instance of . + /// +#pragma warning disable CS8618 + public HarnessContext() + { + } +#pragma warning restore CS8618 + + /// + /// Current working directory for the harness + /// + public string? Cwd { get; set; } + + /// + /// Git repository root, when known + /// + public string? GitRoot { get; set; } + + /// + /// Host-defined context metadata, such as source-control or sandbox details + /// + public IDictionary? Metadata { get; set; } + + + + #region Load Methods + + /// + /// Load a HarnessContext instance from a dictionary. + /// + /// The dictionary containing the data. + /// Optional context with pre/post processing callbacks. + /// The loaded HarnessContext instance. + public static HarnessContext Load(Dictionary data, LoadContext? context = null) + { + if (context is not null) + { + data = context.ProcessInput(data); + } + + + // Create new instance + var instance = new HarnessContext(); + + + if (data.TryGetValue("cwd", out var cwdValue) && cwdValue is not null) + { + instance.Cwd = cwdValue?.ToString()!; + } + + if (data.TryGetValue("gitRoot", out var gitRootValue) && gitRootValue is not null) + { + instance.GitRoot = gitRootValue?.ToString()!; + } + + if (data.TryGetValue("metadata", out var metadataValue) && metadataValue is not null) + { + instance.Metadata = metadataValue.GetDictionary()!; + } + + if (context is not null) + { + instance = context.ProcessOutput(instance); + } + return instance; + } + + + #endregion + + #region Save Methods + + /// + /// Save the HarnessContext instance to a dictionary. + /// + /// Optional context with pre/post processing callbacks. + /// The dictionary representation of this instance. + public Dictionary Save(SaveContext? context = null) + { + var obj = this; + if (context is not null) + { + obj = context.ProcessObject(obj); + } + + + var result = new Dictionary(); + + + if (obj.Cwd is not null) + { + result["cwd"] = obj.Cwd; + } + + + if (obj.GitRoot is not null) + { + result["gitRoot"] = obj.GitRoot; + } + + + if (obj.Metadata is not null) + { + result["metadata"] = obj.Metadata; + } + + + if (context is not null) + { + result = context.ProcessDict(result); + } + + return result; + } + + + /// + /// Convert the HarnessContext instance to a YAML string. + /// + /// Optional context with pre/post processing callbacks. + /// The YAML string representation of this instance. + public string ToYaml(SaveContext? context = null) + { + context ??= new SaveContext(); + return context.ToYaml(Save(context)); + } + + /// + /// Convert the HarnessContext instance to a JSON string. + /// + /// Optional context with pre/post processing callbacks. + /// Whether to indent the output. Defaults to true. + /// The JSON string representation of this instance. + public string ToJson(SaveContext? context = null, bool indent = true) + { + context ??= new SaveContext(); + return context.ToJson(Save(context), indent); + } + + /// + /// Load a HarnessContext instance from a JSON string. + /// + /// The JSON string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded HarnessContext instance. + public static HarnessContext FromJson(string json, LoadContext? context = null) + { + using var doc = JsonDocument.Parse(json); + Dictionary dict; + dict = JsonSerializer.Deserialize>(json, JsonUtils.Options) + ?? throw new ArgumentException("Failed to parse JSON as dictionary"); + + return Load(dict, context); + } + + /// + /// Load a HarnessContext instance from a YAML string. + /// + /// The YAML string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded HarnessContext instance. + public static HarnessContext FromYaml(string yaml, LoadContext? context = null) + { + var dict = YamlUtils.Deserializer.Deserialize>(yaml) + ?? throw new ArgumentException("Failed to parse YAML as dictionary"); + + return Load(dict, context); + } + + #endregion +} diff --git a/runtime/csharp/Prompty.Core/Model/events/HookEndPayload.cs b/runtime/csharp/Prompty.Core/Model/events/HookEndPayload.cs new file mode 100644 index 00000000..6ae0f142 --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/HookEndPayload.cs @@ -0,0 +1,245 @@ +// Copyright (c) Microsoft. All rights reserved. +using System.Text.Json; +using YamlDotNet.Serialization; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + +/// +/// Payload for "hook_end" events — a host lifecycle hook finished. +/// +public partial class HookEndPayload +{ + /// + /// The shorthand property name for this type, if any. + /// + public static string? ShorthandProperty => null; + + /// + /// Initializes a new instance of . + /// +#pragma warning disable CS8618 + public HookEndPayload() + { + } +#pragma warning restore CS8618 + + /// + /// Stable hook invocation identifier + /// + public string HookInvocationId { get; set; } = string.Empty; + + /// + /// Host-defined hook type + /// + public string HookType { get; set; } = string.Empty; + + /// + /// Whether the hook completed successfully + /// + public bool Success { get; set; } = false; + + /// + /// Hook output after host-side sanitization + /// + public IDictionary? Output { get; set; } + + /// + /// Hook execution duration in milliseconds + /// + public double? DurationMs { get; set; } + + /// + /// Human-readable error when success is false + /// + public string? Error { get; set; } + + /// + /// Redaction state for sensitive hook output fields + /// + public RedactionMetadata? Redaction { get; set; } + + + + #region Load Methods + + /// + /// Load a HookEndPayload instance from a dictionary. + /// + /// The dictionary containing the data. + /// Optional context with pre/post processing callbacks. + /// The loaded HookEndPayload instance. + public static HookEndPayload Load(Dictionary data, LoadContext? context = null) + { + if (context is not null) + { + data = context.ProcessInput(data); + } + + + // Create new instance + var instance = new HookEndPayload(); + + + if (data.TryGetValue("hookInvocationId", out var hookInvocationIdValue) && hookInvocationIdValue is not null) + { + instance.HookInvocationId = hookInvocationIdValue?.ToString()!; + } + + if (data.TryGetValue("hookType", out var hookTypeValue) && hookTypeValue is not null) + { + instance.HookType = hookTypeValue?.ToString()!; + } + + if (data.TryGetValue("success", out var successValue) && successValue is not null) + { + instance.Success = Convert.ToBoolean(successValue); + } + + if (data.TryGetValue("output", out var outputValue) && outputValue is not null) + { + instance.Output = outputValue.GetDictionary()!; + } + + if (data.TryGetValue("durationMs", out var durationMsValue) && durationMsValue is not null) + { + instance.DurationMs = Convert.ToDouble(durationMsValue); + } + + if (data.TryGetValue("error", out var errorValue) && errorValue is not null) + { + instance.Error = errorValue?.ToString()!; + } + + if (data.TryGetValue("redaction", out var redactionValue) && redactionValue is not null) + { + instance.Redaction = RedactionMetadata.Load(redactionValue.GetDictionary(RedactionMetadata.ShorthandProperty), context); + } + + if (context is not null) + { + instance = context.ProcessOutput(instance); + } + return instance; + } + + + #endregion + + #region Save Methods + + /// + /// Save the HookEndPayload instance to a dictionary. + /// + /// Optional context with pre/post processing callbacks. + /// The dictionary representation of this instance. + public Dictionary Save(SaveContext? context = null) + { + var obj = this; + if (context is not null) + { + obj = context.ProcessObject(obj); + } + + + var result = new Dictionary(); + + + result["hookInvocationId"] = obj.HookInvocationId; + + + result["hookType"] = obj.HookType; + + + result["success"] = obj.Success; + + + if (obj.Output is not null) + { + result["output"] = obj.Output; + } + + + if (obj.DurationMs is not null) + { + result["durationMs"] = obj.DurationMs; + } + + + if (obj.Error is not null) + { + result["error"] = obj.Error; + } + + + if (obj.Redaction is not null) + { + result["redaction"] = obj.Redaction?.Save(context); + } + + + if (context is not null) + { + result = context.ProcessDict(result); + } + + return result; + } + + + /// + /// Convert the HookEndPayload instance to a YAML string. + /// + /// Optional context with pre/post processing callbacks. + /// The YAML string representation of this instance. + public string ToYaml(SaveContext? context = null) + { + context ??= new SaveContext(); + return context.ToYaml(Save(context)); + } + + /// + /// Convert the HookEndPayload instance to a JSON string. + /// + /// Optional context with pre/post processing callbacks. + /// Whether to indent the output. Defaults to true. + /// The JSON string representation of this instance. + public string ToJson(SaveContext? context = null, bool indent = true) + { + context ??= new SaveContext(); + return context.ToJson(Save(context), indent); + } + + /// + /// Load a HookEndPayload instance from a JSON string. + /// + /// The JSON string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded HookEndPayload instance. + public static HookEndPayload FromJson(string json, LoadContext? context = null) + { + using var doc = JsonDocument.Parse(json); + Dictionary dict; + dict = JsonSerializer.Deserialize>(json, JsonUtils.Options) + ?? throw new ArgumentException("Failed to parse JSON as dictionary"); + + return Load(dict, context); + } + + /// + /// Load a HookEndPayload instance from a YAML string. + /// + /// The YAML string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded HookEndPayload instance. + public static HookEndPayload FromYaml(string yaml, LoadContext? context = null) + { + var dict = YamlUtils.Deserializer.Deserialize>(yaml) + ?? throw new ArgumentException("Failed to parse YAML as dictionary"); + + return Load(dict, context); + } + + #endregion +} diff --git a/runtime/csharp/Prompty.Core/Model/events/HookStartPayload.cs b/runtime/csharp/Prompty.Core/Model/events/HookStartPayload.cs new file mode 100644 index 00000000..8fd18972 --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/HookStartPayload.cs @@ -0,0 +1,200 @@ +// Copyright (c) Microsoft. All rights reserved. +using System.Text.Json; +using YamlDotNet.Serialization; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + +/// +/// Payload for "hook_start" events — a host lifecycle hook is beginning. +/// +public partial class HookStartPayload +{ + /// + /// The shorthand property name for this type, if any. + /// + public static string? ShorthandProperty => null; + + /// + /// Initializes a new instance of . + /// +#pragma warning disable CS8618 + public HookStartPayload() + { + } +#pragma warning restore CS8618 + + /// + /// Stable hook invocation identifier + /// + public string HookInvocationId { get; set; } = string.Empty; + + /// + /// Host-defined hook type + /// + public string HookType { get; set; } = string.Empty; + + /// + /// Hook input after host-side sanitization + /// + public IDictionary? Input { get; set; } + + /// + /// Redaction state for sensitive hook input fields + /// + public RedactionMetadata? Redaction { get; set; } + + + + #region Load Methods + + /// + /// Load a HookStartPayload instance from a dictionary. + /// + /// The dictionary containing the data. + /// Optional context with pre/post processing callbacks. + /// The loaded HookStartPayload instance. + public static HookStartPayload Load(Dictionary data, LoadContext? context = null) + { + if (context is not null) + { + data = context.ProcessInput(data); + } + + + // Create new instance + var instance = new HookStartPayload(); + + + if (data.TryGetValue("hookInvocationId", out var hookInvocationIdValue) && hookInvocationIdValue is not null) + { + instance.HookInvocationId = hookInvocationIdValue?.ToString()!; + } + + if (data.TryGetValue("hookType", out var hookTypeValue) && hookTypeValue is not null) + { + instance.HookType = hookTypeValue?.ToString()!; + } + + if (data.TryGetValue("input", out var inputValue) && inputValue is not null) + { + instance.Input = inputValue.GetDictionary()!; + } + + if (data.TryGetValue("redaction", out var redactionValue) && redactionValue is not null) + { + instance.Redaction = RedactionMetadata.Load(redactionValue.GetDictionary(RedactionMetadata.ShorthandProperty), context); + } + + if (context is not null) + { + instance = context.ProcessOutput(instance); + } + return instance; + } + + + #endregion + + #region Save Methods + + /// + /// Save the HookStartPayload instance to a dictionary. + /// + /// Optional context with pre/post processing callbacks. + /// The dictionary representation of this instance. + public Dictionary Save(SaveContext? context = null) + { + var obj = this; + if (context is not null) + { + obj = context.ProcessObject(obj); + } + + + var result = new Dictionary(); + + + result["hookInvocationId"] = obj.HookInvocationId; + + + result["hookType"] = obj.HookType; + + + if (obj.Input is not null) + { + result["input"] = obj.Input; + } + + + if (obj.Redaction is not null) + { + result["redaction"] = obj.Redaction?.Save(context); + } + + + if (context is not null) + { + result = context.ProcessDict(result); + } + + return result; + } + + + /// + /// Convert the HookStartPayload instance to a YAML string. + /// + /// Optional context with pre/post processing callbacks. + /// The YAML string representation of this instance. + public string ToYaml(SaveContext? context = null) + { + context ??= new SaveContext(); + return context.ToYaml(Save(context)); + } + + /// + /// Convert the HookStartPayload instance to a JSON string. + /// + /// Optional context with pre/post processing callbacks. + /// Whether to indent the output. Defaults to true. + /// The JSON string representation of this instance. + public string ToJson(SaveContext? context = null, bool indent = true) + { + context ??= new SaveContext(); + return context.ToJson(Save(context), indent); + } + + /// + /// Load a HookStartPayload instance from a JSON string. + /// + /// The JSON string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded HookStartPayload instance. + public static HookStartPayload FromJson(string json, LoadContext? context = null) + { + using var doc = JsonDocument.Parse(json); + Dictionary dict; + dict = JsonSerializer.Deserialize>(json, JsonUtils.Options) + ?? throw new ArgumentException("Failed to parse JSON as dictionary"); + + return Load(dict, context); + } + + /// + /// Load a HookStartPayload instance from a YAML string. + /// + /// The YAML string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded HookStartPayload instance. + public static HookStartPayload FromYaml(string yaml, LoadContext? context = null) + { + var dict = YamlUtils.Deserializer.Deserialize>(yaml) + ?? throw new ArgumentException("Failed to parse YAML as dictionary"); + + return Load(dict, context); + } + + #endregion +} diff --git a/runtime/csharp/Prompty.Core/Model/events/HostToolRequest.cs b/runtime/csharp/Prompty.Core/Model/events/HostToolRequest.cs new file mode 100644 index 00000000..a69feca2 --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/HostToolRequest.cs @@ -0,0 +1,219 @@ +// Copyright (c) Microsoft. All rights reserved. +using System.Text.Json; +using YamlDotNet.Serialization; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + +/// +/// Request passed to a host tool executor after policy and permission checks. +/// +public partial class HostToolRequest +{ + /// + /// The shorthand property name for this type, if any. + /// + public static string? ShorthandProperty => null; + + /// + /// Initializes a new instance of . + /// +#pragma warning disable CS8618 + public HostToolRequest() + { + } +#pragma warning restore CS8618 + + /// + /// Stable host execution request identifier + /// + public string? RequestId { get; set; } + + /// + /// Associated model tool call identifier, when available + /// + public string? ToolCallId { get; set; } + + /// + /// Name of the host tool being executed + /// + public string ToolName { get; set; } = string.Empty; + + /// + /// Tool arguments after host-side sanitization + /// + public IDictionary? Arguments { get; set; } + + /// + /// Working directory or execution scope for the tool + /// + public string? WorkingDirectory { get; set; } + + + + #region Load Methods + + /// + /// Load a HostToolRequest instance from a dictionary. + /// + /// The dictionary containing the data. + /// Optional context with pre/post processing callbacks. + /// The loaded HostToolRequest instance. + public static HostToolRequest Load(Dictionary data, LoadContext? context = null) + { + if (context is not null) + { + data = context.ProcessInput(data); + } + + + // Create new instance + var instance = new HostToolRequest(); + + + if (data.TryGetValue("requestId", out var requestIdValue) && requestIdValue is not null) + { + instance.RequestId = requestIdValue?.ToString()!; + } + + if (data.TryGetValue("toolCallId", out var toolCallIdValue) && toolCallIdValue is not null) + { + instance.ToolCallId = toolCallIdValue?.ToString()!; + } + + if (data.TryGetValue("toolName", out var toolNameValue) && toolNameValue is not null) + { + instance.ToolName = toolNameValue?.ToString()!; + } + + if (data.TryGetValue("arguments", out var argumentsValue) && argumentsValue is not null) + { + instance.Arguments = argumentsValue.GetDictionary()!; + } + + if (data.TryGetValue("workingDirectory", out var workingDirectoryValue) && workingDirectoryValue is not null) + { + instance.WorkingDirectory = workingDirectoryValue?.ToString()!; + } + + if (context is not null) + { + instance = context.ProcessOutput(instance); + } + return instance; + } + + + #endregion + + #region Save Methods + + /// + /// Save the HostToolRequest instance to a dictionary. + /// + /// Optional context with pre/post processing callbacks. + /// The dictionary representation of this instance. + public Dictionary Save(SaveContext? context = null) + { + var obj = this; + if (context is not null) + { + obj = context.ProcessObject(obj); + } + + + var result = new Dictionary(); + + + if (obj.RequestId is not null) + { + result["requestId"] = obj.RequestId; + } + + + if (obj.ToolCallId is not null) + { + result["toolCallId"] = obj.ToolCallId; + } + + + result["toolName"] = obj.ToolName; + + + if (obj.Arguments is not null) + { + result["arguments"] = obj.Arguments; + } + + + if (obj.WorkingDirectory is not null) + { + result["workingDirectory"] = obj.WorkingDirectory; + } + + + if (context is not null) + { + result = context.ProcessDict(result); + } + + return result; + } + + + /// + /// Convert the HostToolRequest instance to a YAML string. + /// + /// Optional context with pre/post processing callbacks. + /// The YAML string representation of this instance. + public string ToYaml(SaveContext? context = null) + { + context ??= new SaveContext(); + return context.ToYaml(Save(context)); + } + + /// + /// Convert the HostToolRequest instance to a JSON string. + /// + /// Optional context with pre/post processing callbacks. + /// Whether to indent the output. Defaults to true. + /// The JSON string representation of this instance. + public string ToJson(SaveContext? context = null, bool indent = true) + { + context ??= new SaveContext(); + return context.ToJson(Save(context), indent); + } + + /// + /// Load a HostToolRequest instance from a JSON string. + /// + /// The JSON string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded HostToolRequest instance. + public static HostToolRequest FromJson(string json, LoadContext? context = null) + { + using var doc = JsonDocument.Parse(json); + Dictionary dict; + dict = JsonSerializer.Deserialize>(json, JsonUtils.Options) + ?? throw new ArgumentException("Failed to parse JSON as dictionary"); + + return Load(dict, context); + } + + /// + /// Load a HostToolRequest instance from a YAML string. + /// + /// The YAML string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded HostToolRequest instance. + public static HostToolRequest FromYaml(string yaml, LoadContext? context = null) + { + var dict = YamlUtils.Deserializer.Deserialize>(yaml) + ?? throw new ArgumentException("Failed to parse YAML as dictionary"); + + return Load(dict, context); + } + + #endregion +} diff --git a/runtime/csharp/Prompty.Core/Model/events/HostToolResult.cs b/runtime/csharp/Prompty.Core/Model/events/HostToolResult.cs new file mode 100644 index 00000000..b8aa3459 --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/HostToolResult.cs @@ -0,0 +1,280 @@ +// Copyright (c) Microsoft. All rights reserved. +using System.Text.Json; +using YamlDotNet.Serialization; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + +/// +/// Result returned by a host tool executor. +/// +public partial class HostToolResult +{ + /// + /// The shorthand property name for this type, if any. + /// + public static string? ShorthandProperty => null; + + /// + /// Initializes a new instance of . + /// +#pragma warning disable CS8618 + public HostToolResult() + { + } +#pragma warning restore CS8618 + + /// + /// Stable host execution request identifier + /// + public string? RequestId { get; set; } + + /// + /// Associated model tool call identifier, when available + /// + public string? ToolCallId { get; set; } + + /// + /// Name of the host tool that executed + /// + public string ToolName { get; set; } = string.Empty; + + /// + /// Whether the host execution completed successfully + /// + public bool Success { get; set; } = false; + + /// + /// Host-normalized execution result + /// + public object? Result { get; set; } + + /// + /// Process or host exit code, when applicable + /// + public int? ExitCode { get; set; } + + /// + /// Tool execution duration in milliseconds + /// + public double? DurationMs { get; set; } + + /// + /// Machine-readable error category when success is false + /// + public string? ErrorKind { get; set; } + + /// + /// Host-specific telemetry for the execution + /// + public IDictionary? Telemetry { get; set; } + + + + #region Load Methods + + /// + /// Load a HostToolResult instance from a dictionary. + /// + /// The dictionary containing the data. + /// Optional context with pre/post processing callbacks. + /// The loaded HostToolResult instance. + public static HostToolResult Load(Dictionary data, LoadContext? context = null) + { + if (context is not null) + { + data = context.ProcessInput(data); + } + + + // Create new instance + var instance = new HostToolResult(); + + + if (data.TryGetValue("requestId", out var requestIdValue) && requestIdValue is not null) + { + instance.RequestId = requestIdValue?.ToString()!; + } + + if (data.TryGetValue("toolCallId", out var toolCallIdValue) && toolCallIdValue is not null) + { + instance.ToolCallId = toolCallIdValue?.ToString()!; + } + + if (data.TryGetValue("toolName", out var toolNameValue) && toolNameValue is not null) + { + instance.ToolName = toolNameValue?.ToString()!; + } + + if (data.TryGetValue("success", out var successValue) && successValue is not null) + { + instance.Success = Convert.ToBoolean(successValue); + } + + if (data.TryGetValue("result", out var resultValue) && resultValue is not null) + { + instance.Result = resultValue; + } + + if (data.TryGetValue("exitCode", out var exitCodeValue) && exitCodeValue is not null) + { + instance.ExitCode = Convert.ToInt32(exitCodeValue); + } + + if (data.TryGetValue("durationMs", out var durationMsValue) && durationMsValue is not null) + { + instance.DurationMs = Convert.ToDouble(durationMsValue); + } + + if (data.TryGetValue("errorKind", out var errorKindValue) && errorKindValue is not null) + { + instance.ErrorKind = errorKindValue?.ToString()!; + } + + if (data.TryGetValue("telemetry", out var telemetryValue) && telemetryValue is not null) + { + instance.Telemetry = telemetryValue.GetDictionary()!; + } + + if (context is not null) + { + instance = context.ProcessOutput(instance); + } + return instance; + } + + + #endregion + + #region Save Methods + + /// + /// Save the HostToolResult instance to a dictionary. + /// + /// Optional context with pre/post processing callbacks. + /// The dictionary representation of this instance. + public Dictionary Save(SaveContext? context = null) + { + var obj = this; + if (context is not null) + { + obj = context.ProcessObject(obj); + } + + + var result = new Dictionary(); + + + if (obj.RequestId is not null) + { + result["requestId"] = obj.RequestId; + } + + + if (obj.ToolCallId is not null) + { + result["toolCallId"] = obj.ToolCallId; + } + + + result["toolName"] = obj.ToolName; + + + result["success"] = obj.Success; + + + if (obj.Result is not null) + { + result["result"] = obj.Result; + } + + + if (obj.ExitCode is not null) + { + result["exitCode"] = obj.ExitCode; + } + + + if (obj.DurationMs is not null) + { + result["durationMs"] = obj.DurationMs; + } + + + if (obj.ErrorKind is not null) + { + result["errorKind"] = obj.ErrorKind; + } + + + if (obj.Telemetry is not null) + { + result["telemetry"] = obj.Telemetry; + } + + + if (context is not null) + { + result = context.ProcessDict(result); + } + + return result; + } + + + /// + /// Convert the HostToolResult instance to a YAML string. + /// + /// Optional context with pre/post processing callbacks. + /// The YAML string representation of this instance. + public string ToYaml(SaveContext? context = null) + { + context ??= new SaveContext(); + return context.ToYaml(Save(context)); + } + + /// + /// Convert the HostToolResult instance to a JSON string. + /// + /// Optional context with pre/post processing callbacks. + /// Whether to indent the output. Defaults to true. + /// The JSON string representation of this instance. + public string ToJson(SaveContext? context = null, bool indent = true) + { + context ??= new SaveContext(); + return context.ToJson(Save(context), indent); + } + + /// + /// Load a HostToolResult instance from a JSON string. + /// + /// The JSON string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded HostToolResult instance. + public static HostToolResult FromJson(string json, LoadContext? context = null) + { + using var doc = JsonDocument.Parse(json); + Dictionary dict; + dict = JsonSerializer.Deserialize>(json, JsonUtils.Options) + ?? throw new ArgumentException("Failed to parse JSON as dictionary"); + + return Load(dict, context); + } + + /// + /// Load a HostToolResult instance from a YAML string. + /// + /// The YAML string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded HostToolResult instance. + public static HostToolResult FromYaml(string yaml, LoadContext? context = null) + { + var dict = YamlUtils.Deserializer.Deserialize>(yaml) + ?? throw new ArgumentException("Failed to parse YAML as dictionary"); + + return Load(dict, context); + } + + #endregion +} diff --git a/runtime/csharp/Prompty.Core/Model/events/PermissionCompletedPayload.cs b/runtime/csharp/Prompty.Core/Model/events/PermissionCompletedPayload.cs index ed54a8b2..c8b119c5 100644 --- a/runtime/csharp/Prompty.Core/Model/events/PermissionCompletedPayload.cs +++ b/runtime/csharp/Prompty.Core/Model/events/PermissionCompletedPayload.cs @@ -25,6 +25,16 @@ public PermissionCompletedPayload() } #pragma warning restore CS8618 + /// + /// Stable permission request identifier + /// + public string? RequestId { get; set; } + + /// + /// Associated tool call identifier, when the permission gated a tool call + /// + public string? ToolCallId { get; set; } + /// /// Permission/action name that was decided /// @@ -40,6 +50,11 @@ public PermissionCompletedPayload() /// public string? Reason { get; set; } + /// + /// Host-specific decision result, such as a durable approval token or denial details + /// + public IDictionary? Result { get; set; } + #region Load Methods @@ -62,6 +77,16 @@ public static PermissionCompletedPayload Load(Dictionary data, var instance = new PermissionCompletedPayload(); + if (data.TryGetValue("requestId", out var requestIdValue) && requestIdValue is not null) + { + instance.RequestId = requestIdValue?.ToString()!; + } + + if (data.TryGetValue("toolCallId", out var toolCallIdValue) && toolCallIdValue is not null) + { + instance.ToolCallId = toolCallIdValue?.ToString()!; + } + if (data.TryGetValue("permission", out var permissionValue) && permissionValue is not null) { instance.Permission = permissionValue?.ToString()!; @@ -77,6 +102,11 @@ public static PermissionCompletedPayload Load(Dictionary data, instance.Reason = reasonValue?.ToString()!; } + if (data.TryGetValue("result", out var resultValue) && resultValue is not null) + { + instance.Result = resultValue.GetDictionary()!; + } + if (context is not null) { instance = context.ProcessOutput(instance); @@ -106,6 +136,18 @@ public static PermissionCompletedPayload Load(Dictionary data, var result = new Dictionary(); + if (obj.RequestId is not null) + { + result["requestId"] = obj.RequestId; + } + + + if (obj.ToolCallId is not null) + { + result["toolCallId"] = obj.ToolCallId; + } + + result["permission"] = obj.Permission; @@ -118,6 +160,12 @@ public static PermissionCompletedPayload Load(Dictionary data, } + if (obj.Result is not null) + { + result["result"] = obj.Result; + } + + if (context is not null) { result = context.ProcessDict(result); diff --git a/runtime/csharp/Prompty.Core/Model/events/PermissionDecision.cs b/runtime/csharp/Prompty.Core/Model/events/PermissionDecision.cs new file mode 100644 index 00000000..bbb78351 --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/PermissionDecision.cs @@ -0,0 +1,232 @@ +// Copyright (c) Microsoft. All rights reserved. +using System.Text.Json; +using YamlDotNet.Serialization; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + +/// +/// Decision returned by a permission resolver. +/// +public partial class PermissionDecision +{ + /// + /// The shorthand property name for this type, if any. + /// + public static string? ShorthandProperty => null; + + /// + /// Initializes a new instance of . + /// +#pragma warning disable CS8618 + public PermissionDecision() + { + } +#pragma warning restore CS8618 + + /// + /// Stable permission request identifier + /// + public string? RequestId { get; set; } + + /// + /// Associated tool call identifier, when the permission gated a tool call + /// + public string? ToolCallId { get; set; } + + /// + /// Permission/action name that was decided + /// + public string Permission { get; set; } = string.Empty; + + /// + /// Whether the requested permission was approved + /// + public bool Approved { get; set; } = false; + + /// + /// Decision reason, if available + /// + public string? Reason { get; set; } + + /// + /// Host-specific decision result, such as a durable approval token or denial details + /// + public IDictionary? Result { get; set; } + + + + #region Load Methods + + /// + /// Load a PermissionDecision instance from a dictionary. + /// + /// The dictionary containing the data. + /// Optional context with pre/post processing callbacks. + /// The loaded PermissionDecision instance. + public static PermissionDecision Load(Dictionary data, LoadContext? context = null) + { + if (context is not null) + { + data = context.ProcessInput(data); + } + + + // Create new instance + var instance = new PermissionDecision(); + + + if (data.TryGetValue("requestId", out var requestIdValue) && requestIdValue is not null) + { + instance.RequestId = requestIdValue?.ToString()!; + } + + if (data.TryGetValue("toolCallId", out var toolCallIdValue) && toolCallIdValue is not null) + { + instance.ToolCallId = toolCallIdValue?.ToString()!; + } + + if (data.TryGetValue("permission", out var permissionValue) && permissionValue is not null) + { + instance.Permission = permissionValue?.ToString()!; + } + + if (data.TryGetValue("approved", out var approvedValue) && approvedValue is not null) + { + instance.Approved = Convert.ToBoolean(approvedValue); + } + + if (data.TryGetValue("reason", out var reasonValue) && reasonValue is not null) + { + instance.Reason = reasonValue?.ToString()!; + } + + if (data.TryGetValue("result", out var resultValue) && resultValue is not null) + { + instance.Result = resultValue.GetDictionary()!; + } + + if (context is not null) + { + instance = context.ProcessOutput(instance); + } + return instance; + } + + + #endregion + + #region Save Methods + + /// + /// Save the PermissionDecision instance to a dictionary. + /// + /// Optional context with pre/post processing callbacks. + /// The dictionary representation of this instance. + public Dictionary Save(SaveContext? context = null) + { + var obj = this; + if (context is not null) + { + obj = context.ProcessObject(obj); + } + + + var result = new Dictionary(); + + + if (obj.RequestId is not null) + { + result["requestId"] = obj.RequestId; + } + + + if (obj.ToolCallId is not null) + { + result["toolCallId"] = obj.ToolCallId; + } + + + result["permission"] = obj.Permission; + + + result["approved"] = obj.Approved; + + + if (obj.Reason is not null) + { + result["reason"] = obj.Reason; + } + + + if (obj.Result is not null) + { + result["result"] = obj.Result; + } + + + if (context is not null) + { + result = context.ProcessDict(result); + } + + return result; + } + + + /// + /// Convert the PermissionDecision instance to a YAML string. + /// + /// Optional context with pre/post processing callbacks. + /// The YAML string representation of this instance. + public string ToYaml(SaveContext? context = null) + { + context ??= new SaveContext(); + return context.ToYaml(Save(context)); + } + + /// + /// Convert the PermissionDecision instance to a JSON string. + /// + /// Optional context with pre/post processing callbacks. + /// Whether to indent the output. Defaults to true. + /// The JSON string representation of this instance. + public string ToJson(SaveContext? context = null, bool indent = true) + { + context ??= new SaveContext(); + return context.ToJson(Save(context), indent); + } + + /// + /// Load a PermissionDecision instance from a JSON string. + /// + /// The JSON string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded PermissionDecision instance. + public static PermissionDecision FromJson(string json, LoadContext? context = null) + { + using var doc = JsonDocument.Parse(json); + Dictionary dict; + dict = JsonSerializer.Deserialize>(json, JsonUtils.Options) + ?? throw new ArgumentException("Failed to parse JSON as dictionary"); + + return Load(dict, context); + } + + /// + /// Load a PermissionDecision instance from a YAML string. + /// + /// The YAML string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded PermissionDecision instance. + public static PermissionDecision FromYaml(string yaml, LoadContext? context = null) + { + var dict = YamlUtils.Deserializer.Deserialize>(yaml) + ?? throw new ArgumentException("Failed to parse YAML as dictionary"); + + return Load(dict, context); + } + + #endregion +} diff --git a/runtime/csharp/Prompty.Core/Model/events/PermissionRequest.cs b/runtime/csharp/Prompty.Core/Model/events/PermissionRequest.cs new file mode 100644 index 00000000..41a0f2e5 --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/PermissionRequest.cs @@ -0,0 +1,253 @@ +// Copyright (c) Microsoft. All rights reserved. +using System.Text.Json; +using YamlDotNet.Serialization; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + +/// +/// Request passed to a permission resolver. This is the live protocol shape; the +/// +/// event payloads above can include trace-only metadata such as redaction state. +/// +public partial class PermissionRequest +{ + /// + /// The shorthand property name for this type, if any. + /// + public static string? ShorthandProperty => null; + + /// + /// Initializes a new instance of . + /// +#pragma warning disable CS8618 + public PermissionRequest() + { + } +#pragma warning restore CS8618 + + /// + /// Stable permission request identifier + /// + public string? RequestId { get; set; } + + /// + /// Associated tool call identifier, when the permission gates a tool call + /// + public string? ToolCallId { get; set; } + + /// + /// Permission/action name being requested + /// + public string Permission { get; set; } = string.Empty; + + /// + /// Resource or tool the permission applies to + /// + public string? Target { get; set; } + + /// + /// Additional host-specific permission details + /// + public IDictionary? Details { get; set; } + + /// + /// Human-readable prompt or rationale that can be shown to an approval UI + /// + public string? PromptRequest { get; set; } + + /// + /// Policy metadata used to evaluate or explain the permission request + /// + public IDictionary? Policy { get; set; } + + + + #region Load Methods + + /// + /// Load a PermissionRequest instance from a dictionary. + /// + /// The dictionary containing the data. + /// Optional context with pre/post processing callbacks. + /// The loaded PermissionRequest instance. + public static PermissionRequest Load(Dictionary data, LoadContext? context = null) + { + if (context is not null) + { + data = context.ProcessInput(data); + } + + + // Create new instance + var instance = new PermissionRequest(); + + + if (data.TryGetValue("requestId", out var requestIdValue) && requestIdValue is not null) + { + instance.RequestId = requestIdValue?.ToString()!; + } + + if (data.TryGetValue("toolCallId", out var toolCallIdValue) && toolCallIdValue is not null) + { + instance.ToolCallId = toolCallIdValue?.ToString()!; + } + + if (data.TryGetValue("permission", out var permissionValue) && permissionValue is not null) + { + instance.Permission = permissionValue?.ToString()!; + } + + if (data.TryGetValue("target", out var targetValue) && targetValue is not null) + { + instance.Target = targetValue?.ToString()!; + } + + if (data.TryGetValue("details", out var detailsValue) && detailsValue is not null) + { + instance.Details = detailsValue.GetDictionary()!; + } + + if (data.TryGetValue("promptRequest", out var promptRequestValue) && promptRequestValue is not null) + { + instance.PromptRequest = promptRequestValue?.ToString()!; + } + + if (data.TryGetValue("policy", out var policyValue) && policyValue is not null) + { + instance.Policy = policyValue.GetDictionary()!; + } + + if (context is not null) + { + instance = context.ProcessOutput(instance); + } + return instance; + } + + + #endregion + + #region Save Methods + + /// + /// Save the PermissionRequest instance to a dictionary. + /// + /// Optional context with pre/post processing callbacks. + /// The dictionary representation of this instance. + public Dictionary Save(SaveContext? context = null) + { + var obj = this; + if (context is not null) + { + obj = context.ProcessObject(obj); + } + + + var result = new Dictionary(); + + + if (obj.RequestId is not null) + { + result["requestId"] = obj.RequestId; + } + + + if (obj.ToolCallId is not null) + { + result["toolCallId"] = obj.ToolCallId; + } + + + result["permission"] = obj.Permission; + + + if (obj.Target is not null) + { + result["target"] = obj.Target; + } + + + if (obj.Details is not null) + { + result["details"] = obj.Details; + } + + + if (obj.PromptRequest is not null) + { + result["promptRequest"] = obj.PromptRequest; + } + + + if (obj.Policy is not null) + { + result["policy"] = obj.Policy; + } + + + if (context is not null) + { + result = context.ProcessDict(result); + } + + return result; + } + + + /// + /// Convert the PermissionRequest instance to a YAML string. + /// + /// Optional context with pre/post processing callbacks. + /// The YAML string representation of this instance. + public string ToYaml(SaveContext? context = null) + { + context ??= new SaveContext(); + return context.ToYaml(Save(context)); + } + + /// + /// Convert the PermissionRequest instance to a JSON string. + /// + /// Optional context with pre/post processing callbacks. + /// Whether to indent the output. Defaults to true. + /// The JSON string representation of this instance. + public string ToJson(SaveContext? context = null, bool indent = true) + { + context ??= new SaveContext(); + return context.ToJson(Save(context), indent); + } + + /// + /// Load a PermissionRequest instance from a JSON string. + /// + /// The JSON string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded PermissionRequest instance. + public static PermissionRequest FromJson(string json, LoadContext? context = null) + { + using var doc = JsonDocument.Parse(json); + Dictionary dict; + dict = JsonSerializer.Deserialize>(json, JsonUtils.Options) + ?? throw new ArgumentException("Failed to parse JSON as dictionary"); + + return Load(dict, context); + } + + /// + /// Load a PermissionRequest instance from a YAML string. + /// + /// The YAML string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded PermissionRequest instance. + public static PermissionRequest FromYaml(string yaml, LoadContext? context = null) + { + var dict = YamlUtils.Deserializer.Deserialize>(yaml) + ?? throw new ArgumentException("Failed to parse YAML as dictionary"); + + return Load(dict, context); + } + + #endregion +} diff --git a/runtime/csharp/Prompty.Core/Model/events/PermissionRequestedPayload.cs b/runtime/csharp/Prompty.Core/Model/events/PermissionRequestedPayload.cs index a2e19616..c9a576d4 100644 --- a/runtime/csharp/Prompty.Core/Model/events/PermissionRequestedPayload.cs +++ b/runtime/csharp/Prompty.Core/Model/events/PermissionRequestedPayload.cs @@ -25,6 +25,16 @@ public PermissionRequestedPayload() } #pragma warning restore CS8618 + /// + /// Stable permission request identifier + /// + public string? RequestId { get; set; } + + /// + /// Associated tool call identifier, when the permission gates a tool call + /// + public string? ToolCallId { get; set; } + /// /// Permission/action name being requested /// @@ -40,6 +50,21 @@ public PermissionRequestedPayload() /// public IDictionary? Details { get; set; } + /// + /// Human-readable prompt or rationale that can be shown to an approval UI + /// + public string? PromptRequest { get; set; } + + /// + /// Policy metadata used to evaluate or explain the permission request + /// + public IDictionary? Policy { get; set; } + + /// + /// Redaction state for sensitive request fields + /// + public RedactionMetadata? Redaction { get; set; } + #region Load Methods @@ -62,6 +87,16 @@ public static PermissionRequestedPayload Load(Dictionary data, var instance = new PermissionRequestedPayload(); + if (data.TryGetValue("requestId", out var requestIdValue) && requestIdValue is not null) + { + instance.RequestId = requestIdValue?.ToString()!; + } + + if (data.TryGetValue("toolCallId", out var toolCallIdValue) && toolCallIdValue is not null) + { + instance.ToolCallId = toolCallIdValue?.ToString()!; + } + if (data.TryGetValue("permission", out var permissionValue) && permissionValue is not null) { instance.Permission = permissionValue?.ToString()!; @@ -77,6 +112,21 @@ public static PermissionRequestedPayload Load(Dictionary data, instance.Details = detailsValue.GetDictionary()!; } + if (data.TryGetValue("promptRequest", out var promptRequestValue) && promptRequestValue is not null) + { + instance.PromptRequest = promptRequestValue?.ToString()!; + } + + if (data.TryGetValue("policy", out var policyValue) && policyValue is not null) + { + instance.Policy = policyValue.GetDictionary()!; + } + + if (data.TryGetValue("redaction", out var redactionValue) && redactionValue is not null) + { + instance.Redaction = RedactionMetadata.Load(redactionValue.GetDictionary(RedactionMetadata.ShorthandProperty), context); + } + if (context is not null) { instance = context.ProcessOutput(instance); @@ -106,6 +156,18 @@ public static PermissionRequestedPayload Load(Dictionary data, var result = new Dictionary(); + if (obj.RequestId is not null) + { + result["requestId"] = obj.RequestId; + } + + + if (obj.ToolCallId is not null) + { + result["toolCallId"] = obj.ToolCallId; + } + + result["permission"] = obj.Permission; @@ -121,6 +183,24 @@ public static PermissionRequestedPayload Load(Dictionary data, } + if (obj.PromptRequest is not null) + { + result["promptRequest"] = obj.PromptRequest; + } + + + if (obj.Policy is not null) + { + result["policy"] = obj.Policy; + } + + + if (obj.Redaction is not null) + { + result["redaction"] = obj.Redaction?.Save(context); + } + + if (context is not null) { result = context.ProcessDict(result); diff --git a/runtime/csharp/Prompty.Core/Model/events/RedactedField.cs b/runtime/csharp/Prompty.Core/Model/events/RedactedField.cs new file mode 100644 index 00000000..76563869 --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/RedactedField.cs @@ -0,0 +1,184 @@ +// Copyright (c) Microsoft. All rights reserved. +using System.Text.Json; +using YamlDotNet.Serialization; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + +/// +/// Redaction handling for one JSON-shaped field path. +/// +public partial class RedactedField +{ + /// + /// The shorthand property name for this type, if any. + /// + public static string? ShorthandProperty => null; + + /// + /// Initializes a new instance of . + /// +#pragma warning disable CS8618 + public RedactedField() + { + } +#pragma warning restore CS8618 + + /// + /// JSONPath-like field path, relative to the containing payload + /// + public string Path { get; set; } = string.Empty; + + /// + /// How the field was represented + /// + public RedactionMode Mode { get; set; } = RedactionMode.None; + + /// + /// Human-readable reason or policy that caused this handling + /// + public string? Reason { get; set; } + + + + #region Load Methods + + /// + /// Load a RedactedField instance from a dictionary. + /// + /// The dictionary containing the data. + /// Optional context with pre/post processing callbacks. + /// The loaded RedactedField instance. + public static RedactedField Load(Dictionary data, LoadContext? context = null) + { + if (context is not null) + { + data = context.ProcessInput(data); + } + + + // Create new instance + var instance = new RedactedField(); + + + if (data.TryGetValue("path", out var pathValue) && pathValue is not null) + { + instance.Path = pathValue?.ToString()!; + } + + if (data.TryGetValue("mode", out var modeValue) && modeValue is not null) + { + instance.Mode = Enum.Parse(modeValue?.ToString()!, true); + } + + if (data.TryGetValue("reason", out var reasonValue) && reasonValue is not null) + { + instance.Reason = reasonValue?.ToString()!; + } + + if (context is not null) + { + instance = context.ProcessOutput(instance); + } + return instance; + } + + + #endregion + + #region Save Methods + + /// + /// Save the RedactedField instance to a dictionary. + /// + /// Optional context with pre/post processing callbacks. + /// The dictionary representation of this instance. + public Dictionary Save(SaveContext? context = null) + { + var obj = this; + if (context is not null) + { + obj = context.ProcessObject(obj); + } + + + var result = new Dictionary(); + + + result["path"] = obj.Path; + + + result["mode"] = obj.Mode.ToString().ToLowerInvariant(); + + + if (obj.Reason is not null) + { + result["reason"] = obj.Reason; + } + + + if (context is not null) + { + result = context.ProcessDict(result); + } + + return result; + } + + + /// + /// Convert the RedactedField instance to a YAML string. + /// + /// Optional context with pre/post processing callbacks. + /// The YAML string representation of this instance. + public string ToYaml(SaveContext? context = null) + { + context ??= new SaveContext(); + return context.ToYaml(Save(context)); + } + + /// + /// Convert the RedactedField instance to a JSON string. + /// + /// Optional context with pre/post processing callbacks. + /// Whether to indent the output. Defaults to true. + /// The JSON string representation of this instance. + public string ToJson(SaveContext? context = null, bool indent = true) + { + context ??= new SaveContext(); + return context.ToJson(Save(context), indent); + } + + /// + /// Load a RedactedField instance from a JSON string. + /// + /// The JSON string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded RedactedField instance. + public static RedactedField FromJson(string json, LoadContext? context = null) + { + using var doc = JsonDocument.Parse(json); + Dictionary dict; + dict = JsonSerializer.Deserialize>(json, JsonUtils.Options) + ?? throw new ArgumentException("Failed to parse JSON as dictionary"); + + return Load(dict, context); + } + + /// + /// Load a RedactedField instance from a YAML string. + /// + /// The YAML string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded RedactedField instance. + public static RedactedField FromYaml(string yaml, LoadContext? context = null) + { + var dict = YamlUtils.Deserializer.Deserialize>(yaml) + ?? throw new ArgumentException("Failed to parse YAML as dictionary"); + + return Load(dict, context); + } + + #endregion +} diff --git a/runtime/csharp/Prompty.Core/Model/events/RedactionMetadata.cs b/runtime/csharp/Prompty.Core/Model/events/RedactionMetadata.cs new file mode 100644 index 00000000..5bcf7720 --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/RedactionMetadata.cs @@ -0,0 +1,257 @@ +// Copyright (c) Microsoft. All rights reserved. +using System.Text.Json; +using YamlDotNet.Serialization; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + +/// +/// Metadata describing whether and how a payload was sanitized. +/// +public partial class RedactionMetadata +{ + /// + /// The shorthand property name for this type, if any. + /// + public static string? ShorthandProperty => null; + + /// + /// Initializes a new instance of . + /// +#pragma warning disable CS8618 + public RedactionMetadata() + { + } +#pragma warning restore CS8618 + + /// + /// Whether the payload has been sanitized for persistence or external display + /// + public bool? Sanitized { get; set; } + + /// + /// Field-level redaction details + /// + public IList? Fields { get; set; } + + /// + /// Host policy or sanitizer version that produced this metadata + /// + public string? Policy { get; set; } + + + + #region Load Methods + + /// + /// Load a RedactionMetadata instance from a dictionary. + /// + /// The dictionary containing the data. + /// Optional context with pre/post processing callbacks. + /// The loaded RedactionMetadata instance. + public static RedactionMetadata Load(Dictionary data, LoadContext? context = null) + { + if (context is not null) + { + data = context.ProcessInput(data); + } + + + // Create new instance + var instance = new RedactionMetadata(); + + + if (data.TryGetValue("sanitized", out var sanitizedValue) && sanitizedValue is not null) + { + instance.Sanitized = Convert.ToBoolean(sanitizedValue); + } + + if (data.TryGetValue("fields", out var fieldsValue) && fieldsValue is not null) + { + instance.Fields = LoadFields(fieldsValue, context); + } + + if (data.TryGetValue("policy", out var policyValue) && policyValue is not null) + { + instance.Policy = policyValue?.ToString()!; + } + + if (context is not null) + { + instance = context.ProcessOutput(instance); + } + return instance; + } + + + /// + /// Load a list of RedactedField from a dictionary or list. + /// + public static IList LoadFields(object data, LoadContext? context) + { + var result = new List(); + + if (data is Dictionary dict) + { + // Convert named dictionary to list + foreach (var kvp in dict) + { + if (kvp.Value is IEnumerable) + { + throw new ArgumentException( + $"Invalid 'fields' format: key '{kvp.Key}' has an array value. " + + $"'fields' must be a flat list of objects or a name-keyed dict — " + + "not a nested {" + kvp.Key + ": [...]} structure."); + } + var itemDict = kvp.Value.GetDictionary(); + if (itemDict.Count > 0) + { + // Value is an object, add name to it + itemDict["name"] = kvp.Key; + result.Add(RedactedField.Load(itemDict, context)); + } + else + { + // Value is a scalar, use it as the primary property + var newDict = new Dictionary + { + ["name"] = kvp.Key, + ["path"] = kvp.Value + }; + result.Add(RedactedField.Load(newDict, context)); + } + } + } + else if (data is IEnumerable list) + { + foreach (var item in list) + { + var itemDict = item.GetDictionary(RedactedField.ShorthandProperty); + if (itemDict.Count > 0) + { + result.Add(RedactedField.Load(itemDict, context)); + } + } + } + + return result; + } + + + #endregion + + #region Save Methods + + /// + /// Save the RedactionMetadata instance to a dictionary. + /// + /// Optional context with pre/post processing callbacks. + /// The dictionary representation of this instance. + public Dictionary Save(SaveContext? context = null) + { + var obj = this; + if (context is not null) + { + obj = context.ProcessObject(obj); + } + + + var result = new Dictionary(); + + + if (obj.Sanitized is not null) + { + result["sanitized"] = obj.Sanitized; + } + + + if (obj.Fields is not null) + { + result["fields"] = SaveFields(obj.Fields, context); + } + + + if (obj.Policy is not null) + { + result["policy"] = obj.Policy; + } + + + if (context is not null) + { + result = context.ProcessDict(result); + } + + return result; + } + + + /// + /// Save a list of RedactedField to object or array format. + /// + public static object SaveFields(IList items, SaveContext? context) + { + context ??= new SaveContext(); + + // This collection type does not have a 'name' property, only array format is supported + return items.Select(item => item.Save(context)).ToList(); + + } + + + /// + /// Convert the RedactionMetadata instance to a YAML string. + /// + /// Optional context with pre/post processing callbacks. + /// The YAML string representation of this instance. + public string ToYaml(SaveContext? context = null) + { + context ??= new SaveContext(); + return context.ToYaml(Save(context)); + } + + /// + /// Convert the RedactionMetadata instance to a JSON string. + /// + /// Optional context with pre/post processing callbacks. + /// Whether to indent the output. Defaults to true. + /// The JSON string representation of this instance. + public string ToJson(SaveContext? context = null, bool indent = true) + { + context ??= new SaveContext(); + return context.ToJson(Save(context), indent); + } + + /// + /// Load a RedactionMetadata instance from a JSON string. + /// + /// The JSON string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded RedactionMetadata instance. + public static RedactionMetadata FromJson(string json, LoadContext? context = null) + { + using var doc = JsonDocument.Parse(json); + Dictionary dict; + dict = JsonSerializer.Deserialize>(json, JsonUtils.Options) + ?? throw new ArgumentException("Failed to parse JSON as dictionary"); + + return Load(dict, context); + } + + /// + /// Load a RedactionMetadata instance from a YAML string. + /// + /// The YAML string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded RedactionMetadata instance. + public static RedactionMetadata FromYaml(string yaml, LoadContext? context = null) + { + var dict = YamlUtils.Deserializer.Deserialize>(yaml) + ?? throw new ArgumentException("Failed to parse YAML as dictionary"); + + return Load(dict, context); + } + + #endregion +} diff --git a/runtime/csharp/Prompty.Core/Model/events/RedactionMode.cs b/runtime/csharp/Prompty.Core/Model/events/RedactionMode.cs new file mode 100644 index 00000000..fb5bdcca --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/RedactionMode.cs @@ -0,0 +1,26 @@ +// +// Code generated by Prompty emitter; DO NOT EDIT. + +using System.Text.Json.Serialization; + +namespace Prompty.Core; + +[JsonConverter(typeof(JsonStringEnumConverter))] +public enum RedactionMode +{ + [JsonPropertyName("none")] + None, + + [JsonPropertyName("redacted")] + Redacted, + + [JsonPropertyName("hashed")] + Hashed, + + [JsonPropertyName("summary")] + Summary, + + [JsonPropertyName("reference")] + Reference, + +} diff --git a/runtime/csharp/Prompty.Core/Model/events/SessionEndPayload.cs b/runtime/csharp/Prompty.Core/Model/events/SessionEndPayload.cs new file mode 100644 index 00000000..abe74a0f --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/SessionEndPayload.cs @@ -0,0 +1,206 @@ +// Copyright (c) Microsoft. All rights reserved. +using System.Text.Json; +using YamlDotNet.Serialization; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + +/// +/// Payload for "session_end" events. +/// +public partial class SessionEndPayload +{ + /// + /// The shorthand property name for this type, if any. + /// + public static string? ShorthandProperty => null; + + /// + /// Initializes a new instance of . + /// +#pragma warning disable CS8618 + public SessionEndPayload() + { + } +#pragma warning restore CS8618 + + /// + /// Stable session identifier + /// + public string? SessionId { get; set; } + + /// + /// Final session status + /// + public SessionEndStatus? Status { get; set; } + + /// + /// Host-specific reason the session ended + /// + public string? Reason { get; set; } + + /// + /// Total elapsed session duration in milliseconds + /// + public double? DurationMs { get; set; } + + + + #region Load Methods + + /// + /// Load a SessionEndPayload instance from a dictionary. + /// + /// The dictionary containing the data. + /// Optional context with pre/post processing callbacks. + /// The loaded SessionEndPayload instance. + public static SessionEndPayload Load(Dictionary data, LoadContext? context = null) + { + if (context is not null) + { + data = context.ProcessInput(data); + } + + + // Create new instance + var instance = new SessionEndPayload(); + + + if (data.TryGetValue("sessionId", out var sessionIdValue) && sessionIdValue is not null) + { + instance.SessionId = sessionIdValue?.ToString()!; + } + + if (data.TryGetValue("status", out var statusValue) && statusValue is not null) + { + instance.Status = Enum.Parse(statusValue?.ToString()!, true); + } + + if (data.TryGetValue("reason", out var reasonValue) && reasonValue is not null) + { + instance.Reason = reasonValue?.ToString()!; + } + + if (data.TryGetValue("durationMs", out var durationMsValue) && durationMsValue is not null) + { + instance.DurationMs = Convert.ToDouble(durationMsValue); + } + + if (context is not null) + { + instance = context.ProcessOutput(instance); + } + return instance; + } + + + #endregion + + #region Save Methods + + /// + /// Save the SessionEndPayload instance to a dictionary. + /// + /// Optional context with pre/post processing callbacks. + /// The dictionary representation of this instance. + public Dictionary Save(SaveContext? context = null) + { + var obj = this; + if (context is not null) + { + obj = context.ProcessObject(obj); + } + + + var result = new Dictionary(); + + + if (obj.SessionId is not null) + { + result["sessionId"] = obj.SessionId; + } + + + if (obj.Status is not null) + { + result["status"] = obj.Status.Value.ToString().ToLowerInvariant(); + } + + + if (obj.Reason is not null) + { + result["reason"] = obj.Reason; + } + + + if (obj.DurationMs is not null) + { + result["durationMs"] = obj.DurationMs; + } + + + if (context is not null) + { + result = context.ProcessDict(result); + } + + return result; + } + + + /// + /// Convert the SessionEndPayload instance to a YAML string. + /// + /// Optional context with pre/post processing callbacks. + /// The YAML string representation of this instance. + public string ToYaml(SaveContext? context = null) + { + context ??= new SaveContext(); + return context.ToYaml(Save(context)); + } + + /// + /// Convert the SessionEndPayload instance to a JSON string. + /// + /// Optional context with pre/post processing callbacks. + /// Whether to indent the output. Defaults to true. + /// The JSON string representation of this instance. + public string ToJson(SaveContext? context = null, bool indent = true) + { + context ??= new SaveContext(); + return context.ToJson(Save(context), indent); + } + + /// + /// Load a SessionEndPayload instance from a JSON string. + /// + /// The JSON string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded SessionEndPayload instance. + public static SessionEndPayload FromJson(string json, LoadContext? context = null) + { + using var doc = JsonDocument.Parse(json); + Dictionary dict; + dict = JsonSerializer.Deserialize>(json, JsonUtils.Options) + ?? throw new ArgumentException("Failed to parse JSON as dictionary"); + + return Load(dict, context); + } + + /// + /// Load a SessionEndPayload instance from a YAML string. + /// + /// The YAML string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded SessionEndPayload instance. + public static SessionEndPayload FromYaml(string yaml, LoadContext? context = null) + { + var dict = YamlUtils.Deserializer.Deserialize>(yaml) + ?? throw new ArgumentException("Failed to parse YAML as dictionary"); + + return Load(dict, context); + } + + #endregion +} diff --git a/runtime/csharp/Prompty.Core/Model/events/SessionEndStatus.cs b/runtime/csharp/Prompty.Core/Model/events/SessionEndStatus.cs new file mode 100644 index 00000000..2294745a --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/SessionEndStatus.cs @@ -0,0 +1,23 @@ +// +// Code generated by Prompty emitter; DO NOT EDIT. + +using System.Text.Json.Serialization; + +namespace Prompty.Core; + +[JsonConverter(typeof(JsonStringEnumConverter))] +public enum SessionEndStatus +{ + [JsonPropertyName("success")] + Success, + + [JsonPropertyName("error")] + Error, + + [JsonPropertyName("cancelled")] + Cancelled, + + [JsonPropertyName("interrupted")] + Interrupted, + +} diff --git a/runtime/csharp/Prompty.Core/Model/events/SessionEvent.cs b/runtime/csharp/Prompty.Core/Model/events/SessionEvent.cs new file mode 100644 index 00000000..953c332c --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/SessionEvent.cs @@ -0,0 +1,274 @@ +// Copyright (c) Microsoft. All rights reserved. +using System.Text.Json; +using YamlDotNet.Serialization; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + +/// +/// A canonical event envelope emitted by an outer harness session. +/// +public partial class SessionEvent +{ + /// + /// The shorthand property name for this type, if any. + /// + public static string? ShorthandProperty => null; + + /// + /// Initializes a new instance of . + /// +#pragma warning disable CS8618 + public SessionEvent() + { + } +#pragma warning restore CS8618 + + /// + /// Unique identifier for this event + /// + public string Id { get; set; } = string.Empty; + + /// + /// Event type discriminator + /// + public SessionEventType Type { get; set; } = SessionEventType.SessionStart; + + /// + /// ISO 8601 UTC timestamp when the event was emitted + /// + public string Timestamp { get; set; } = string.Empty; + + /// + /// Stable identifier for the outer session + /// + public string? SessionId { get; set; } + + /// + /// Associated turn identifier, when this session event is linked to a turn + /// + public string? TurnId { get; set; } + + /// + /// Parent event or span identifier for reconstructing event hierarchy + /// + public string? ParentId { get; set; } + + /// + /// Trace span identifier associated with this event + /// + public string? SpanId { get; set; } + + /// + /// Event-specific payload. Use the typed payload model matching 'type'. + /// + public IDictionary Payload { get; set; } = new Dictionary(); + + /// + /// Redaction state for sensitive payload fields + /// + public RedactionMetadata? Redaction { get; set; } + + + + #region Load Methods + + /// + /// Load a SessionEvent instance from a dictionary. + /// + /// The dictionary containing the data. + /// Optional context with pre/post processing callbacks. + /// The loaded SessionEvent instance. + public static SessionEvent Load(Dictionary data, LoadContext? context = null) + { + if (context is not null) + { + data = context.ProcessInput(data); + } + + + // Create new instance + var instance = new SessionEvent(); + + + if (data.TryGetValue("id", out var idValue) && idValue is not null) + { + instance.Id = idValue?.ToString()!; + } + + if (data.TryGetValue("type", out var typeValue) && typeValue is not null) + { + instance.Type = Enum.Parse(typeValue?.ToString()!, true); + } + + if (data.TryGetValue("timestamp", out var timestampValue) && timestampValue is not null) + { + instance.Timestamp = timestampValue?.ToString()!; + } + + if (data.TryGetValue("sessionId", out var sessionIdValue) && sessionIdValue is not null) + { + instance.SessionId = sessionIdValue?.ToString()!; + } + + if (data.TryGetValue("turnId", out var turnIdValue) && turnIdValue is not null) + { + instance.TurnId = turnIdValue?.ToString()!; + } + + if (data.TryGetValue("parentId", out var parentIdValue) && parentIdValue is not null) + { + instance.ParentId = parentIdValue?.ToString()!; + } + + if (data.TryGetValue("spanId", out var spanIdValue) && spanIdValue is not null) + { + instance.SpanId = spanIdValue?.ToString()!; + } + + if (data.TryGetValue("payload", out var payloadValue) && payloadValue is not null) + { + instance.Payload = payloadValue.GetDictionary()!; + } + + if (data.TryGetValue("redaction", out var redactionValue) && redactionValue is not null) + { + instance.Redaction = RedactionMetadata.Load(redactionValue.GetDictionary(RedactionMetadata.ShorthandProperty), context); + } + + if (context is not null) + { + instance = context.ProcessOutput(instance); + } + return instance; + } + + + #endregion + + #region Save Methods + + /// + /// Save the SessionEvent instance to a dictionary. + /// + /// Optional context with pre/post processing callbacks. + /// The dictionary representation of this instance. + public Dictionary Save(SaveContext? context = null) + { + var obj = this; + if (context is not null) + { + obj = context.ProcessObject(obj); + } + + + var result = new Dictionary(); + + + result["id"] = obj.Id; + + + result["type"] = obj.Type.ToString().ToLowerInvariant(); + + + result["timestamp"] = obj.Timestamp; + + + if (obj.SessionId is not null) + { + result["sessionId"] = obj.SessionId; + } + + + if (obj.TurnId is not null) + { + result["turnId"] = obj.TurnId; + } + + + if (obj.ParentId is not null) + { + result["parentId"] = obj.ParentId; + } + + + if (obj.SpanId is not null) + { + result["spanId"] = obj.SpanId; + } + + + result["payload"] = obj.Payload; + + + if (obj.Redaction is not null) + { + result["redaction"] = obj.Redaction?.Save(context); + } + + + if (context is not null) + { + result = context.ProcessDict(result); + } + + return result; + } + + + /// + /// Convert the SessionEvent instance to a YAML string. + /// + /// Optional context with pre/post processing callbacks. + /// The YAML string representation of this instance. + public string ToYaml(SaveContext? context = null) + { + context ??= new SaveContext(); + return context.ToYaml(Save(context)); + } + + /// + /// Convert the SessionEvent instance to a JSON string. + /// + /// Optional context with pre/post processing callbacks. + /// Whether to indent the output. Defaults to true. + /// The JSON string representation of this instance. + public string ToJson(SaveContext? context = null, bool indent = true) + { + context ??= new SaveContext(); + return context.ToJson(Save(context), indent); + } + + /// + /// Load a SessionEvent instance from a JSON string. + /// + /// The JSON string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded SessionEvent instance. + public static SessionEvent FromJson(string json, LoadContext? context = null) + { + using var doc = JsonDocument.Parse(json); + Dictionary dict; + dict = JsonSerializer.Deserialize>(json, JsonUtils.Options) + ?? throw new ArgumentException("Failed to parse JSON as dictionary"); + + return Load(dict, context); + } + + /// + /// Load a SessionEvent instance from a YAML string. + /// + /// The YAML string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded SessionEvent instance. + public static SessionEvent FromYaml(string yaml, LoadContext? context = null) + { + var dict = YamlUtils.Deserializer.Deserialize>(yaml) + ?? throw new ArgumentException("Failed to parse YAML as dictionary"); + + return Load(dict, context); + } + + #endregion +} diff --git a/runtime/csharp/Prompty.Core/Model/events/SessionEventType.cs b/runtime/csharp/Prompty.Core/Model/events/SessionEventType.cs new file mode 100644 index 00000000..14e57015 --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/SessionEventType.cs @@ -0,0 +1,32 @@ +// +// Code generated by Prompty emitter; DO NOT EDIT. + +using System.Text.Json.Serialization; + +namespace Prompty.Core; + +[JsonConverter(typeof(JsonStringEnumConverter))] +public enum SessionEventType +{ + [JsonPropertyName("session_start")] + SessionStart, + + [JsonPropertyName("session_end")] + SessionEnd, + + [JsonPropertyName("session_warning")] + SessionWarning, + + [JsonPropertyName("session_hook_start")] + SessionHookStart, + + [JsonPropertyName("session_hook_end")] + SessionHookEnd, + + [JsonPropertyName("checkpoint_created")] + CheckpointCreated, + + [JsonPropertyName("trajectory_event")] + TrajectoryEvent, + +} diff --git a/runtime/csharp/Prompty.Core/Model/events/SessionFileRef.cs b/runtime/csharp/Prompty.Core/Model/events/SessionFileRef.cs new file mode 100644 index 00000000..3348def8 --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/SessionFileRef.cs @@ -0,0 +1,219 @@ +// Copyright (c) Microsoft. All rights reserved. +using System.Text.Json; +using YamlDotNet.Serialization; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + +/// +/// A file observed or touched by a harness session. +/// +public partial class SessionFileRef +{ + /// + /// The shorthand property name for this type, if any. + /// + public static string? ShorthandProperty => null; + + /// + /// Initializes a new instance of . + /// +#pragma warning disable CS8618 + public SessionFileRef() + { + } +#pragma warning restore CS8618 + + /// + /// Stable session identifier + /// + public string? SessionId { get; set; } + + /// + /// File path, relative to the harness workspace when possible + /// + public string Path { get; set; } = string.Empty; + + /// + /// Tool that first observed the file, when known + /// + public string? ToolName { get; set; } + + /// + /// Zero-based turn index where the file was first observed + /// + public int? TurnIndex { get; set; } + + /// + /// ISO 8601 UTC timestamp when the file was first observed + /// + public string? FirstSeenAt { get; set; } + + + + #region Load Methods + + /// + /// Load a SessionFileRef instance from a dictionary. + /// + /// The dictionary containing the data. + /// Optional context with pre/post processing callbacks. + /// The loaded SessionFileRef instance. + public static SessionFileRef Load(Dictionary data, LoadContext? context = null) + { + if (context is not null) + { + data = context.ProcessInput(data); + } + + + // Create new instance + var instance = new SessionFileRef(); + + + if (data.TryGetValue("sessionId", out var sessionIdValue) && sessionIdValue is not null) + { + instance.SessionId = sessionIdValue?.ToString()!; + } + + if (data.TryGetValue("path", out var pathValue) && pathValue is not null) + { + instance.Path = pathValue?.ToString()!; + } + + if (data.TryGetValue("toolName", out var toolNameValue) && toolNameValue is not null) + { + instance.ToolName = toolNameValue?.ToString()!; + } + + if (data.TryGetValue("turnIndex", out var turnIndexValue) && turnIndexValue is not null) + { + instance.TurnIndex = Convert.ToInt32(turnIndexValue); + } + + if (data.TryGetValue("firstSeenAt", out var firstSeenAtValue) && firstSeenAtValue is not null) + { + instance.FirstSeenAt = firstSeenAtValue?.ToString()!; + } + + if (context is not null) + { + instance = context.ProcessOutput(instance); + } + return instance; + } + + + #endregion + + #region Save Methods + + /// + /// Save the SessionFileRef instance to a dictionary. + /// + /// Optional context with pre/post processing callbacks. + /// The dictionary representation of this instance. + public Dictionary Save(SaveContext? context = null) + { + var obj = this; + if (context is not null) + { + obj = context.ProcessObject(obj); + } + + + var result = new Dictionary(); + + + if (obj.SessionId is not null) + { + result["sessionId"] = obj.SessionId; + } + + + result["path"] = obj.Path; + + + if (obj.ToolName is not null) + { + result["toolName"] = obj.ToolName; + } + + + if (obj.TurnIndex is not null) + { + result["turnIndex"] = obj.TurnIndex; + } + + + if (obj.FirstSeenAt is not null) + { + result["firstSeenAt"] = obj.FirstSeenAt; + } + + + if (context is not null) + { + result = context.ProcessDict(result); + } + + return result; + } + + + /// + /// Convert the SessionFileRef instance to a YAML string. + /// + /// Optional context with pre/post processing callbacks. + /// The YAML string representation of this instance. + public string ToYaml(SaveContext? context = null) + { + context ??= new SaveContext(); + return context.ToYaml(Save(context)); + } + + /// + /// Convert the SessionFileRef instance to a JSON string. + /// + /// Optional context with pre/post processing callbacks. + /// Whether to indent the output. Defaults to true. + /// The JSON string representation of this instance. + public string ToJson(SaveContext? context = null, bool indent = true) + { + context ??= new SaveContext(); + return context.ToJson(Save(context), indent); + } + + /// + /// Load a SessionFileRef instance from a JSON string. + /// + /// The JSON string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded SessionFileRef instance. + public static SessionFileRef FromJson(string json, LoadContext? context = null) + { + using var doc = JsonDocument.Parse(json); + Dictionary dict; + dict = JsonSerializer.Deserialize>(json, JsonUtils.Options) + ?? throw new ArgumentException("Failed to parse JSON as dictionary"); + + return Load(dict, context); + } + + /// + /// Load a SessionFileRef instance from a YAML string. + /// + /// The YAML string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded SessionFileRef instance. + public static SessionFileRef FromYaml(string yaml, LoadContext? context = null) + { + var dict = YamlUtils.Deserializer.Deserialize>(yaml) + ?? throw new ArgumentException("Failed to parse YAML as dictionary"); + + return Load(dict, context); + } + + #endregion +} diff --git a/runtime/csharp/Prompty.Core/Model/events/SessionRef.cs b/runtime/csharp/Prompty.Core/Model/events/SessionRef.cs new file mode 100644 index 00000000..4594a137 --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/SessionRef.cs @@ -0,0 +1,216 @@ +// Copyright (c) Microsoft. All rights reserved. +using System.Text.Json; +using YamlDotNet.Serialization; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + +/// +/// A non-file reference observed by a harness session. +/// +public partial class SessionRef +{ + /// + /// The shorthand property name for this type, if any. + /// + public static string? ShorthandProperty => null; + + /// + /// Initializes a new instance of . + /// +#pragma warning disable CS8618 + public SessionRef() + { + } +#pragma warning restore CS8618 + + /// + /// Stable session identifier + /// + public string? SessionId { get; set; } + + /// + /// Reference category + /// + public string RefType { get; set; } = string.Empty; + + /// + /// Reference value + /// + public string RefValue { get; set; } = string.Empty; + + /// + /// Zero-based turn index where the reference was first observed + /// + public int? TurnIndex { get; set; } + + /// + /// ISO 8601 UTC timestamp when the reference was recorded + /// + public string? CreatedAt { get; set; } + + + + #region Load Methods + + /// + /// Load a SessionRef instance from a dictionary. + /// + /// The dictionary containing the data. + /// Optional context with pre/post processing callbacks. + /// The loaded SessionRef instance. + public static SessionRef Load(Dictionary data, LoadContext? context = null) + { + if (context is not null) + { + data = context.ProcessInput(data); + } + + + // Create new instance + var instance = new SessionRef(); + + + if (data.TryGetValue("sessionId", out var sessionIdValue) && sessionIdValue is not null) + { + instance.SessionId = sessionIdValue?.ToString()!; + } + + if (data.TryGetValue("refType", out var refTypeValue) && refTypeValue is not null) + { + instance.RefType = refTypeValue?.ToString()!; + } + + if (data.TryGetValue("refValue", out var refValueValue) && refValueValue is not null) + { + instance.RefValue = refValueValue?.ToString()!; + } + + if (data.TryGetValue("turnIndex", out var turnIndexValue) && turnIndexValue is not null) + { + instance.TurnIndex = Convert.ToInt32(turnIndexValue); + } + + if (data.TryGetValue("createdAt", out var createdAtValue) && createdAtValue is not null) + { + instance.CreatedAt = createdAtValue?.ToString()!; + } + + if (context is not null) + { + instance = context.ProcessOutput(instance); + } + return instance; + } + + + #endregion + + #region Save Methods + + /// + /// Save the SessionRef instance to a dictionary. + /// + /// Optional context with pre/post processing callbacks. + /// The dictionary representation of this instance. + public Dictionary Save(SaveContext? context = null) + { + var obj = this; + if (context is not null) + { + obj = context.ProcessObject(obj); + } + + + var result = new Dictionary(); + + + if (obj.SessionId is not null) + { + result["sessionId"] = obj.SessionId; + } + + + result["refType"] = obj.RefType; + + + result["refValue"] = obj.RefValue; + + + if (obj.TurnIndex is not null) + { + result["turnIndex"] = obj.TurnIndex; + } + + + if (obj.CreatedAt is not null) + { + result["createdAt"] = obj.CreatedAt; + } + + + if (context is not null) + { + result = context.ProcessDict(result); + } + + return result; + } + + + /// + /// Convert the SessionRef instance to a YAML string. + /// + /// Optional context with pre/post processing callbacks. + /// The YAML string representation of this instance. + public string ToYaml(SaveContext? context = null) + { + context ??= new SaveContext(); + return context.ToYaml(Save(context)); + } + + /// + /// Convert the SessionRef instance to a JSON string. + /// + /// Optional context with pre/post processing callbacks. + /// Whether to indent the output. Defaults to true. + /// The JSON string representation of this instance. + public string ToJson(SaveContext? context = null, bool indent = true) + { + context ??= new SaveContext(); + return context.ToJson(Save(context), indent); + } + + /// + /// Load a SessionRef instance from a JSON string. + /// + /// The JSON string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded SessionRef instance. + public static SessionRef FromJson(string json, LoadContext? context = null) + { + using var doc = JsonDocument.Parse(json); + Dictionary dict; + dict = JsonSerializer.Deserialize>(json, JsonUtils.Options) + ?? throw new ArgumentException("Failed to parse JSON as dictionary"); + + return Load(dict, context); + } + + /// + /// Load a SessionRef instance from a YAML string. + /// + /// The YAML string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded SessionRef instance. + public static SessionRef FromYaml(string yaml, LoadContext? context = null) + { + var dict = YamlUtils.Deserializer.Deserialize>(yaml) + ?? throw new ArgumentException("Failed to parse YAML as dictionary"); + + return Load(dict, context); + } + + #endregion +} diff --git a/runtime/csharp/Prompty.Core/Model/events/SessionStartPayload.cs b/runtime/csharp/Prompty.Core/Model/events/SessionStartPayload.cs new file mode 100644 index 00000000..c1282f96 --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/SessionStartPayload.cs @@ -0,0 +1,283 @@ +// Copyright (c) Microsoft. All rights reserved. +using System.Text.Json; +using YamlDotNet.Serialization; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + +/// +/// Payload for "session_start" events. +/// +public partial class SessionStartPayload +{ + /// + /// The shorthand property name for this type, if any. + /// + public static string? ShorthandProperty => null; + + /// + /// Initializes a new instance of . + /// +#pragma warning disable CS8618 + public SessionStartPayload() + { + } +#pragma warning restore CS8618 + + /// + /// Stable session identifier + /// + public string SessionId { get; set; } = string.Empty; + + /// + /// Session event schema version + /// + public int? Version { get; set; } + + /// + /// Producer that started the session + /// + public string? Producer { get; set; } + + /// + /// Runtime that produced the session + /// + public string? Runtime { get; set; } + + /// + /// Prompty library version + /// + public string? PromptyVersion { get; set; } + + /// + /// ISO 8601 UTC timestamp when the session started + /// + public string? StartTime { get; set; } + + /// + /// Selected model identifier, when known + /// + public string? SelectedModel { get; set; } + + /// + /// Selected reasoning effort or equivalent model setting, when known + /// + public string? ReasoningEffort { get; set; } + + /// + /// Repository and execution context + /// + public HarnessContext? Context { get; set; } + + + + #region Load Methods + + /// + /// Load a SessionStartPayload instance from a dictionary. + /// + /// The dictionary containing the data. + /// Optional context with pre/post processing callbacks. + /// The loaded SessionStartPayload instance. + public static SessionStartPayload Load(Dictionary data, LoadContext? context = null) + { + if (context is not null) + { + data = context.ProcessInput(data); + } + + + // Create new instance + var instance = new SessionStartPayload(); + + + if (data.TryGetValue("sessionId", out var sessionIdValue) && sessionIdValue is not null) + { + instance.SessionId = sessionIdValue?.ToString()!; + } + + if (data.TryGetValue("version", out var versionValue) && versionValue is not null) + { + instance.Version = Convert.ToInt32(versionValue); + } + + if (data.TryGetValue("producer", out var producerValue) && producerValue is not null) + { + instance.Producer = producerValue?.ToString()!; + } + + if (data.TryGetValue("runtime", out var runtimeValue) && runtimeValue is not null) + { + instance.Runtime = runtimeValue?.ToString()!; + } + + if (data.TryGetValue("promptyVersion", out var promptyVersionValue) && promptyVersionValue is not null) + { + instance.PromptyVersion = promptyVersionValue?.ToString()!; + } + + if (data.TryGetValue("startTime", out var startTimeValue) && startTimeValue is not null) + { + instance.StartTime = startTimeValue?.ToString()!; + } + + if (data.TryGetValue("selectedModel", out var selectedModelValue) && selectedModelValue is not null) + { + instance.SelectedModel = selectedModelValue?.ToString()!; + } + + if (data.TryGetValue("reasoningEffort", out var reasoningEffortValue) && reasoningEffortValue is not null) + { + instance.ReasoningEffort = reasoningEffortValue?.ToString()!; + } + + if (data.TryGetValue("context", out var contextValue) && contextValue is not null) + { + instance.Context = HarnessContext.Load(contextValue.GetDictionary(HarnessContext.ShorthandProperty), context); + } + + if (context is not null) + { + instance = context.ProcessOutput(instance); + } + return instance; + } + + + #endregion + + #region Save Methods + + /// + /// Save the SessionStartPayload instance to a dictionary. + /// + /// Optional context with pre/post processing callbacks. + /// The dictionary representation of this instance. + public Dictionary Save(SaveContext? context = null) + { + var obj = this; + if (context is not null) + { + obj = context.ProcessObject(obj); + } + + + var result = new Dictionary(); + + + result["sessionId"] = obj.SessionId; + + + if (obj.Version is not null) + { + result["version"] = obj.Version; + } + + + if (obj.Producer is not null) + { + result["producer"] = obj.Producer; + } + + + if (obj.Runtime is not null) + { + result["runtime"] = obj.Runtime; + } + + + if (obj.PromptyVersion is not null) + { + result["promptyVersion"] = obj.PromptyVersion; + } + + + if (obj.StartTime is not null) + { + result["startTime"] = obj.StartTime; + } + + + if (obj.SelectedModel is not null) + { + result["selectedModel"] = obj.SelectedModel; + } + + + if (obj.ReasoningEffort is not null) + { + result["reasoningEffort"] = obj.ReasoningEffort; + } + + + if (obj.Context is not null) + { + result["context"] = obj.Context?.Save(context); + } + + + if (context is not null) + { + result = context.ProcessDict(result); + } + + return result; + } + + + /// + /// Convert the SessionStartPayload instance to a YAML string. + /// + /// Optional context with pre/post processing callbacks. + /// The YAML string representation of this instance. + public string ToYaml(SaveContext? context = null) + { + context ??= new SaveContext(); + return context.ToYaml(Save(context)); + } + + /// + /// Convert the SessionStartPayload instance to a JSON string. + /// + /// Optional context with pre/post processing callbacks. + /// Whether to indent the output. Defaults to true. + /// The JSON string representation of this instance. + public string ToJson(SaveContext? context = null, bool indent = true) + { + context ??= new SaveContext(); + return context.ToJson(Save(context), indent); + } + + /// + /// Load a SessionStartPayload instance from a JSON string. + /// + /// The JSON string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded SessionStartPayload instance. + public static SessionStartPayload FromJson(string json, LoadContext? context = null) + { + using var doc = JsonDocument.Parse(json); + Dictionary dict; + dict = JsonSerializer.Deserialize>(json, JsonUtils.Options) + ?? throw new ArgumentException("Failed to parse JSON as dictionary"); + + return Load(dict, context); + } + + /// + /// Load a SessionStartPayload instance from a YAML string. + /// + /// The YAML string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded SessionStartPayload instance. + public static SessionStartPayload FromYaml(string yaml, LoadContext? context = null) + { + var dict = YamlUtils.Deserializer.Deserialize>(yaml) + ?? throw new ArgumentException("Failed to parse YAML as dictionary"); + + return Load(dict, context); + } + + #endregion +} diff --git a/runtime/csharp/Prompty.Core/Model/events/SessionSummary.cs b/runtime/csharp/Prompty.Core/Model/events/SessionSummary.cs new file mode 100644 index 00000000..ce388ae7 --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/SessionSummary.cs @@ -0,0 +1,235 @@ +// Copyright (c) Microsoft. All rights reserved. +using System.Text.Json; +using YamlDotNet.Serialization; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + +/// +/// Summary statistics for a completed session trace. +/// +public partial class SessionSummary +{ + /// + /// The shorthand property name for this type, if any. + /// + public static string? ShorthandProperty => null; + + /// + /// Initializes a new instance of . + /// +#pragma warning disable CS8618 + public SessionSummary() + { + } +#pragma warning restore CS8618 + + /// + /// Stable session identifier + /// + public string SessionId { get; set; } = string.Empty; + + /// + /// Final session status + /// + public SessionSummaryStatus? Status { get; set; } + + /// + /// Number of user/assistant turns in the session + /// + public int? Turns { get; set; } + + /// + /// Number of checkpoints created + /// + public int? Checkpoints { get; set; } + + /// + /// Aggregated token usage for the session + /// + public TokenUsage? Usage { get; set; } + + /// + /// Total elapsed session duration in milliseconds + /// + public double? DurationMs { get; set; } + + + + #region Load Methods + + /// + /// Load a SessionSummary instance from a dictionary. + /// + /// The dictionary containing the data. + /// Optional context with pre/post processing callbacks. + /// The loaded SessionSummary instance. + public static SessionSummary Load(Dictionary data, LoadContext? context = null) + { + if (context is not null) + { + data = context.ProcessInput(data); + } + + + // Create new instance + var instance = new SessionSummary(); + + + if (data.TryGetValue("sessionId", out var sessionIdValue) && sessionIdValue is not null) + { + instance.SessionId = sessionIdValue?.ToString()!; + } + + if (data.TryGetValue("status", out var statusValue) && statusValue is not null) + { + instance.Status = Enum.Parse(statusValue?.ToString()!, true); + } + + if (data.TryGetValue("turns", out var turnsValue) && turnsValue is not null) + { + instance.Turns = Convert.ToInt32(turnsValue); + } + + if (data.TryGetValue("checkpoints", out var checkpointsValue) && checkpointsValue is not null) + { + instance.Checkpoints = Convert.ToInt32(checkpointsValue); + } + + if (data.TryGetValue("usage", out var usageValue) && usageValue is not null) + { + instance.Usage = TokenUsage.Load(usageValue.GetDictionary(TokenUsage.ShorthandProperty), context); + } + + if (data.TryGetValue("durationMs", out var durationMsValue) && durationMsValue is not null) + { + instance.DurationMs = Convert.ToDouble(durationMsValue); + } + + if (context is not null) + { + instance = context.ProcessOutput(instance); + } + return instance; + } + + + #endregion + + #region Save Methods + + /// + /// Save the SessionSummary instance to a dictionary. + /// + /// Optional context with pre/post processing callbacks. + /// The dictionary representation of this instance. + public Dictionary Save(SaveContext? context = null) + { + var obj = this; + if (context is not null) + { + obj = context.ProcessObject(obj); + } + + + var result = new Dictionary(); + + + result["sessionId"] = obj.SessionId; + + + if (obj.Status is not null) + { + result["status"] = obj.Status.Value.ToString().ToLowerInvariant(); + } + + + if (obj.Turns is not null) + { + result["turns"] = obj.Turns; + } + + + if (obj.Checkpoints is not null) + { + result["checkpoints"] = obj.Checkpoints; + } + + + if (obj.Usage is not null) + { + result["usage"] = obj.Usage?.Save(context); + } + + + if (obj.DurationMs is not null) + { + result["durationMs"] = obj.DurationMs; + } + + + if (context is not null) + { + result = context.ProcessDict(result); + } + + return result; + } + + + /// + /// Convert the SessionSummary instance to a YAML string. + /// + /// Optional context with pre/post processing callbacks. + /// The YAML string representation of this instance. + public string ToYaml(SaveContext? context = null) + { + context ??= new SaveContext(); + return context.ToYaml(Save(context)); + } + + /// + /// Convert the SessionSummary instance to a JSON string. + /// + /// Optional context with pre/post processing callbacks. + /// Whether to indent the output. Defaults to true. + /// The JSON string representation of this instance. + public string ToJson(SaveContext? context = null, bool indent = true) + { + context ??= new SaveContext(); + return context.ToJson(Save(context), indent); + } + + /// + /// Load a SessionSummary instance from a JSON string. + /// + /// The JSON string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded SessionSummary instance. + public static SessionSummary FromJson(string json, LoadContext? context = null) + { + using var doc = JsonDocument.Parse(json); + Dictionary dict; + dict = JsonSerializer.Deserialize>(json, JsonUtils.Options) + ?? throw new ArgumentException("Failed to parse JSON as dictionary"); + + return Load(dict, context); + } + + /// + /// Load a SessionSummary instance from a YAML string. + /// + /// The YAML string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded SessionSummary instance. + public static SessionSummary FromYaml(string yaml, LoadContext? context = null) + { + var dict = YamlUtils.Deserializer.Deserialize>(yaml) + ?? throw new ArgumentException("Failed to parse YAML as dictionary"); + + return Load(dict, context); + } + + #endregion +} diff --git a/runtime/csharp/Prompty.Core/Model/events/SessionSummaryStatus.cs b/runtime/csharp/Prompty.Core/Model/events/SessionSummaryStatus.cs new file mode 100644 index 00000000..69f17e79 --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/SessionSummaryStatus.cs @@ -0,0 +1,23 @@ +// +// Code generated by Prompty emitter; DO NOT EDIT. + +using System.Text.Json.Serialization; + +namespace Prompty.Core; + +[JsonConverter(typeof(JsonStringEnumConverter))] +public enum SessionSummaryStatus +{ + [JsonPropertyName("success")] + Success, + + [JsonPropertyName("error")] + Error, + + [JsonPropertyName("cancelled")] + Cancelled, + + [JsonPropertyName("interrupted")] + Interrupted, + +} diff --git a/runtime/csharp/Prompty.Core/Model/events/SessionTrace.cs b/runtime/csharp/Prompty.Core/Model/events/SessionTrace.cs new file mode 100644 index 00000000..4886a099 --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/SessionTrace.cs @@ -0,0 +1,714 @@ +// Copyright (c) Microsoft. All rights reserved. +using System.Text.Json; +using YamlDotNet.Serialization; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + +/// +/// Portable replay container for an outer harness session. +/// +public partial class SessionTrace +{ + /// + /// The shorthand property name for this type, if any. + /// + public static string? ShorthandProperty => null; + + /// + /// Initializes a new instance of . + /// +#pragma warning disable CS8618 + public SessionTrace() + { + } +#pragma warning restore CS8618 + + /// + /// Trace schema version + /// + public string Version { get; set; } = "1"; + + /// + /// Runtime name that produced the trace + /// + public string? Runtime { get; set; } + + /// + /// Prompty library version that produced the trace + /// + public string? PromptyVersion { get; set; } + + /// + /// Stable session identifier + /// + public string? SessionId { get; set; } + + /// + /// Recorded session events in emission order + /// + public IList Events { get; set; } = []; + + /// + /// Recorded turn traces associated with the session + /// + public IList? Turns { get; set; } + + /// + /// Checkpoints created during the session + /// + public IList? Checkpoints { get; set; } + + /// + /// Compact trajectory records associated with the session + /// + public IList? Trajectory { get; set; } + + /// + /// Files observed or touched during the session + /// + public IList? Files { get; set; } + + /// + /// Non-file references observed during the session + /// + public IList? Refs { get; set; } + + /// + /// Optional summary computed from the event stream + /// + public SessionSummary? Summary { get; set; } + + + + #region Load Methods + + /// + /// Load a SessionTrace instance from a dictionary. + /// + /// The dictionary containing the data. + /// Optional context with pre/post processing callbacks. + /// The loaded SessionTrace instance. + public static SessionTrace Load(Dictionary data, LoadContext? context = null) + { + if (context is not null) + { + data = context.ProcessInput(data); + } + + + // Create new instance + var instance = new SessionTrace(); + + + if (data.TryGetValue("version", out var versionValue) && versionValue is not null) + { + instance.Version = versionValue?.ToString()!; + } + + if (data.TryGetValue("runtime", out var runtimeValue) && runtimeValue is not null) + { + instance.Runtime = runtimeValue?.ToString()!; + } + + if (data.TryGetValue("promptyVersion", out var promptyVersionValue) && promptyVersionValue is not null) + { + instance.PromptyVersion = promptyVersionValue?.ToString()!; + } + + if (data.TryGetValue("sessionId", out var sessionIdValue) && sessionIdValue is not null) + { + instance.SessionId = sessionIdValue?.ToString()!; + } + + if (data.TryGetValue("events", out var eventsValue) && eventsValue is not null) + { + instance.Events = LoadEvents(eventsValue, context); + } + + if (data.TryGetValue("turns", out var turnsValue) && turnsValue is not null) + { + instance.Turns = LoadTurns(turnsValue, context); + } + + if (data.TryGetValue("checkpoints", out var checkpointsValue) && checkpointsValue is not null) + { + instance.Checkpoints = LoadCheckpoints(checkpointsValue, context); + } + + if (data.TryGetValue("trajectory", out var trajectoryValue) && trajectoryValue is not null) + { + instance.Trajectory = LoadTrajectory(trajectoryValue, context); + } + + if (data.TryGetValue("files", out var filesValue) && filesValue is not null) + { + instance.Files = LoadFiles(filesValue, context); + } + + if (data.TryGetValue("refs", out var refsValue) && refsValue is not null) + { + instance.Refs = LoadRefs(refsValue, context); + } + + if (data.TryGetValue("summary", out var summaryValue) && summaryValue is not null) + { + instance.Summary = SessionSummary.Load(summaryValue.GetDictionary(SessionSummary.ShorthandProperty), context); + } + + if (context is not null) + { + instance = context.ProcessOutput(instance); + } + return instance; + } + + + /// + /// Load a list of SessionEvent from a dictionary or list. + /// + public static IList LoadEvents(object data, LoadContext? context) + { + var result = new List(); + + if (data is Dictionary dict) + { + // Convert named dictionary to list + foreach (var kvp in dict) + { + if (kvp.Value is IEnumerable) + { + throw new ArgumentException( + $"Invalid 'events' format: key '{kvp.Key}' has an array value. " + + $"'events' must be a flat list of objects or a name-keyed dict — " + + "not a nested {" + kvp.Key + ": [...]} structure."); + } + var itemDict = kvp.Value.GetDictionary(); + if (itemDict.Count > 0) + { + // Value is an object, add name to it + itemDict["name"] = kvp.Key; + result.Add(SessionEvent.Load(itemDict, context)); + } + else + { + // Value is a scalar, use it as the primary property + var newDict = new Dictionary + { + ["name"] = kvp.Key, + ["id"] = kvp.Value + }; + result.Add(SessionEvent.Load(newDict, context)); + } + } + } + else if (data is IEnumerable list) + { + foreach (var item in list) + { + var itemDict = item.GetDictionary(SessionEvent.ShorthandProperty); + if (itemDict.Count > 0) + { + result.Add(SessionEvent.Load(itemDict, context)); + } + } + } + + return result; + } + + + /// + /// Load a list of TurnTrace from a dictionary or list. + /// + public static IList LoadTurns(object data, LoadContext? context) + { + var result = new List(); + + if (data is Dictionary dict) + { + // Convert named dictionary to list + foreach (var kvp in dict) + { + if (kvp.Value is IEnumerable) + { + throw new ArgumentException( + $"Invalid 'turns' format: key '{kvp.Key}' has an array value. " + + $"'turns' must be a flat list of objects or a name-keyed dict — " + + "not a nested {" + kvp.Key + ": [...]} structure."); + } + var itemDict = kvp.Value.GetDictionary(); + if (itemDict.Count > 0) + { + // Value is an object, add name to it + itemDict["name"] = kvp.Key; + result.Add(TurnTrace.Load(itemDict, context)); + } + else + { + // Value is a scalar, use it as the primary property + var newDict = new Dictionary + { + ["name"] = kvp.Key, + ["version"] = kvp.Value + }; + result.Add(TurnTrace.Load(newDict, context)); + } + } + } + else if (data is IEnumerable list) + { + foreach (var item in list) + { + var itemDict = item.GetDictionary(TurnTrace.ShorthandProperty); + if (itemDict.Count > 0) + { + result.Add(TurnTrace.Load(itemDict, context)); + } + } + } + + return result; + } + + + /// + /// Load a list of Checkpoint from a dictionary or list. + /// + public static IList LoadCheckpoints(object data, LoadContext? context) + { + var result = new List(); + + if (data is Dictionary dict) + { + // Convert named dictionary to list + foreach (var kvp in dict) + { + if (kvp.Value is IEnumerable) + { + throw new ArgumentException( + $"Invalid 'checkpoints' format: key '{kvp.Key}' has an array value. " + + $"'checkpoints' must be a flat list of objects or a name-keyed dict — " + + "not a nested {" + kvp.Key + ": [...]} structure."); + } + var itemDict = kvp.Value.GetDictionary(); + if (itemDict.Count > 0) + { + // Value is an object, add name to it + itemDict["name"] = kvp.Key; + result.Add(Checkpoint.Load(itemDict, context)); + } + else + { + // Value is a scalar, use it as the primary property + var newDict = new Dictionary + { + ["name"] = kvp.Key, + ["id"] = kvp.Value + }; + result.Add(Checkpoint.Load(newDict, context)); + } + } + } + else if (data is IEnumerable list) + { + foreach (var item in list) + { + var itemDict = item.GetDictionary(Checkpoint.ShorthandProperty); + if (itemDict.Count > 0) + { + result.Add(Checkpoint.Load(itemDict, context)); + } + } + } + + return result; + } + + + /// + /// Load a list of TrajectoryEvent from a dictionary or list. + /// + public static IList LoadTrajectory(object data, LoadContext? context) + { + var result = new List(); + + if (data is Dictionary dict) + { + // Convert named dictionary to list + foreach (var kvp in dict) + { + if (kvp.Value is IEnumerable) + { + throw new ArgumentException( + $"Invalid 'trajectory' format: key '{kvp.Key}' has an array value. " + + $"'trajectory' must be a flat list of objects or a name-keyed dict — " + + "not a nested {" + kvp.Key + ": [...]} structure."); + } + var itemDict = kvp.Value.GetDictionary(); + if (itemDict.Count > 0) + { + // Value is an object, add name to it + itemDict["name"] = kvp.Key; + result.Add(TrajectoryEvent.Load(itemDict, context)); + } + else + { + // Value is a scalar, use it as the primary property + var newDict = new Dictionary + { + ["name"] = kvp.Key, + ["id"] = kvp.Value + }; + result.Add(TrajectoryEvent.Load(newDict, context)); + } + } + } + else if (data is IEnumerable list) + { + foreach (var item in list) + { + var itemDict = item.GetDictionary(TrajectoryEvent.ShorthandProperty); + if (itemDict.Count > 0) + { + result.Add(TrajectoryEvent.Load(itemDict, context)); + } + } + } + + return result; + } + + + /// + /// Load a list of SessionFileRef from a dictionary or list. + /// + public static IList LoadFiles(object data, LoadContext? context) + { + var result = new List(); + + if (data is Dictionary dict) + { + // Convert named dictionary to list + foreach (var kvp in dict) + { + if (kvp.Value is IEnumerable) + { + throw new ArgumentException( + $"Invalid 'files' format: key '{kvp.Key}' has an array value. " + + $"'files' must be a flat list of objects or a name-keyed dict — " + + "not a nested {" + kvp.Key + ": [...]} structure."); + } + var itemDict = kvp.Value.GetDictionary(); + if (itemDict.Count > 0) + { + // Value is an object, add name to it + itemDict["name"] = kvp.Key; + result.Add(SessionFileRef.Load(itemDict, context)); + } + else + { + // Value is a scalar, use it as the primary property + var newDict = new Dictionary + { + ["name"] = kvp.Key, + ["sessionId"] = kvp.Value + }; + result.Add(SessionFileRef.Load(newDict, context)); + } + } + } + else if (data is IEnumerable list) + { + foreach (var item in list) + { + var itemDict = item.GetDictionary(SessionFileRef.ShorthandProperty); + if (itemDict.Count > 0) + { + result.Add(SessionFileRef.Load(itemDict, context)); + } + } + } + + return result; + } + + + /// + /// Load a list of SessionRef from a dictionary or list. + /// + public static IList LoadRefs(object data, LoadContext? context) + { + var result = new List(); + + if (data is Dictionary dict) + { + // Convert named dictionary to list + foreach (var kvp in dict) + { + if (kvp.Value is IEnumerable) + { + throw new ArgumentException( + $"Invalid 'refs' format: key '{kvp.Key}' has an array value. " + + $"'refs' must be a flat list of objects or a name-keyed dict — " + + "not a nested {" + kvp.Key + ": [...]} structure."); + } + var itemDict = kvp.Value.GetDictionary(); + if (itemDict.Count > 0) + { + // Value is an object, add name to it + itemDict["name"] = kvp.Key; + result.Add(SessionRef.Load(itemDict, context)); + } + else + { + // Value is a scalar, use it as the primary property + var newDict = new Dictionary + { + ["name"] = kvp.Key, + ["sessionId"] = kvp.Value + }; + result.Add(SessionRef.Load(newDict, context)); + } + } + } + else if (data is IEnumerable list) + { + foreach (var item in list) + { + var itemDict = item.GetDictionary(SessionRef.ShorthandProperty); + if (itemDict.Count > 0) + { + result.Add(SessionRef.Load(itemDict, context)); + } + } + } + + return result; + } + + + #endregion + + #region Save Methods + + /// + /// Save the SessionTrace instance to a dictionary. + /// + /// Optional context with pre/post processing callbacks. + /// The dictionary representation of this instance. + public Dictionary Save(SaveContext? context = null) + { + var obj = this; + if (context is not null) + { + obj = context.ProcessObject(obj); + } + + + var result = new Dictionary(); + + + result["version"] = obj.Version; + + + if (obj.Runtime is not null) + { + result["runtime"] = obj.Runtime; + } + + + if (obj.PromptyVersion is not null) + { + result["promptyVersion"] = obj.PromptyVersion; + } + + + if (obj.SessionId is not null) + { + result["sessionId"] = obj.SessionId; + } + + + result["events"] = SaveEvents(obj.Events, context); + + + if (obj.Turns is not null) + { + result["turns"] = SaveTurns(obj.Turns, context); + } + + + if (obj.Checkpoints is not null) + { + result["checkpoints"] = SaveCheckpoints(obj.Checkpoints, context); + } + + + if (obj.Trajectory is not null) + { + result["trajectory"] = SaveTrajectory(obj.Trajectory, context); + } + + + if (obj.Files is not null) + { + result["files"] = SaveFiles(obj.Files, context); + } + + + if (obj.Refs is not null) + { + result["refs"] = SaveRefs(obj.Refs, context); + } + + + if (obj.Summary is not null) + { + result["summary"] = obj.Summary?.Save(context); + } + + + if (context is not null) + { + result = context.ProcessDict(result); + } + + return result; + } + + + /// + /// Save a list of SessionEvent to object or array format. + /// + public static object SaveEvents(IList items, SaveContext? context) + { + context ??= new SaveContext(); + + // This collection type does not have a 'name' property, only array format is supported + return items.Select(item => item.Save(context)).ToList(); + + } + + + /// + /// Save a list of TurnTrace to object or array format. + /// + public static object SaveTurns(IList items, SaveContext? context) + { + context ??= new SaveContext(); + + // This collection type does not have a 'name' property, only array format is supported + return items.Select(item => item.Save(context)).ToList(); + + } + + + /// + /// Save a list of Checkpoint to object or array format. + /// + public static object SaveCheckpoints(IList items, SaveContext? context) + { + context ??= new SaveContext(); + + // This collection type does not have a 'name' property, only array format is supported + return items.Select(item => item.Save(context)).ToList(); + + } + + + /// + /// Save a list of TrajectoryEvent to object or array format. + /// + public static object SaveTrajectory(IList items, SaveContext? context) + { + context ??= new SaveContext(); + + // This collection type does not have a 'name' property, only array format is supported + return items.Select(item => item.Save(context)).ToList(); + + } + + + /// + /// Save a list of SessionFileRef to object or array format. + /// + public static object SaveFiles(IList items, SaveContext? context) + { + context ??= new SaveContext(); + + // This collection type does not have a 'name' property, only array format is supported + return items.Select(item => item.Save(context)).ToList(); + + } + + + /// + /// Save a list of SessionRef to object or array format. + /// + public static object SaveRefs(IList items, SaveContext? context) + { + context ??= new SaveContext(); + + // This collection type does not have a 'name' property, only array format is supported + return items.Select(item => item.Save(context)).ToList(); + + } + + + /// + /// Convert the SessionTrace instance to a YAML string. + /// + /// Optional context with pre/post processing callbacks. + /// The YAML string representation of this instance. + public string ToYaml(SaveContext? context = null) + { + context ??= new SaveContext(); + return context.ToYaml(Save(context)); + } + + /// + /// Convert the SessionTrace instance to a JSON string. + /// + /// Optional context with pre/post processing callbacks. + /// Whether to indent the output. Defaults to true. + /// The JSON string representation of this instance. + public string ToJson(SaveContext? context = null, bool indent = true) + { + context ??= new SaveContext(); + return context.ToJson(Save(context), indent); + } + + /// + /// Load a SessionTrace instance from a JSON string. + /// + /// The JSON string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded SessionTrace instance. + public static SessionTrace FromJson(string json, LoadContext? context = null) + { + using var doc = JsonDocument.Parse(json); + Dictionary dict; + dict = JsonSerializer.Deserialize>(json, JsonUtils.Options) + ?? throw new ArgumentException("Failed to parse JSON as dictionary"); + + return Load(dict, context); + } + + /// + /// Load a SessionTrace instance from a YAML string. + /// + /// The YAML string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded SessionTrace instance. + public static SessionTrace FromYaml(string yaml, LoadContext? context = null) + { + var dict = YamlUtils.Deserializer.Deserialize>(yaml) + ?? throw new ArgumentException("Failed to parse YAML as dictionary"); + + return Load(dict, context); + } + + #endregion +} diff --git a/runtime/csharp/Prompty.Core/Model/events/SessionWarningPayload.cs b/runtime/csharp/Prompty.Core/Model/events/SessionWarningPayload.cs new file mode 100644 index 00000000..3456a18c --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/SessionWarningPayload.cs @@ -0,0 +1,184 @@ +// Copyright (c) Microsoft. All rights reserved. +using System.Text.Json; +using YamlDotNet.Serialization; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + +/// +/// Payload for "session_warning" events. +/// +public partial class SessionWarningPayload +{ + /// + /// The shorthand property name for this type, if any. + /// + public static string? ShorthandProperty => null; + + /// + /// Initializes a new instance of . + /// +#pragma warning disable CS8618 + public SessionWarningPayload() + { + } +#pragma warning restore CS8618 + + /// + /// Stable machine-readable warning category + /// + public string WarningType { get; set; } = string.Empty; + + /// + /// Human-readable warning message + /// + public string Message { get; set; } = string.Empty; + + /// + /// Additional host-specific warning details + /// + public IDictionary? Details { get; set; } + + + + #region Load Methods + + /// + /// Load a SessionWarningPayload instance from a dictionary. + /// + /// The dictionary containing the data. + /// Optional context with pre/post processing callbacks. + /// The loaded SessionWarningPayload instance. + public static SessionWarningPayload Load(Dictionary data, LoadContext? context = null) + { + if (context is not null) + { + data = context.ProcessInput(data); + } + + + // Create new instance + var instance = new SessionWarningPayload(); + + + if (data.TryGetValue("warningType", out var warningTypeValue) && warningTypeValue is not null) + { + instance.WarningType = warningTypeValue?.ToString()!; + } + + if (data.TryGetValue("message", out var messageValue) && messageValue is not null) + { + instance.Message = messageValue?.ToString()!; + } + + if (data.TryGetValue("details", out var detailsValue) && detailsValue is not null) + { + instance.Details = detailsValue.GetDictionary()!; + } + + if (context is not null) + { + instance = context.ProcessOutput(instance); + } + return instance; + } + + + #endregion + + #region Save Methods + + /// + /// Save the SessionWarningPayload instance to a dictionary. + /// + /// Optional context with pre/post processing callbacks. + /// The dictionary representation of this instance. + public Dictionary Save(SaveContext? context = null) + { + var obj = this; + if (context is not null) + { + obj = context.ProcessObject(obj); + } + + + var result = new Dictionary(); + + + result["warningType"] = obj.WarningType; + + + result["message"] = obj.Message; + + + if (obj.Details is not null) + { + result["details"] = obj.Details; + } + + + if (context is not null) + { + result = context.ProcessDict(result); + } + + return result; + } + + + /// + /// Convert the SessionWarningPayload instance to a YAML string. + /// + /// Optional context with pre/post processing callbacks. + /// The YAML string representation of this instance. + public string ToYaml(SaveContext? context = null) + { + context ??= new SaveContext(); + return context.ToYaml(Save(context)); + } + + /// + /// Convert the SessionWarningPayload instance to a JSON string. + /// + /// Optional context with pre/post processing callbacks. + /// Whether to indent the output. Defaults to true. + /// The JSON string representation of this instance. + public string ToJson(SaveContext? context = null, bool indent = true) + { + context ??= new SaveContext(); + return context.ToJson(Save(context), indent); + } + + /// + /// Load a SessionWarningPayload instance from a JSON string. + /// + /// The JSON string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded SessionWarningPayload instance. + public static SessionWarningPayload FromJson(string json, LoadContext? context = null) + { + using var doc = JsonDocument.Parse(json); + Dictionary dict; + dict = JsonSerializer.Deserialize>(json, JsonUtils.Options) + ?? throw new ArgumentException("Failed to parse JSON as dictionary"); + + return Load(dict, context); + } + + /// + /// Load a SessionWarningPayload instance from a YAML string. + /// + /// The YAML string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded SessionWarningPayload instance. + public static SessionWarningPayload FromYaml(string yaml, LoadContext? context = null) + { + var dict = YamlUtils.Deserializer.Deserialize>(yaml) + ?? throw new ArgumentException("Failed to parse YAML as dictionary"); + + return Load(dict, context); + } + + #endregion +} diff --git a/runtime/csharp/Prompty.Core/Model/events/ToolExecutionCompletePayload.cs b/runtime/csharp/Prompty.Core/Model/events/ToolExecutionCompletePayload.cs new file mode 100644 index 00000000..20a92ac7 --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/ToolExecutionCompletePayload.cs @@ -0,0 +1,296 @@ +// Copyright (c) Microsoft. All rights reserved. +using System.Text.Json; +using YamlDotNet.Serialization; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + +/// +/// Payload for "tool_execution_complete" events — a concrete host tool execution finished. +/// +public partial class ToolExecutionCompletePayload +{ + /// + /// The shorthand property name for this type, if any. + /// + public static string? ShorthandProperty => null; + + /// + /// Initializes a new instance of . + /// +#pragma warning disable CS8618 + public ToolExecutionCompletePayload() + { + } +#pragma warning restore CS8618 + + /// + /// Stable host execution request identifier + /// + public string? RequestId { get; set; } + + /// + /// Associated model tool call identifier, when available + /// + public string? ToolCallId { get; set; } + + /// + /// Name of the host tool that executed + /// + public string ToolName { get; set; } = string.Empty; + + /// + /// Whether the host execution completed successfully + /// + public bool Success { get; set; } = false; + + /// + /// Host-normalized execution result + /// + public object? Result { get; set; } + + /// + /// Process or host exit code, when applicable + /// + public int? ExitCode { get; set; } + + /// + /// Tool execution duration in milliseconds + /// + public double? DurationMs { get; set; } + + /// + /// Machine-readable error category when success is false + /// + public string? ErrorKind { get; set; } + + /// + /// Host-specific telemetry for the execution + /// + public IDictionary? Telemetry { get; set; } + + /// + /// Redaction state for sensitive result fields + /// + public RedactionMetadata? Redaction { get; set; } + + + + #region Load Methods + + /// + /// Load a ToolExecutionCompletePayload instance from a dictionary. + /// + /// The dictionary containing the data. + /// Optional context with pre/post processing callbacks. + /// The loaded ToolExecutionCompletePayload instance. + public static ToolExecutionCompletePayload Load(Dictionary data, LoadContext? context = null) + { + if (context is not null) + { + data = context.ProcessInput(data); + } + + + // Create new instance + var instance = new ToolExecutionCompletePayload(); + + + if (data.TryGetValue("requestId", out var requestIdValue) && requestIdValue is not null) + { + instance.RequestId = requestIdValue?.ToString()!; + } + + if (data.TryGetValue("toolCallId", out var toolCallIdValue) && toolCallIdValue is not null) + { + instance.ToolCallId = toolCallIdValue?.ToString()!; + } + + if (data.TryGetValue("toolName", out var toolNameValue) && toolNameValue is not null) + { + instance.ToolName = toolNameValue?.ToString()!; + } + + if (data.TryGetValue("success", out var successValue) && successValue is not null) + { + instance.Success = Convert.ToBoolean(successValue); + } + + if (data.TryGetValue("result", out var resultValue) && resultValue is not null) + { + instance.Result = resultValue; + } + + if (data.TryGetValue("exitCode", out var exitCodeValue) && exitCodeValue is not null) + { + instance.ExitCode = Convert.ToInt32(exitCodeValue); + } + + if (data.TryGetValue("durationMs", out var durationMsValue) && durationMsValue is not null) + { + instance.DurationMs = Convert.ToDouble(durationMsValue); + } + + if (data.TryGetValue("errorKind", out var errorKindValue) && errorKindValue is not null) + { + instance.ErrorKind = errorKindValue?.ToString()!; + } + + if (data.TryGetValue("telemetry", out var telemetryValue) && telemetryValue is not null) + { + instance.Telemetry = telemetryValue.GetDictionary()!; + } + + if (data.TryGetValue("redaction", out var redactionValue) && redactionValue is not null) + { + instance.Redaction = RedactionMetadata.Load(redactionValue.GetDictionary(RedactionMetadata.ShorthandProperty), context); + } + + if (context is not null) + { + instance = context.ProcessOutput(instance); + } + return instance; + } + + + #endregion + + #region Save Methods + + /// + /// Save the ToolExecutionCompletePayload instance to a dictionary. + /// + /// Optional context with pre/post processing callbacks. + /// The dictionary representation of this instance. + public Dictionary Save(SaveContext? context = null) + { + var obj = this; + if (context is not null) + { + obj = context.ProcessObject(obj); + } + + + var result = new Dictionary(); + + + if (obj.RequestId is not null) + { + result["requestId"] = obj.RequestId; + } + + + if (obj.ToolCallId is not null) + { + result["toolCallId"] = obj.ToolCallId; + } + + + result["toolName"] = obj.ToolName; + + + result["success"] = obj.Success; + + + if (obj.Result is not null) + { + result["result"] = obj.Result; + } + + + if (obj.ExitCode is not null) + { + result["exitCode"] = obj.ExitCode; + } + + + if (obj.DurationMs is not null) + { + result["durationMs"] = obj.DurationMs; + } + + + if (obj.ErrorKind is not null) + { + result["errorKind"] = obj.ErrorKind; + } + + + if (obj.Telemetry is not null) + { + result["telemetry"] = obj.Telemetry; + } + + + if (obj.Redaction is not null) + { + result["redaction"] = obj.Redaction?.Save(context); + } + + + if (context is not null) + { + result = context.ProcessDict(result); + } + + return result; + } + + + /// + /// Convert the ToolExecutionCompletePayload instance to a YAML string. + /// + /// Optional context with pre/post processing callbacks. + /// The YAML string representation of this instance. + public string ToYaml(SaveContext? context = null) + { + context ??= new SaveContext(); + return context.ToYaml(Save(context)); + } + + /// + /// Convert the ToolExecutionCompletePayload instance to a JSON string. + /// + /// Optional context with pre/post processing callbacks. + /// Whether to indent the output. Defaults to true. + /// The JSON string representation of this instance. + public string ToJson(SaveContext? context = null, bool indent = true) + { + context ??= new SaveContext(); + return context.ToJson(Save(context), indent); + } + + /// + /// Load a ToolExecutionCompletePayload instance from a JSON string. + /// + /// The JSON string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded ToolExecutionCompletePayload instance. + public static ToolExecutionCompletePayload FromJson(string json, LoadContext? context = null) + { + using var doc = JsonDocument.Parse(json); + Dictionary dict; + dict = JsonSerializer.Deserialize>(json, JsonUtils.Options) + ?? throw new ArgumentException("Failed to parse JSON as dictionary"); + + return Load(dict, context); + } + + /// + /// Load a ToolExecutionCompletePayload instance from a YAML string. + /// + /// The YAML string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded ToolExecutionCompletePayload instance. + public static ToolExecutionCompletePayload FromYaml(string yaml, LoadContext? context = null) + { + var dict = YamlUtils.Deserializer.Deserialize>(yaml) + ?? throw new ArgumentException("Failed to parse YAML as dictionary"); + + return Load(dict, context); + } + + #endregion +} diff --git a/runtime/csharp/Prompty.Core/Model/events/ToolExecutionStartPayload.cs b/runtime/csharp/Prompty.Core/Model/events/ToolExecutionStartPayload.cs new file mode 100644 index 00000000..c9c8c66f --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/ToolExecutionStartPayload.cs @@ -0,0 +1,239 @@ +// Copyright (c) Microsoft. All rights reserved. +using System.Text.Json; +using YamlDotNet.Serialization; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + +/// +/// Payload for "tool_execution_start" events — the host is about to execute a concrete tool request. +/// +/// This is distinct from "tool_call_start", which records the model requesting a tool. +/// +/// Tool execution events capture the harness-side action after policy and permission checks. +/// +public partial class ToolExecutionStartPayload +{ + /// + /// The shorthand property name for this type, if any. + /// + public static string? ShorthandProperty => null; + + /// + /// Initializes a new instance of . + /// +#pragma warning disable CS8618 + public ToolExecutionStartPayload() + { + } +#pragma warning restore CS8618 + + /// + /// Stable host execution request identifier + /// + public string? RequestId { get; set; } + + /// + /// Associated model tool call identifier, when available + /// + public string? ToolCallId { get; set; } + + /// + /// Name of the host tool being executed + /// + public string ToolName { get; set; } = string.Empty; + + /// + /// Tool arguments after host-side sanitization + /// + public IDictionary? Arguments { get; set; } + + /// + /// Working directory or execution scope for the tool + /// + public string? WorkingDirectory { get; set; } + + /// + /// Redaction state for sensitive argument fields + /// + public RedactionMetadata? Redaction { get; set; } + + + + #region Load Methods + + /// + /// Load a ToolExecutionStartPayload instance from a dictionary. + /// + /// The dictionary containing the data. + /// Optional context with pre/post processing callbacks. + /// The loaded ToolExecutionStartPayload instance. + public static ToolExecutionStartPayload Load(Dictionary data, LoadContext? context = null) + { + if (context is not null) + { + data = context.ProcessInput(data); + } + + + // Create new instance + var instance = new ToolExecutionStartPayload(); + + + if (data.TryGetValue("requestId", out var requestIdValue) && requestIdValue is not null) + { + instance.RequestId = requestIdValue?.ToString()!; + } + + if (data.TryGetValue("toolCallId", out var toolCallIdValue) && toolCallIdValue is not null) + { + instance.ToolCallId = toolCallIdValue?.ToString()!; + } + + if (data.TryGetValue("toolName", out var toolNameValue) && toolNameValue is not null) + { + instance.ToolName = toolNameValue?.ToString()!; + } + + if (data.TryGetValue("arguments", out var argumentsValue) && argumentsValue is not null) + { + instance.Arguments = argumentsValue.GetDictionary()!; + } + + if (data.TryGetValue("workingDirectory", out var workingDirectoryValue) && workingDirectoryValue is not null) + { + instance.WorkingDirectory = workingDirectoryValue?.ToString()!; + } + + if (data.TryGetValue("redaction", out var redactionValue) && redactionValue is not null) + { + instance.Redaction = RedactionMetadata.Load(redactionValue.GetDictionary(RedactionMetadata.ShorthandProperty), context); + } + + if (context is not null) + { + instance = context.ProcessOutput(instance); + } + return instance; + } + + + #endregion + + #region Save Methods + + /// + /// Save the ToolExecutionStartPayload instance to a dictionary. + /// + /// Optional context with pre/post processing callbacks. + /// The dictionary representation of this instance. + public Dictionary Save(SaveContext? context = null) + { + var obj = this; + if (context is not null) + { + obj = context.ProcessObject(obj); + } + + + var result = new Dictionary(); + + + if (obj.RequestId is not null) + { + result["requestId"] = obj.RequestId; + } + + + if (obj.ToolCallId is not null) + { + result["toolCallId"] = obj.ToolCallId; + } + + + result["toolName"] = obj.ToolName; + + + if (obj.Arguments is not null) + { + result["arguments"] = obj.Arguments; + } + + + if (obj.WorkingDirectory is not null) + { + result["workingDirectory"] = obj.WorkingDirectory; + } + + + if (obj.Redaction is not null) + { + result["redaction"] = obj.Redaction?.Save(context); + } + + + if (context is not null) + { + result = context.ProcessDict(result); + } + + return result; + } + + + /// + /// Convert the ToolExecutionStartPayload instance to a YAML string. + /// + /// Optional context with pre/post processing callbacks. + /// The YAML string representation of this instance. + public string ToYaml(SaveContext? context = null) + { + context ??= new SaveContext(); + return context.ToYaml(Save(context)); + } + + /// + /// Convert the ToolExecutionStartPayload instance to a JSON string. + /// + /// Optional context with pre/post processing callbacks. + /// Whether to indent the output. Defaults to true. + /// The JSON string representation of this instance. + public string ToJson(SaveContext? context = null, bool indent = true) + { + context ??= new SaveContext(); + return context.ToJson(Save(context), indent); + } + + /// + /// Load a ToolExecutionStartPayload instance from a JSON string. + /// + /// The JSON string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded ToolExecutionStartPayload instance. + public static ToolExecutionStartPayload FromJson(string json, LoadContext? context = null) + { + using var doc = JsonDocument.Parse(json); + Dictionary dict; + dict = JsonSerializer.Deserialize>(json, JsonUtils.Options) + ?? throw new ArgumentException("Failed to parse JSON as dictionary"); + + return Load(dict, context); + } + + /// + /// Load a ToolExecutionStartPayload instance from a YAML string. + /// + /// The YAML string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded ToolExecutionStartPayload instance. + public static ToolExecutionStartPayload FromYaml(string yaml, LoadContext? context = null) + { + var dict = YamlUtils.Deserializer.Deserialize>(yaml) + ?? throw new ArgumentException("Failed to parse YAML as dictionary"); + + return Load(dict, context); + } + + #endregion +} diff --git a/runtime/csharp/Prompty.Core/Model/events/TrajectoryEvent.cs b/runtime/csharp/Prompty.Core/Model/events/TrajectoryEvent.cs new file mode 100644 index 00000000..9f8f106c --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/TrajectoryEvent.cs @@ -0,0 +1,283 @@ +// Copyright (c) Microsoft. All rights reserved. +using System.Text.Json; +using YamlDotNet.Serialization; + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + +/// +/// A compact, replay-oriented record of one harness-side action or observation. +/// +public partial class TrajectoryEvent +{ + /// + /// The shorthand property name for this type, if any. + /// + public static string? ShorthandProperty => null; + + /// + /// Initializes a new instance of . + /// +#pragma warning disable CS8618 + public TrajectoryEvent() + { + } +#pragma warning restore CS8618 + + /// + /// Stable trajectory event identifier + /// + public string? Id { get; set; } + + /// + /// Stable session identifier + /// + public string? SessionId { get; set; } + + /// + /// Associated turn identifier, when available + /// + public string? TurnId { get; set; } + + /// + /// Associated tool call identifier, when available + /// + public string? ToolCallId { get; set; } + + /// + /// Zero-based turn index in the session + /// + public int? TurnIndex { get; set; } + + /// + /// Host-defined trajectory event category + /// + public string EventType { get; set; } = string.Empty; + + /// + /// Sanitized event data + /// + public IDictionary? Data { get; set; } + + /// + /// ISO 8601 UTC timestamp when the trajectory event was recorded + /// + public string? CreatedAt { get; set; } + + /// + /// Redaction state for sensitive trajectory fields + /// + public RedactionMetadata? Redaction { get; set; } + + + + #region Load Methods + + /// + /// Load a TrajectoryEvent instance from a dictionary. + /// + /// The dictionary containing the data. + /// Optional context with pre/post processing callbacks. + /// The loaded TrajectoryEvent instance. + public static TrajectoryEvent Load(Dictionary data, LoadContext? context = null) + { + if (context is not null) + { + data = context.ProcessInput(data); + } + + + // Create new instance + var instance = new TrajectoryEvent(); + + + if (data.TryGetValue("id", out var idValue) && idValue is not null) + { + instance.Id = idValue?.ToString()!; + } + + if (data.TryGetValue("sessionId", out var sessionIdValue) && sessionIdValue is not null) + { + instance.SessionId = sessionIdValue?.ToString()!; + } + + if (data.TryGetValue("turnId", out var turnIdValue) && turnIdValue is not null) + { + instance.TurnId = turnIdValue?.ToString()!; + } + + if (data.TryGetValue("toolCallId", out var toolCallIdValue) && toolCallIdValue is not null) + { + instance.ToolCallId = toolCallIdValue?.ToString()!; + } + + if (data.TryGetValue("turnIndex", out var turnIndexValue) && turnIndexValue is not null) + { + instance.TurnIndex = Convert.ToInt32(turnIndexValue); + } + + if (data.TryGetValue("eventType", out var eventTypeValue) && eventTypeValue is not null) + { + instance.EventType = eventTypeValue?.ToString()!; + } + + if (data.TryGetValue("data", out var dataValue) && dataValue is not null) + { + instance.Data = dataValue.GetDictionary()!; + } + + if (data.TryGetValue("createdAt", out var createdAtValue) && createdAtValue is not null) + { + instance.CreatedAt = createdAtValue?.ToString()!; + } + + if (data.TryGetValue("redaction", out var redactionValue) && redactionValue is not null) + { + instance.Redaction = RedactionMetadata.Load(redactionValue.GetDictionary(RedactionMetadata.ShorthandProperty), context); + } + + if (context is not null) + { + instance = context.ProcessOutput(instance); + } + return instance; + } + + + #endregion + + #region Save Methods + + /// + /// Save the TrajectoryEvent instance to a dictionary. + /// + /// Optional context with pre/post processing callbacks. + /// The dictionary representation of this instance. + public Dictionary Save(SaveContext? context = null) + { + var obj = this; + if (context is not null) + { + obj = context.ProcessObject(obj); + } + + + var result = new Dictionary(); + + + if (obj.Id is not null) + { + result["id"] = obj.Id; + } + + + if (obj.SessionId is not null) + { + result["sessionId"] = obj.SessionId; + } + + + if (obj.TurnId is not null) + { + result["turnId"] = obj.TurnId; + } + + + if (obj.ToolCallId is not null) + { + result["toolCallId"] = obj.ToolCallId; + } + + + if (obj.TurnIndex is not null) + { + result["turnIndex"] = obj.TurnIndex; + } + + + result["eventType"] = obj.EventType; + + + if (obj.Data is not null) + { + result["data"] = obj.Data; + } + + + if (obj.CreatedAt is not null) + { + result["createdAt"] = obj.CreatedAt; + } + + + if (obj.Redaction is not null) + { + result["redaction"] = obj.Redaction?.Save(context); + } + + + if (context is not null) + { + result = context.ProcessDict(result); + } + + return result; + } + + + /// + /// Convert the TrajectoryEvent instance to a YAML string. + /// + /// Optional context with pre/post processing callbacks. + /// The YAML string representation of this instance. + public string ToYaml(SaveContext? context = null) + { + context ??= new SaveContext(); + return context.ToYaml(Save(context)); + } + + /// + /// Convert the TrajectoryEvent instance to a JSON string. + /// + /// Optional context with pre/post processing callbacks. + /// Whether to indent the output. Defaults to true. + /// The JSON string representation of this instance. + public string ToJson(SaveContext? context = null, bool indent = true) + { + context ??= new SaveContext(); + return context.ToJson(Save(context), indent); + } + + /// + /// Load a TrajectoryEvent instance from a JSON string. + /// + /// The JSON string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded TrajectoryEvent instance. + public static TrajectoryEvent FromJson(string json, LoadContext? context = null) + { + using var doc = JsonDocument.Parse(json); + Dictionary dict; + dict = JsonSerializer.Deserialize>(json, JsonUtils.Options) + ?? throw new ArgumentException("Failed to parse JSON as dictionary"); + + return Load(dict, context); + } + + /// + /// Load a TrajectoryEvent instance from a YAML string. + /// + /// The YAML string to parse. + /// Optional context with pre/post processing callbacks. + /// The loaded TrajectoryEvent instance. + public static TrajectoryEvent FromYaml(string yaml, LoadContext? context = null) + { + var dict = YamlUtils.Deserializer.Deserialize>(yaml) + ?? throw new ArgumentException("Failed to parse YAML as dictionary"); + + return Load(dict, context); + } + + #endregion +} diff --git a/runtime/csharp/Prompty.Core/Model/events/TurnEventType.cs b/runtime/csharp/Prompty.Core/Model/events/TurnEventType.cs index 99bccc9f..21121af7 100644 --- a/runtime/csharp/Prompty.Core/Model/events/TurnEventType.cs +++ b/runtime/csharp/Prompty.Core/Model/events/TurnEventType.cs @@ -41,9 +41,21 @@ public enum TurnEventType [JsonPropertyName("tool_call_complete")] ToolCallComplete, + [JsonPropertyName("tool_execution_start")] + ToolExecutionStart, + + [JsonPropertyName("tool_execution_complete")] + ToolExecutionComplete, + [JsonPropertyName("tool_result")] ToolResult, + [JsonPropertyName("hook_start")] + HookStart, + + [JsonPropertyName("hook_end")] + HookEnd, + [JsonPropertyName("status")] Status, diff --git a/runtime/csharp/Prompty.Core/Model/pipeline/CheckpointStore.cs b/runtime/csharp/Prompty.Core/Model/pipeline/CheckpointStore.cs new file mode 100644 index 00000000..6c787c4d --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/pipeline/CheckpointStore.cs @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft. All rights reserved. + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + +/// +/// Stores and retrieves resumable session checkpoints. +/// +public interface ICheckpointStore +{ + /// + /// Persist a session checkpoint and return the stored checkpoint + /// + Task SaveAsync(Checkpoint checkpoint); + /// + /// Load a checkpoint by session and checkpoint identifier + /// + Task LoadAsync(string sessionId, string checkpointId); + /// + /// List checkpoints for a session + /// + Task> ListCheckpointsAsync(string sessionId); +} diff --git a/runtime/csharp/Prompty.Core/Model/pipeline/EventSink.cs b/runtime/csharp/Prompty.Core/Model/pipeline/EventSink.cs new file mode 100644 index 00000000..8e3f9187 --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/pipeline/EventSink.cs @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft. All rights reserved. + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + +/// +/// Receives typed turn and session events from a harness. +/// +public interface IEventSink +{ + /// + /// Emit a typed turn event to a host sink + /// + bool EmitTurn(TurnEvent turnEvent); + /// + /// Emit a typed session event to a host sink + /// + bool EmitSession(SessionEvent sessionEvent); +} diff --git a/runtime/csharp/Prompty.Core/Model/pipeline/HostToolExecutor.cs b/runtime/csharp/Prompty.Core/Model/pipeline/HostToolExecutor.cs new file mode 100644 index 00000000..d82751e9 --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/pipeline/HostToolExecutor.cs @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft. All rights reserved. + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + +/// +/// Executes host tools after policy and permission checks. +/// +public interface IHostToolExecutor +{ + /// + /// Execute a concrete host tool request and return its completion payload + /// + Task ExecuteAsync(HostToolRequest request); +} diff --git a/runtime/csharp/Prompty.Core/Model/pipeline/PermissionResolver.cs b/runtime/csharp/Prompty.Core/Model/pipeline/PermissionResolver.cs new file mode 100644 index 00000000..13e8d026 --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/pipeline/PermissionResolver.cs @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft. All rights reserved. + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + +/// +/// Resolves host permission requests for potentially sensitive actions. +/// +public interface IPermissionResolver +{ + /// + /// Resolve a host permission request + /// + Task RequestAsync(PermissionRequest request); +} diff --git a/runtime/csharp/Prompty.Core/Model/pipeline/TraceWriter.cs b/runtime/csharp/Prompty.Core/Model/pipeline/TraceWriter.cs new file mode 100644 index 00000000..bc4530ae --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/pipeline/TraceWriter.cs @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft. All rights reserved. + +#pragma warning disable IDE0130 +namespace Prompty.Core; +#pragma warning restore IDE0130 + +/// +/// Persists typed events to a replayable trace. +/// +public interface ITraceWriter +{ + /// + /// Append a turn event to a replayable trace + /// + bool AppendTurn(TurnEvent turnEvent); + /// + /// Append a session event to a replayable trace + /// + bool AppendSession(SessionEvent sessionEvent); + /// + /// Finalize the trace with an optional session summary + /// + bool Close(SessionSummary? summary); +} diff --git a/runtime/go/prompty/model/checkpoint.go b/runtime/go/prompty/model/checkpoint.go new file mode 100644 index 00000000..5e9b22d6 --- /dev/null +++ b/runtime/go/prompty/model/checkpoint.go @@ -0,0 +1,174 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: events + +package prompty + +import ( + "encoding/json" + + "gopkg.in/yaml.v3" +) + +// Checkpoint represents A persisted handoff point for a harness session. + +type Checkpoint struct { + Id *string `json:"id,omitempty" yaml:"id,omitempty"` + SessionId *string `json:"sessionId,omitempty" yaml:"sessionId,omitempty"` + TurnId *string `json:"turnId,omitempty" yaml:"turnId,omitempty"` + CheckpointNumber *int32 `json:"checkpointNumber,omitempty" yaml:"checkpointNumber,omitempty"` + Title string `json:"title" yaml:"title"` + Overview *string `json:"overview,omitempty" yaml:"overview,omitempty"` + State map[string]interface{} `json:"state,omitempty" yaml:"state,omitempty"` + Summary *string `json:"summary,omitempty" yaml:"summary,omitempty"` + Metadata map[string]interface{} `json:"metadata,omitempty" yaml:"metadata,omitempty"` + CreatedAt *string `json:"createdAt,omitempty" yaml:"createdAt,omitempty"` + Redaction *RedactionMetadata `json:"redaction,omitempty" yaml:"redaction,omitempty"` +} + +// LoadCheckpoint creates a Checkpoint from a map[string]interface{} +func LoadCheckpoint(data interface{}, ctx *LoadContext) (Checkpoint, error) { + result := Checkpoint{} + + // Load from map + if m, ok := data.(map[string]interface{}); ok { + if val, ok := m["id"]; ok && val != nil { + v := string(val.(string)) + result.Id = &v + } + if val, ok := m["sessionId"]; ok && val != nil { + v := string(val.(string)) + result.SessionId = &v + } + if val, ok := m["turnId"]; ok && val != nil { + v := string(val.(string)) + result.TurnId = &v + } + if val, ok := m["checkpointNumber"]; ok && val != nil { // Handle various numeric types from JSON/YAML/roundtrip + var v int32 + switch n := val.(type) { + case int: + v = int32(n) + case int32: + v = int32(n) + case int64: + v = int32(n) + case float64: + v = int32(n) + } + result.CheckpointNumber = &v + } + if val, ok := m["title"]; ok && val != nil { + result.Title = string(val.(string)) + } + if val, ok := m["overview"]; ok && val != nil { + v := string(val.(string)) + result.Overview = &v + } + if val, ok := m["state"]; ok && val != nil { + if m, ok := val.(map[string]interface{}); ok { + result.State = m + } + } + if val, ok := m["summary"]; ok && val != nil { + v := string(val.(string)) + result.Summary = &v + } + if val, ok := m["metadata"]; ok && val != nil { + if m, ok := val.(map[string]interface{}); ok { + result.Metadata = m + } + } + if val, ok := m["createdAt"]; ok && val != nil { + v := string(val.(string)) + result.CreatedAt = &v + } + if val, ok := m["redaction"]; ok && val != nil { + if m, ok := val.(map[string]interface{}); ok { + loaded, _ := LoadRedactionMetadata(m, ctx) + result.Redaction = &loaded + } + } + } + + return result, nil +} + +// Save serializes Checkpoint to map[string]interface{} +func (obj *Checkpoint) Save(ctx *SaveContext) map[string]interface{} { + result := make(map[string]interface{}) + if obj.Id != nil { + result["id"] = *obj.Id + } + if obj.SessionId != nil { + result["sessionId"] = *obj.SessionId + } + if obj.TurnId != nil { + result["turnId"] = *obj.TurnId + } + if obj.CheckpointNumber != nil { + result["checkpointNumber"] = *obj.CheckpointNumber + } + result["title"] = obj.Title + if obj.Overview != nil { + result["overview"] = *obj.Overview + } + if obj.State != nil { + result["state"] = obj.State + } + if obj.Summary != nil { + result["summary"] = *obj.Summary + } + if obj.Metadata != nil { + result["metadata"] = obj.Metadata + } + if obj.CreatedAt != nil { + result["createdAt"] = *obj.CreatedAt + } + if obj.Redaction != nil { + result["redaction"] = obj.Redaction.Save(ctx) + } + + return result +} + +// ToJSON serializes Checkpoint to JSON string +func (obj *Checkpoint) ToJSON() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := json.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// ToYAML serializes Checkpoint to YAML string +func (obj *Checkpoint) ToYAML() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := yaml.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// FromJSON creates Checkpoint from JSON string +func CheckpointFromJSON(jsonStr string) (Checkpoint, error) { + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { + return Checkpoint{}, err + } + ctx := NewLoadContext() + return LoadCheckpoint(data, ctx) +} + +// FromYAML creates Checkpoint from YAML string +func CheckpointFromYAML(yamlStr string) (Checkpoint, error) { + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlStr), &data); err != nil { + return Checkpoint{}, err + } + ctx := NewLoadContext() + return LoadCheckpoint(data, ctx) +} diff --git a/runtime/go/prompty/model/checkpoint_store.go b/runtime/go/prompty/model/checkpoint_store.go new file mode 100644 index 00000000..fad18bd8 --- /dev/null +++ b/runtime/go/prompty/model/checkpoint_store.go @@ -0,0 +1,15 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: pipeline + +package prompty + +// CheckpointStore represents Stores and retrieves resumable session checkpoints. + +type CheckpointStore interface { + // Save — Persist a session checkpoint and return the stored checkpoint + Save(checkpoint Checkpoint) (Checkpoint, error) + // Load — Load a checkpoint by session and checkpoint identifier + Load(sessionId string, checkpointId string) (*Checkpoint, error) + // ListCheckpoints — List checkpoints for a session + ListCheckpoints(sessionId string) ([]Checkpoint, error) +} diff --git a/runtime/go/prompty/model/checkpoint_test.go b/runtime/go/prompty/model/checkpoint_test.go new file mode 100644 index 00000000..efb4db95 --- /dev/null +++ b/runtime/go/prompty/model/checkpoint_test.go @@ -0,0 +1,210 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +package prompty_test + +import ( + "encoding/json" + "testing" + + "gopkg.in/yaml.v3" + + "prompty/model" +) + +// TestCheckpointLoadJSON tests loading Checkpoint from JSON +func TestCheckpointLoadJSON(t *testing.T) { + jsonData := ` +{ + "id": "chk_abc123", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "checkpointNumber": 3, + "title": "Added harness contracts", + "createdAt": "2026-06-09T20:00:00Z" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadCheckpoint(data, ctx) + if err != nil { + t.Fatalf("Failed to load Checkpoint: %v", err) + } + if instance.Id == nil || *instance.Id != "chk_abc123" { + t.Errorf(`Expected Id to be "chk_abc123", got %v`, instance.Id) + } + if instance.SessionId == nil || *instance.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, instance.SessionId) + } + if instance.TurnId == nil || *instance.TurnId != "turn_001" { + t.Errorf(`Expected TurnId to be "turn_001", got %v`, instance.TurnId) + } + if instance.CheckpointNumber == nil || *instance.CheckpointNumber != 3 { + t.Errorf(`Expected CheckpointNumber to be 3, got %v`, instance.CheckpointNumber) + } + if instance.Title != "Added harness contracts" { + t.Errorf(`Expected Title to be "Added harness contracts", got %v`, instance.Title) + } + if instance.CreatedAt == nil || *instance.CreatedAt != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected CreatedAt to be "2026-06-09T20:00:00Z", got %v`, instance.CreatedAt) + } +} + +// TestCheckpointLoadYAML tests loading Checkpoint from YAML +func TestCheckpointLoadYAML(t *testing.T) { + yamlData := ` +id: chk_abc123 +sessionId: sess_abc123 +turnId: turn_001 +checkpointNumber: 3 +title: Added harness contracts +createdAt: "2026-06-09T20:00:00Z" + +` + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlData), &data); err != nil { + t.Fatalf("Failed to parse YAML: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadCheckpoint(data, ctx) + if err != nil { + t.Fatalf("Failed to load Checkpoint: %v", err) + } + if instance.Id == nil || *instance.Id != "chk_abc123" { + t.Errorf(`Expected Id to be "chk_abc123", got %v`, instance.Id) + } + if instance.SessionId == nil || *instance.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, instance.SessionId) + } + if instance.TurnId == nil || *instance.TurnId != "turn_001" { + t.Errorf(`Expected TurnId to be "turn_001", got %v`, instance.TurnId) + } + if instance.CheckpointNumber == nil || *instance.CheckpointNumber != 3 { + t.Errorf(`Expected CheckpointNumber to be 3, got %v`, instance.CheckpointNumber) + } + if instance.Title != "Added harness contracts" { + t.Errorf(`Expected Title to be "Added harness contracts", got %v`, instance.Title) + } + if instance.CreatedAt == nil || *instance.CreatedAt != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected CreatedAt to be "2026-06-09T20:00:00Z", got %v`, instance.CreatedAt) + } +} + +// TestCheckpointRoundtrip tests load -> save -> load produces equivalent data +func TestCheckpointRoundtrip(t *testing.T) { + jsonData := ` +{ + "id": "chk_abc123", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "checkpointNumber": 3, + "title": "Added harness contracts", + "createdAt": "2026-06-09T20:00:00Z" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + loadCtx := prompty.NewLoadContext() + instance, err := prompty.LoadCheckpoint(data, loadCtx) + if err != nil { + t.Fatalf("Failed to load Checkpoint: %v", err) + } + saveCtx := prompty.NewSaveContext() + savedData := instance.Save(saveCtx) + + reloaded, err := prompty.LoadCheckpoint(savedData, loadCtx) + if err != nil { + t.Fatalf("Failed to reload Checkpoint: %v", err) + } + if reloaded.Id == nil || *reloaded.Id != "chk_abc123" { + t.Errorf(`Expected Id to be "chk_abc123", got %v`, reloaded.Id) + } + if reloaded.SessionId == nil || *reloaded.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, reloaded.SessionId) + } + if reloaded.TurnId == nil || *reloaded.TurnId != "turn_001" { + t.Errorf(`Expected TurnId to be "turn_001", got %v`, reloaded.TurnId) + } + if reloaded.CheckpointNumber == nil || *reloaded.CheckpointNumber != 3 { + t.Errorf(`Expected CheckpointNumber to be 3, got %v`, reloaded.CheckpointNumber) + } + if reloaded.Title != "Added harness contracts" { + t.Errorf(`Expected Title to be "Added harness contracts", got %v`, reloaded.Title) + } + if reloaded.CreatedAt == nil || *reloaded.CreatedAt != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected CreatedAt to be "2026-06-09T20:00:00Z", got %v`, reloaded.CreatedAt) + } +} + +// TestCheckpointToJSON tests that ToJSON produces valid JSON +func TestCheckpointToJSON(t *testing.T) { + jsonData := ` +{ + "id": "chk_abc123", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "checkpointNumber": 3, + "title": "Added harness contracts", + "createdAt": "2026-06-09T20:00:00Z" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadCheckpoint(data, ctx) + if err != nil { + t.Fatalf("Failed to load Checkpoint: %v", err) + } + jsonOutput, err := instance.ToJSON() + if err != nil { + t.Fatalf("Failed to convert to JSON: %v", err) + } + + var parsed map[string]interface{} + if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated JSON: %v", err) + } +} + +// TestCheckpointToYAML tests that ToYAML produces valid YAML +func TestCheckpointToYAML(t *testing.T) { + jsonData := ` +{ + "id": "chk_abc123", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "checkpointNumber": 3, + "title": "Added harness contracts", + "createdAt": "2026-06-09T20:00:00Z" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadCheckpoint(data, ctx) + if err != nil { + t.Fatalf("Failed to load Checkpoint: %v", err) + } + yamlOutput, err := instance.ToYAML() + if err != nil { + t.Fatalf("Failed to convert to YAML: %v", err) + } + + var parsed map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated YAML: %v", err) + } +} diff --git a/runtime/go/prompty/model/event_sink.go b/runtime/go/prompty/model/event_sink.go new file mode 100644 index 00000000..e38e8260 --- /dev/null +++ b/runtime/go/prompty/model/event_sink.go @@ -0,0 +1,13 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: pipeline + +package prompty + +// EventSink represents Receives typed turn and session events from a harness. + +type EventSink interface { + // EmitTurn — Emit a typed turn event to a host sink + EmitTurn(turnEvent TurnEvent) (bool, error) + // EmitSession — Emit a typed session event to a host sink + EmitSession(sessionEvent SessionEvent) (bool, error) +} diff --git a/runtime/go/prompty/model/harness_context.go b/runtime/go/prompty/model/harness_context.go new file mode 100644 index 00000000..d9e3e484 --- /dev/null +++ b/runtime/go/prompty/model/harness_context.go @@ -0,0 +1,102 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: events + +package prompty + +import ( + "encoding/json" + + "gopkg.in/yaml.v3" +) + +// HarnessContext represents Execution context associated with a harness session. Host-specific +// environments can store detailed profiles in metadata without making the core +// contract depend on one source-control provider or workspace shape. + +type HarnessContext struct { + Cwd *string `json:"cwd,omitempty" yaml:"cwd,omitempty"` + GitRoot *string `json:"gitRoot,omitempty" yaml:"gitRoot,omitempty"` + Metadata map[string]interface{} `json:"metadata,omitempty" yaml:"metadata,omitempty"` +} + +// LoadHarnessContext creates a HarnessContext from a map[string]interface{} +func LoadHarnessContext(data interface{}, ctx *LoadContext) (HarnessContext, error) { + result := HarnessContext{} + + // Load from map + if m, ok := data.(map[string]interface{}); ok { + if val, ok := m["cwd"]; ok && val != nil { + v := string(val.(string)) + result.Cwd = &v + } + if val, ok := m["gitRoot"]; ok && val != nil { + v := string(val.(string)) + result.GitRoot = &v + } + if val, ok := m["metadata"]; ok && val != nil { + if m, ok := val.(map[string]interface{}); ok { + result.Metadata = m + } + } + } + + return result, nil +} + +// Save serializes HarnessContext to map[string]interface{} +func (obj *HarnessContext) Save(ctx *SaveContext) map[string]interface{} { + result := make(map[string]interface{}) + if obj.Cwd != nil { + result["cwd"] = *obj.Cwd + } + if obj.GitRoot != nil { + result["gitRoot"] = *obj.GitRoot + } + if obj.Metadata != nil { + result["metadata"] = obj.Metadata + } + + return result +} + +// ToJSON serializes HarnessContext to JSON string +func (obj *HarnessContext) ToJSON() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := json.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// ToYAML serializes HarnessContext to YAML string +func (obj *HarnessContext) ToYAML() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := yaml.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// FromJSON creates HarnessContext from JSON string +func HarnessContextFromJSON(jsonStr string) (HarnessContext, error) { + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { + return HarnessContext{}, err + } + ctx := NewLoadContext() + return LoadHarnessContext(data, ctx) +} + +// FromYAML creates HarnessContext from YAML string +func HarnessContextFromYAML(yamlStr string) (HarnessContext, error) { + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlStr), &data); err != nil { + return HarnessContext{}, err + } + ctx := NewLoadContext() + return LoadHarnessContext(data, ctx) +} diff --git a/runtime/go/prompty/model/harness_context_test.go b/runtime/go/prompty/model/harness_context_test.go new file mode 100644 index 00000000..f8c12155 --- /dev/null +++ b/runtime/go/prompty/model/harness_context_test.go @@ -0,0 +1,154 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +package prompty_test + +import ( + "encoding/json" + "testing" + + "gopkg.in/yaml.v3" + + "prompty/model" +) + +// TestHarnessContextLoadJSON tests loading HarnessContext from JSON +func TestHarnessContextLoadJSON(t *testing.T) { + jsonData := ` +{ + "cwd": "/workspace/project", + "gitRoot": "/workspace/project" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadHarnessContext(data, ctx) + if err != nil { + t.Fatalf("Failed to load HarnessContext: %v", err) + } + if instance.Cwd == nil || *instance.Cwd != "/workspace/project" { + t.Errorf(`Expected Cwd to be "/workspace/project", got %v`, instance.Cwd) + } + if instance.GitRoot == nil || *instance.GitRoot != "/workspace/project" { + t.Errorf(`Expected GitRoot to be "/workspace/project", got %v`, instance.GitRoot) + } +} + +// TestHarnessContextLoadYAML tests loading HarnessContext from YAML +func TestHarnessContextLoadYAML(t *testing.T) { + yamlData := ` +cwd: /workspace/project +gitRoot: /workspace/project + +` + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlData), &data); err != nil { + t.Fatalf("Failed to parse YAML: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadHarnessContext(data, ctx) + if err != nil { + t.Fatalf("Failed to load HarnessContext: %v", err) + } + if instance.Cwd == nil || *instance.Cwd != "/workspace/project" { + t.Errorf(`Expected Cwd to be "/workspace/project", got %v`, instance.Cwd) + } + if instance.GitRoot == nil || *instance.GitRoot != "/workspace/project" { + t.Errorf(`Expected GitRoot to be "/workspace/project", got %v`, instance.GitRoot) + } +} + +// TestHarnessContextRoundtrip tests load -> save -> load produces equivalent data +func TestHarnessContextRoundtrip(t *testing.T) { + jsonData := ` +{ + "cwd": "/workspace/project", + "gitRoot": "/workspace/project" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + loadCtx := prompty.NewLoadContext() + instance, err := prompty.LoadHarnessContext(data, loadCtx) + if err != nil { + t.Fatalf("Failed to load HarnessContext: %v", err) + } + saveCtx := prompty.NewSaveContext() + savedData := instance.Save(saveCtx) + + reloaded, err := prompty.LoadHarnessContext(savedData, loadCtx) + if err != nil { + t.Fatalf("Failed to reload HarnessContext: %v", err) + } + if reloaded.Cwd == nil || *reloaded.Cwd != "/workspace/project" { + t.Errorf(`Expected Cwd to be "/workspace/project", got %v`, reloaded.Cwd) + } + if reloaded.GitRoot == nil || *reloaded.GitRoot != "/workspace/project" { + t.Errorf(`Expected GitRoot to be "/workspace/project", got %v`, reloaded.GitRoot) + } +} + +// TestHarnessContextToJSON tests that ToJSON produces valid JSON +func TestHarnessContextToJSON(t *testing.T) { + jsonData := ` +{ + "cwd": "/workspace/project", + "gitRoot": "/workspace/project" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadHarnessContext(data, ctx) + if err != nil { + t.Fatalf("Failed to load HarnessContext: %v", err) + } + jsonOutput, err := instance.ToJSON() + if err != nil { + t.Fatalf("Failed to convert to JSON: %v", err) + } + + var parsed map[string]interface{} + if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated JSON: %v", err) + } +} + +// TestHarnessContextToYAML tests that ToYAML produces valid YAML +func TestHarnessContextToYAML(t *testing.T) { + jsonData := ` +{ + "cwd": "/workspace/project", + "gitRoot": "/workspace/project" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadHarnessContext(data, ctx) + if err != nil { + t.Fatalf("Failed to load HarnessContext: %v", err) + } + yamlOutput, err := instance.ToYAML() + if err != nil { + t.Fatalf("Failed to convert to YAML: %v", err) + } + + var parsed map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated YAML: %v", err) + } +} diff --git a/runtime/go/prompty/model/hook_end_payload.go b/runtime/go/prompty/model/hook_end_payload.go new file mode 100644 index 00000000..38d5b82f --- /dev/null +++ b/runtime/go/prompty/model/hook_end_payload.go @@ -0,0 +1,137 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: events + +package prompty + +import ( + "encoding/json" + + "gopkg.in/yaml.v3" +) + +// HookEndPayload represents Payload for "hook_end" events — a host lifecycle hook finished. + +type HookEndPayload struct { + HookInvocationId string `json:"hookInvocationId" yaml:"hookInvocationId"` + HookType string `json:"hookType" yaml:"hookType"` + Success bool `json:"success" yaml:"success"` + Output map[string]interface{} `json:"output,omitempty" yaml:"output,omitempty"` + DurationMs *float64 `json:"durationMs,omitempty" yaml:"durationMs,omitempty"` + Error *string `json:"error,omitempty" yaml:"error,omitempty"` + Redaction *RedactionMetadata `json:"redaction,omitempty" yaml:"redaction,omitempty"` +} + +// LoadHookEndPayload creates a HookEndPayload from a map[string]interface{} +func LoadHookEndPayload(data interface{}, ctx *LoadContext) (HookEndPayload, error) { + result := HookEndPayload{} + + // Load from map + if m, ok := data.(map[string]interface{}); ok { + if val, ok := m["hookInvocationId"]; ok && val != nil { + result.HookInvocationId = string(val.(string)) + } + if val, ok := m["hookType"]; ok && val != nil { + result.HookType = string(val.(string)) + } + if val, ok := m["success"]; ok && val != nil { + result.Success = val.(bool) + } + if val, ok := m["output"]; ok && val != nil { + if m, ok := val.(map[string]interface{}); ok { + result.Output = m + } + } + if val, ok := m["durationMs"]; ok && val != nil { // Handle various numeric types from JSON/YAML/roundtrip + var v float64 + switch n := val.(type) { + case int: + v = float64(n) + case int32: + v = float64(n) + case int64: + v = float64(n) + case float32: + v = float64(n) + case float64: + v = n + } + result.DurationMs = &v + } + if val, ok := m["error"]; ok && val != nil { + v := string(val.(string)) + result.Error = &v + } + if val, ok := m["redaction"]; ok && val != nil { + if m, ok := val.(map[string]interface{}); ok { + loaded, _ := LoadRedactionMetadata(m, ctx) + result.Redaction = &loaded + } + } + } + + return result, nil +} + +// Save serializes HookEndPayload to map[string]interface{} +func (obj *HookEndPayload) Save(ctx *SaveContext) map[string]interface{} { + result := make(map[string]interface{}) + result["hookInvocationId"] = obj.HookInvocationId + result["hookType"] = obj.HookType + result["success"] = obj.Success + if obj.Output != nil { + result["output"] = obj.Output + } + if obj.DurationMs != nil { + result["durationMs"] = *obj.DurationMs + } + if obj.Error != nil { + result["error"] = *obj.Error + } + if obj.Redaction != nil { + result["redaction"] = obj.Redaction.Save(ctx) + } + + return result +} + +// ToJSON serializes HookEndPayload to JSON string +func (obj *HookEndPayload) ToJSON() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := json.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// ToYAML serializes HookEndPayload to YAML string +func (obj *HookEndPayload) ToYAML() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := yaml.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// FromJSON creates HookEndPayload from JSON string +func HookEndPayloadFromJSON(jsonStr string) (HookEndPayload, error) { + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { + return HookEndPayload{}, err + } + ctx := NewLoadContext() + return LoadHookEndPayload(data, ctx) +} + +// FromYAML creates HookEndPayload from YAML string +func HookEndPayloadFromYAML(yamlStr string) (HookEndPayload, error) { + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlStr), &data); err != nil { + return HookEndPayload{}, err + } + ctx := NewLoadContext() + return LoadHookEndPayload(data, ctx) +} diff --git a/runtime/go/prompty/model/hook_end_payload_test.go b/runtime/go/prompty/model/hook_end_payload_test.go new file mode 100644 index 00000000..cec7647e --- /dev/null +++ b/runtime/go/prompty/model/hook_end_payload_test.go @@ -0,0 +1,196 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +package prompty_test + +import ( + "encoding/json" + "testing" + + "gopkg.in/yaml.v3" + + "prompty/model" +) + +// TestHookEndPayloadLoadJSON tests loading HookEndPayload from JSON +func TestHookEndPayloadLoadJSON(t *testing.T) { + jsonData := ` +{ + "hookInvocationId": "hook_abc123", + "hookType": "preToolUse", + "success": true, + "durationMs": 12, + "error": "hook failed" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadHookEndPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load HookEndPayload: %v", err) + } + if instance.HookInvocationId != "hook_abc123" { + t.Errorf(`Expected HookInvocationId to be "hook_abc123", got %v`, instance.HookInvocationId) + } + if instance.HookType != "preToolUse" { + t.Errorf(`Expected HookType to be "preToolUse", got %v`, instance.HookType) + } + if instance.Success != true { + t.Errorf(`Expected Success to be true, got %v`, instance.Success) + } + if instance.DurationMs == nil || *instance.DurationMs != 12 { + t.Errorf(`Expected DurationMs to be 12, got %v`, instance.DurationMs) + } + if instance.Error == nil || *instance.Error != "hook failed" { + t.Errorf(`Expected Error to be "hook failed", got %v`, instance.Error) + } +} + +// TestHookEndPayloadLoadYAML tests loading HookEndPayload from YAML +func TestHookEndPayloadLoadYAML(t *testing.T) { + yamlData := ` +hookInvocationId: hook_abc123 +hookType: preToolUse +success: true +durationMs: 12 +error: hook failed + +` + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlData), &data); err != nil { + t.Fatalf("Failed to parse YAML: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadHookEndPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load HookEndPayload: %v", err) + } + if instance.HookInvocationId != "hook_abc123" { + t.Errorf(`Expected HookInvocationId to be "hook_abc123", got %v`, instance.HookInvocationId) + } + if instance.HookType != "preToolUse" { + t.Errorf(`Expected HookType to be "preToolUse", got %v`, instance.HookType) + } + if instance.Success != true { + t.Errorf(`Expected Success to be true, got %v`, instance.Success) + } + if instance.DurationMs == nil || *instance.DurationMs != 12 { + t.Errorf(`Expected DurationMs to be 12, got %v`, instance.DurationMs) + } + if instance.Error == nil || *instance.Error != "hook failed" { + t.Errorf(`Expected Error to be "hook failed", got %v`, instance.Error) + } +} + +// TestHookEndPayloadRoundtrip tests load -> save -> load produces equivalent data +func TestHookEndPayloadRoundtrip(t *testing.T) { + jsonData := ` +{ + "hookInvocationId": "hook_abc123", + "hookType": "preToolUse", + "success": true, + "durationMs": 12, + "error": "hook failed" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + loadCtx := prompty.NewLoadContext() + instance, err := prompty.LoadHookEndPayload(data, loadCtx) + if err != nil { + t.Fatalf("Failed to load HookEndPayload: %v", err) + } + saveCtx := prompty.NewSaveContext() + savedData := instance.Save(saveCtx) + + reloaded, err := prompty.LoadHookEndPayload(savedData, loadCtx) + if err != nil { + t.Fatalf("Failed to reload HookEndPayload: %v", err) + } + if reloaded.HookInvocationId != "hook_abc123" { + t.Errorf(`Expected HookInvocationId to be "hook_abc123", got %v`, reloaded.HookInvocationId) + } + if reloaded.HookType != "preToolUse" { + t.Errorf(`Expected HookType to be "preToolUse", got %v`, reloaded.HookType) + } + if reloaded.Success != true { + t.Errorf(`Expected Success to be true, got %v`, reloaded.Success) + } + if reloaded.DurationMs == nil || *reloaded.DurationMs != 12 { + t.Errorf(`Expected DurationMs to be 12, got %v`, reloaded.DurationMs) + } + if reloaded.Error == nil || *reloaded.Error != "hook failed" { + t.Errorf(`Expected Error to be "hook failed", got %v`, reloaded.Error) + } +} + +// TestHookEndPayloadToJSON tests that ToJSON produces valid JSON +func TestHookEndPayloadToJSON(t *testing.T) { + jsonData := ` +{ + "hookInvocationId": "hook_abc123", + "hookType": "preToolUse", + "success": true, + "durationMs": 12, + "error": "hook failed" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadHookEndPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load HookEndPayload: %v", err) + } + jsonOutput, err := instance.ToJSON() + if err != nil { + t.Fatalf("Failed to convert to JSON: %v", err) + } + + var parsed map[string]interface{} + if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated JSON: %v", err) + } +} + +// TestHookEndPayloadToYAML tests that ToYAML produces valid YAML +func TestHookEndPayloadToYAML(t *testing.T) { + jsonData := ` +{ + "hookInvocationId": "hook_abc123", + "hookType": "preToolUse", + "success": true, + "durationMs": 12, + "error": "hook failed" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadHookEndPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load HookEndPayload: %v", err) + } + yamlOutput, err := instance.ToYAML() + if err != nil { + t.Fatalf("Failed to convert to YAML: %v", err) + } + + var parsed map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated YAML: %v", err) + } +} diff --git a/runtime/go/prompty/model/hook_start_payload.go b/runtime/go/prompty/model/hook_start_payload.go new file mode 100644 index 00000000..7bb8d795 --- /dev/null +++ b/runtime/go/prompty/model/hook_start_payload.go @@ -0,0 +1,104 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: events + +package prompty + +import ( + "encoding/json" + + "gopkg.in/yaml.v3" +) + +// HookStartPayload represents Payload for "hook_start" events — a host lifecycle hook is beginning. + +type HookStartPayload struct { + HookInvocationId string `json:"hookInvocationId" yaml:"hookInvocationId"` + HookType string `json:"hookType" yaml:"hookType"` + Input map[string]interface{} `json:"input,omitempty" yaml:"input,omitempty"` + Redaction *RedactionMetadata `json:"redaction,omitempty" yaml:"redaction,omitempty"` +} + +// LoadHookStartPayload creates a HookStartPayload from a map[string]interface{} +func LoadHookStartPayload(data interface{}, ctx *LoadContext) (HookStartPayload, error) { + result := HookStartPayload{} + + // Load from map + if m, ok := data.(map[string]interface{}); ok { + if val, ok := m["hookInvocationId"]; ok && val != nil { + result.HookInvocationId = string(val.(string)) + } + if val, ok := m["hookType"]; ok && val != nil { + result.HookType = string(val.(string)) + } + if val, ok := m["input"]; ok && val != nil { + if m, ok := val.(map[string]interface{}); ok { + result.Input = m + } + } + if val, ok := m["redaction"]; ok && val != nil { + if m, ok := val.(map[string]interface{}); ok { + loaded, _ := LoadRedactionMetadata(m, ctx) + result.Redaction = &loaded + } + } + } + + return result, nil +} + +// Save serializes HookStartPayload to map[string]interface{} +func (obj *HookStartPayload) Save(ctx *SaveContext) map[string]interface{} { + result := make(map[string]interface{}) + result["hookInvocationId"] = obj.HookInvocationId + result["hookType"] = obj.HookType + if obj.Input != nil { + result["input"] = obj.Input + } + if obj.Redaction != nil { + result["redaction"] = obj.Redaction.Save(ctx) + } + + return result +} + +// ToJSON serializes HookStartPayload to JSON string +func (obj *HookStartPayload) ToJSON() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := json.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// ToYAML serializes HookStartPayload to YAML string +func (obj *HookStartPayload) ToYAML() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := yaml.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// FromJSON creates HookStartPayload from JSON string +func HookStartPayloadFromJSON(jsonStr string) (HookStartPayload, error) { + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { + return HookStartPayload{}, err + } + ctx := NewLoadContext() + return LoadHookStartPayload(data, ctx) +} + +// FromYAML creates HookStartPayload from YAML string +func HookStartPayloadFromYAML(yamlStr string) (HookStartPayload, error) { + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlStr), &data); err != nil { + return HookStartPayload{}, err + } + ctx := NewLoadContext() + return LoadHookStartPayload(data, ctx) +} diff --git a/runtime/go/prompty/model/hook_start_payload_test.go b/runtime/go/prompty/model/hook_start_payload_test.go new file mode 100644 index 00000000..b6d65429 --- /dev/null +++ b/runtime/go/prompty/model/hook_start_payload_test.go @@ -0,0 +1,154 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +package prompty_test + +import ( + "encoding/json" + "testing" + + "gopkg.in/yaml.v3" + + "prompty/model" +) + +// TestHookStartPayloadLoadJSON tests loading HookStartPayload from JSON +func TestHookStartPayloadLoadJSON(t *testing.T) { + jsonData := ` +{ + "hookInvocationId": "hook_abc123", + "hookType": "preToolUse" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadHookStartPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load HookStartPayload: %v", err) + } + if instance.HookInvocationId != "hook_abc123" { + t.Errorf(`Expected HookInvocationId to be "hook_abc123", got %v`, instance.HookInvocationId) + } + if instance.HookType != "preToolUse" { + t.Errorf(`Expected HookType to be "preToolUse", got %v`, instance.HookType) + } +} + +// TestHookStartPayloadLoadYAML tests loading HookStartPayload from YAML +func TestHookStartPayloadLoadYAML(t *testing.T) { + yamlData := ` +hookInvocationId: hook_abc123 +hookType: preToolUse + +` + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlData), &data); err != nil { + t.Fatalf("Failed to parse YAML: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadHookStartPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load HookStartPayload: %v", err) + } + if instance.HookInvocationId != "hook_abc123" { + t.Errorf(`Expected HookInvocationId to be "hook_abc123", got %v`, instance.HookInvocationId) + } + if instance.HookType != "preToolUse" { + t.Errorf(`Expected HookType to be "preToolUse", got %v`, instance.HookType) + } +} + +// TestHookStartPayloadRoundtrip tests load -> save -> load produces equivalent data +func TestHookStartPayloadRoundtrip(t *testing.T) { + jsonData := ` +{ + "hookInvocationId": "hook_abc123", + "hookType": "preToolUse" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + loadCtx := prompty.NewLoadContext() + instance, err := prompty.LoadHookStartPayload(data, loadCtx) + if err != nil { + t.Fatalf("Failed to load HookStartPayload: %v", err) + } + saveCtx := prompty.NewSaveContext() + savedData := instance.Save(saveCtx) + + reloaded, err := prompty.LoadHookStartPayload(savedData, loadCtx) + if err != nil { + t.Fatalf("Failed to reload HookStartPayload: %v", err) + } + if reloaded.HookInvocationId != "hook_abc123" { + t.Errorf(`Expected HookInvocationId to be "hook_abc123", got %v`, reloaded.HookInvocationId) + } + if reloaded.HookType != "preToolUse" { + t.Errorf(`Expected HookType to be "preToolUse", got %v`, reloaded.HookType) + } +} + +// TestHookStartPayloadToJSON tests that ToJSON produces valid JSON +func TestHookStartPayloadToJSON(t *testing.T) { + jsonData := ` +{ + "hookInvocationId": "hook_abc123", + "hookType": "preToolUse" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadHookStartPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load HookStartPayload: %v", err) + } + jsonOutput, err := instance.ToJSON() + if err != nil { + t.Fatalf("Failed to convert to JSON: %v", err) + } + + var parsed map[string]interface{} + if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated JSON: %v", err) + } +} + +// TestHookStartPayloadToYAML tests that ToYAML produces valid YAML +func TestHookStartPayloadToYAML(t *testing.T) { + jsonData := ` +{ + "hookInvocationId": "hook_abc123", + "hookType": "preToolUse" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadHookStartPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load HookStartPayload: %v", err) + } + yamlOutput, err := instance.ToYAML() + if err != nil { + t.Fatalf("Failed to convert to YAML: %v", err) + } + + var parsed map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated YAML: %v", err) + } +} diff --git a/runtime/go/prompty/model/host_tool_executor.go b/runtime/go/prompty/model/host_tool_executor.go new file mode 100644 index 00000000..97650f48 --- /dev/null +++ b/runtime/go/prompty/model/host_tool_executor.go @@ -0,0 +1,11 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: pipeline + +package prompty + +// HostToolExecutor represents Executes host tools after policy and permission checks. + +type HostToolExecutor interface { + // Execute — Execute a concrete host tool request and return its completion payload + Execute(request HostToolRequest) (HostToolResult, error) +} diff --git a/runtime/go/prompty/model/host_tool_request.go b/runtime/go/prompty/model/host_tool_request.go new file mode 100644 index 00000000..d2abd541 --- /dev/null +++ b/runtime/go/prompty/model/host_tool_request.go @@ -0,0 +1,113 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: events + +package prompty + +import ( + "encoding/json" + + "gopkg.in/yaml.v3" +) + +// HostToolRequest represents Request passed to a host tool executor after policy and permission checks. + +type HostToolRequest struct { + RequestId *string `json:"requestId,omitempty" yaml:"requestId,omitempty"` + ToolCallId *string `json:"toolCallId,omitempty" yaml:"toolCallId,omitempty"` + ToolName string `json:"toolName" yaml:"toolName"` + Arguments map[string]interface{} `json:"arguments,omitempty" yaml:"arguments,omitempty"` + WorkingDirectory *string `json:"workingDirectory,omitempty" yaml:"workingDirectory,omitempty"` +} + +// LoadHostToolRequest creates a HostToolRequest from a map[string]interface{} +func LoadHostToolRequest(data interface{}, ctx *LoadContext) (HostToolRequest, error) { + result := HostToolRequest{} + + // Load from map + if m, ok := data.(map[string]interface{}); ok { + if val, ok := m["requestId"]; ok && val != nil { + v := string(val.(string)) + result.RequestId = &v + } + if val, ok := m["toolCallId"]; ok && val != nil { + v := string(val.(string)) + result.ToolCallId = &v + } + if val, ok := m["toolName"]; ok && val != nil { + result.ToolName = string(val.(string)) + } + if val, ok := m["arguments"]; ok && val != nil { + if m, ok := val.(map[string]interface{}); ok { + result.Arguments = m + } + } + if val, ok := m["workingDirectory"]; ok && val != nil { + v := string(val.(string)) + result.WorkingDirectory = &v + } + } + + return result, nil +} + +// Save serializes HostToolRequest to map[string]interface{} +func (obj *HostToolRequest) Save(ctx *SaveContext) map[string]interface{} { + result := make(map[string]interface{}) + if obj.RequestId != nil { + result["requestId"] = *obj.RequestId + } + if obj.ToolCallId != nil { + result["toolCallId"] = *obj.ToolCallId + } + result["toolName"] = obj.ToolName + if obj.Arguments != nil { + result["arguments"] = obj.Arguments + } + if obj.WorkingDirectory != nil { + result["workingDirectory"] = *obj.WorkingDirectory + } + + return result +} + +// ToJSON serializes HostToolRequest to JSON string +func (obj *HostToolRequest) ToJSON() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := json.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// ToYAML serializes HostToolRequest to YAML string +func (obj *HostToolRequest) ToYAML() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := yaml.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// FromJSON creates HostToolRequest from JSON string +func HostToolRequestFromJSON(jsonStr string) (HostToolRequest, error) { + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { + return HostToolRequest{}, err + } + ctx := NewLoadContext() + return LoadHostToolRequest(data, ctx) +} + +// FromYAML creates HostToolRequest from YAML string +func HostToolRequestFromYAML(yamlStr string) (HostToolRequest, error) { + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlStr), &data); err != nil { + return HostToolRequest{}, err + } + ctx := NewLoadContext() + return LoadHostToolRequest(data, ctx) +} diff --git a/runtime/go/prompty/model/host_tool_request_test.go b/runtime/go/prompty/model/host_tool_request_test.go new file mode 100644 index 00000000..48023ef3 --- /dev/null +++ b/runtime/go/prompty/model/host_tool_request_test.go @@ -0,0 +1,182 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +package prompty_test + +import ( + "encoding/json" + "testing" + + "gopkg.in/yaml.v3" + + "prompty/model" +) + +// TestHostToolRequestLoadJSON tests loading HostToolRequest from JSON +func TestHostToolRequestLoadJSON(t *testing.T) { + jsonData := ` +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "workingDirectory": "/workspace/project" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadHostToolRequest(data, ctx) + if err != nil { + t.Fatalf("Failed to load HostToolRequest: %v", err) + } + if instance.RequestId == nil || *instance.RequestId != "exec_abc123" { + t.Errorf(`Expected RequestId to be "exec_abc123", got %v`, instance.RequestId) + } + if instance.ToolCallId == nil || *instance.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, instance.ToolCallId) + } + if instance.ToolName != "powershell" { + t.Errorf(`Expected ToolName to be "powershell", got %v`, instance.ToolName) + } + if instance.WorkingDirectory == nil || *instance.WorkingDirectory != "/workspace/project" { + t.Errorf(`Expected WorkingDirectory to be "/workspace/project", got %v`, instance.WorkingDirectory) + } +} + +// TestHostToolRequestLoadYAML tests loading HostToolRequest from YAML +func TestHostToolRequestLoadYAML(t *testing.T) { + yamlData := ` +requestId: exec_abc123 +toolCallId: call_abc123 +toolName: powershell +workingDirectory: /workspace/project + +` + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlData), &data); err != nil { + t.Fatalf("Failed to parse YAML: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadHostToolRequest(data, ctx) + if err != nil { + t.Fatalf("Failed to load HostToolRequest: %v", err) + } + if instance.RequestId == nil || *instance.RequestId != "exec_abc123" { + t.Errorf(`Expected RequestId to be "exec_abc123", got %v`, instance.RequestId) + } + if instance.ToolCallId == nil || *instance.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, instance.ToolCallId) + } + if instance.ToolName != "powershell" { + t.Errorf(`Expected ToolName to be "powershell", got %v`, instance.ToolName) + } + if instance.WorkingDirectory == nil || *instance.WorkingDirectory != "/workspace/project" { + t.Errorf(`Expected WorkingDirectory to be "/workspace/project", got %v`, instance.WorkingDirectory) + } +} + +// TestHostToolRequestRoundtrip tests load -> save -> load produces equivalent data +func TestHostToolRequestRoundtrip(t *testing.T) { + jsonData := ` +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "workingDirectory": "/workspace/project" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + loadCtx := prompty.NewLoadContext() + instance, err := prompty.LoadHostToolRequest(data, loadCtx) + if err != nil { + t.Fatalf("Failed to load HostToolRequest: %v", err) + } + saveCtx := prompty.NewSaveContext() + savedData := instance.Save(saveCtx) + + reloaded, err := prompty.LoadHostToolRequest(savedData, loadCtx) + if err != nil { + t.Fatalf("Failed to reload HostToolRequest: %v", err) + } + if reloaded.RequestId == nil || *reloaded.RequestId != "exec_abc123" { + t.Errorf(`Expected RequestId to be "exec_abc123", got %v`, reloaded.RequestId) + } + if reloaded.ToolCallId == nil || *reloaded.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, reloaded.ToolCallId) + } + if reloaded.ToolName != "powershell" { + t.Errorf(`Expected ToolName to be "powershell", got %v`, reloaded.ToolName) + } + if reloaded.WorkingDirectory == nil || *reloaded.WorkingDirectory != "/workspace/project" { + t.Errorf(`Expected WorkingDirectory to be "/workspace/project", got %v`, reloaded.WorkingDirectory) + } +} + +// TestHostToolRequestToJSON tests that ToJSON produces valid JSON +func TestHostToolRequestToJSON(t *testing.T) { + jsonData := ` +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "workingDirectory": "/workspace/project" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadHostToolRequest(data, ctx) + if err != nil { + t.Fatalf("Failed to load HostToolRequest: %v", err) + } + jsonOutput, err := instance.ToJSON() + if err != nil { + t.Fatalf("Failed to convert to JSON: %v", err) + } + + var parsed map[string]interface{} + if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated JSON: %v", err) + } +} + +// TestHostToolRequestToYAML tests that ToYAML produces valid YAML +func TestHostToolRequestToYAML(t *testing.T) { + jsonData := ` +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "workingDirectory": "/workspace/project" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadHostToolRequest(data, ctx) + if err != nil { + t.Fatalf("Failed to load HostToolRequest: %v", err) + } + yamlOutput, err := instance.ToYAML() + if err != nil { + t.Fatalf("Failed to convert to YAML: %v", err) + } + + var parsed map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated YAML: %v", err) + } +} diff --git a/runtime/go/prompty/model/host_tool_result.go b/runtime/go/prompty/model/host_tool_result.go new file mode 100644 index 00000000..eed30373 --- /dev/null +++ b/runtime/go/prompty/model/host_tool_result.go @@ -0,0 +1,163 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: events + +package prompty + +import ( + "encoding/json" + + "gopkg.in/yaml.v3" +) + +// HostToolResult represents Result returned by a host tool executor. + +type HostToolResult struct { + RequestId *string `json:"requestId,omitempty" yaml:"requestId,omitempty"` + ToolCallId *string `json:"toolCallId,omitempty" yaml:"toolCallId,omitempty"` + ToolName string `json:"toolName" yaml:"toolName"` + Success bool `json:"success" yaml:"success"` + Result *interface{} `json:"result,omitempty" yaml:"result,omitempty"` + ExitCode *int32 `json:"exitCode,omitempty" yaml:"exitCode,omitempty"` + DurationMs *float64 `json:"durationMs,omitempty" yaml:"durationMs,omitempty"` + ErrorKind *string `json:"errorKind,omitempty" yaml:"errorKind,omitempty"` + Telemetry map[string]interface{} `json:"telemetry,omitempty" yaml:"telemetry,omitempty"` +} + +// LoadHostToolResult creates a HostToolResult from a map[string]interface{} +func LoadHostToolResult(data interface{}, ctx *LoadContext) (HostToolResult, error) { + result := HostToolResult{} + + // Load from map + if m, ok := data.(map[string]interface{}); ok { + if val, ok := m["requestId"]; ok && val != nil { + v := string(val.(string)) + result.RequestId = &v + } + if val, ok := m["toolCallId"]; ok && val != nil { + v := string(val.(string)) + result.ToolCallId = &v + } + if val, ok := m["toolName"]; ok && val != nil { + result.ToolName = string(val.(string)) + } + if val, ok := m["success"]; ok && val != nil { + result.Success = val.(bool) + } + if val, ok := m["result"]; ok && val != nil { + result.Result = &val + } + if val, ok := m["exitCode"]; ok && val != nil { // Handle various numeric types from JSON/YAML/roundtrip + var v int32 + switch n := val.(type) { + case int: + v = int32(n) + case int32: + v = int32(n) + case int64: + v = int32(n) + case float64: + v = int32(n) + } + result.ExitCode = &v + } + if val, ok := m["durationMs"]; ok && val != nil { // Handle various numeric types from JSON/YAML/roundtrip + var v float64 + switch n := val.(type) { + case int: + v = float64(n) + case int32: + v = float64(n) + case int64: + v = float64(n) + case float32: + v = float64(n) + case float64: + v = n + } + result.DurationMs = &v + } + if val, ok := m["errorKind"]; ok && val != nil { + v := string(val.(string)) + result.ErrorKind = &v + } + if val, ok := m["telemetry"]; ok && val != nil { + if m, ok := val.(map[string]interface{}); ok { + result.Telemetry = m + } + } + } + + return result, nil +} + +// Save serializes HostToolResult to map[string]interface{} +func (obj *HostToolResult) Save(ctx *SaveContext) map[string]interface{} { + result := make(map[string]interface{}) + if obj.RequestId != nil { + result["requestId"] = *obj.RequestId + } + if obj.ToolCallId != nil { + result["toolCallId"] = *obj.ToolCallId + } + result["toolName"] = obj.ToolName + result["success"] = obj.Success + if obj.Result != nil { + result["result"] = *obj.Result + } + if obj.ExitCode != nil { + result["exitCode"] = *obj.ExitCode + } + if obj.DurationMs != nil { + result["durationMs"] = *obj.DurationMs + } + if obj.ErrorKind != nil { + result["errorKind"] = *obj.ErrorKind + } + if obj.Telemetry != nil { + result["telemetry"] = obj.Telemetry + } + + return result +} + +// ToJSON serializes HostToolResult to JSON string +func (obj *HostToolResult) ToJSON() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := json.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// ToYAML serializes HostToolResult to YAML string +func (obj *HostToolResult) ToYAML() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := yaml.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// FromJSON creates HostToolResult from JSON string +func HostToolResultFromJSON(jsonStr string) (HostToolResult, error) { + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { + return HostToolResult{}, err + } + ctx := NewLoadContext() + return LoadHostToolResult(data, ctx) +} + +// FromYAML creates HostToolResult from YAML string +func HostToolResultFromYAML(yamlStr string) (HostToolResult, error) { + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlStr), &data); err != nil { + return HostToolResult{}, err + } + ctx := NewLoadContext() + return LoadHostToolResult(data, ctx) +} diff --git a/runtime/go/prompty/model/host_tool_result_test.go b/runtime/go/prompty/model/host_tool_result_test.go new file mode 100644 index 00000000..94e03d41 --- /dev/null +++ b/runtime/go/prompty/model/host_tool_result_test.go @@ -0,0 +1,224 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +package prompty_test + +import ( + "encoding/json" + "testing" + + "gopkg.in/yaml.v3" + + "prompty/model" +) + +// TestHostToolResultLoadJSON tests loading HostToolResult from JSON +func TestHostToolResultLoadJSON(t *testing.T) { + jsonData := ` +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "success": true, + "exitCode": 0, + "durationMs": 250, + "errorKind": "timeout" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadHostToolResult(data, ctx) + if err != nil { + t.Fatalf("Failed to load HostToolResult: %v", err) + } + if instance.RequestId == nil || *instance.RequestId != "exec_abc123" { + t.Errorf(`Expected RequestId to be "exec_abc123", got %v`, instance.RequestId) + } + if instance.ToolCallId == nil || *instance.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, instance.ToolCallId) + } + if instance.ToolName != "powershell" { + t.Errorf(`Expected ToolName to be "powershell", got %v`, instance.ToolName) + } + if instance.Success != true { + t.Errorf(`Expected Success to be true, got %v`, instance.Success) + } + if instance.ExitCode == nil || *instance.ExitCode != 0 { + t.Errorf(`Expected ExitCode to be 0, got %v`, instance.ExitCode) + } + if instance.DurationMs == nil || *instance.DurationMs != 250 { + t.Errorf(`Expected DurationMs to be 250, got %v`, instance.DurationMs) + } + if instance.ErrorKind == nil || *instance.ErrorKind != "timeout" { + t.Errorf(`Expected ErrorKind to be "timeout", got %v`, instance.ErrorKind) + } +} + +// TestHostToolResultLoadYAML tests loading HostToolResult from YAML +func TestHostToolResultLoadYAML(t *testing.T) { + yamlData := ` +requestId: exec_abc123 +toolCallId: call_abc123 +toolName: powershell +success: true +exitCode: 0 +durationMs: 250 +errorKind: timeout + +` + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlData), &data); err != nil { + t.Fatalf("Failed to parse YAML: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadHostToolResult(data, ctx) + if err != nil { + t.Fatalf("Failed to load HostToolResult: %v", err) + } + if instance.RequestId == nil || *instance.RequestId != "exec_abc123" { + t.Errorf(`Expected RequestId to be "exec_abc123", got %v`, instance.RequestId) + } + if instance.ToolCallId == nil || *instance.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, instance.ToolCallId) + } + if instance.ToolName != "powershell" { + t.Errorf(`Expected ToolName to be "powershell", got %v`, instance.ToolName) + } + if instance.Success != true { + t.Errorf(`Expected Success to be true, got %v`, instance.Success) + } + if instance.ExitCode == nil || *instance.ExitCode != 0 { + t.Errorf(`Expected ExitCode to be 0, got %v`, instance.ExitCode) + } + if instance.DurationMs == nil || *instance.DurationMs != 250 { + t.Errorf(`Expected DurationMs to be 250, got %v`, instance.DurationMs) + } + if instance.ErrorKind == nil || *instance.ErrorKind != "timeout" { + t.Errorf(`Expected ErrorKind to be "timeout", got %v`, instance.ErrorKind) + } +} + +// TestHostToolResultRoundtrip tests load -> save -> load produces equivalent data +func TestHostToolResultRoundtrip(t *testing.T) { + jsonData := ` +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "success": true, + "exitCode": 0, + "durationMs": 250, + "errorKind": "timeout" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + loadCtx := prompty.NewLoadContext() + instance, err := prompty.LoadHostToolResult(data, loadCtx) + if err != nil { + t.Fatalf("Failed to load HostToolResult: %v", err) + } + saveCtx := prompty.NewSaveContext() + savedData := instance.Save(saveCtx) + + reloaded, err := prompty.LoadHostToolResult(savedData, loadCtx) + if err != nil { + t.Fatalf("Failed to reload HostToolResult: %v", err) + } + if reloaded.RequestId == nil || *reloaded.RequestId != "exec_abc123" { + t.Errorf(`Expected RequestId to be "exec_abc123", got %v`, reloaded.RequestId) + } + if reloaded.ToolCallId == nil || *reloaded.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, reloaded.ToolCallId) + } + if reloaded.ToolName != "powershell" { + t.Errorf(`Expected ToolName to be "powershell", got %v`, reloaded.ToolName) + } + if reloaded.Success != true { + t.Errorf(`Expected Success to be true, got %v`, reloaded.Success) + } + if reloaded.ExitCode == nil || *reloaded.ExitCode != 0 { + t.Errorf(`Expected ExitCode to be 0, got %v`, reloaded.ExitCode) + } + if reloaded.DurationMs == nil || *reloaded.DurationMs != 250 { + t.Errorf(`Expected DurationMs to be 250, got %v`, reloaded.DurationMs) + } + if reloaded.ErrorKind == nil || *reloaded.ErrorKind != "timeout" { + t.Errorf(`Expected ErrorKind to be "timeout", got %v`, reloaded.ErrorKind) + } +} + +// TestHostToolResultToJSON tests that ToJSON produces valid JSON +func TestHostToolResultToJSON(t *testing.T) { + jsonData := ` +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "success": true, + "exitCode": 0, + "durationMs": 250, + "errorKind": "timeout" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadHostToolResult(data, ctx) + if err != nil { + t.Fatalf("Failed to load HostToolResult: %v", err) + } + jsonOutput, err := instance.ToJSON() + if err != nil { + t.Fatalf("Failed to convert to JSON: %v", err) + } + + var parsed map[string]interface{} + if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated JSON: %v", err) + } +} + +// TestHostToolResultToYAML tests that ToYAML produces valid YAML +func TestHostToolResultToYAML(t *testing.T) { + jsonData := ` +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "success": true, + "exitCode": 0, + "durationMs": 250, + "errorKind": "timeout" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadHostToolResult(data, ctx) + if err != nil { + t.Fatalf("Failed to load HostToolResult: %v", err) + } + yamlOutput, err := instance.ToYAML() + if err != nil { + t.Fatalf("Failed to convert to YAML: %v", err) + } + + var parsed map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated YAML: %v", err) + } +} diff --git a/runtime/go/prompty/model/permission_completed_payload.go b/runtime/go/prompty/model/permission_completed_payload.go index 12d34036..c2831053 100644 --- a/runtime/go/prompty/model/permission_completed_payload.go +++ b/runtime/go/prompty/model/permission_completed_payload.go @@ -12,9 +12,12 @@ import ( // PermissionCompletedPayload represents Payload for permission completion events — an approval decision was made. type PermissionCompletedPayload struct { - Permission string `json:"permission" yaml:"permission"` - Approved bool `json:"approved" yaml:"approved"` - Reason *string `json:"reason,omitempty" yaml:"reason,omitempty"` + RequestId *string `json:"requestId,omitempty" yaml:"requestId,omitempty"` + ToolCallId *string `json:"toolCallId,omitempty" yaml:"toolCallId,omitempty"` + Permission string `json:"permission" yaml:"permission"` + Approved bool `json:"approved" yaml:"approved"` + Reason *string `json:"reason,omitempty" yaml:"reason,omitempty"` + Result map[string]interface{} `json:"result,omitempty" yaml:"result,omitempty"` } // LoadPermissionCompletedPayload creates a PermissionCompletedPayload from a map[string]interface{} @@ -23,6 +26,14 @@ func LoadPermissionCompletedPayload(data interface{}, ctx *LoadContext) (Permiss // Load from map if m, ok := data.(map[string]interface{}); ok { + if val, ok := m["requestId"]; ok && val != nil { + v := string(val.(string)) + result.RequestId = &v + } + if val, ok := m["toolCallId"]; ok && val != nil { + v := string(val.(string)) + result.ToolCallId = &v + } if val, ok := m["permission"]; ok && val != nil { result.Permission = string(val.(string)) } @@ -33,6 +44,11 @@ func LoadPermissionCompletedPayload(data interface{}, ctx *LoadContext) (Permiss v := string(val.(string)) result.Reason = &v } + if val, ok := m["result"]; ok && val != nil { + if m, ok := val.(map[string]interface{}); ok { + result.Result = m + } + } } return result, nil @@ -41,11 +57,20 @@ func LoadPermissionCompletedPayload(data interface{}, ctx *LoadContext) (Permiss // Save serializes PermissionCompletedPayload to map[string]interface{} func (obj *PermissionCompletedPayload) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) + if obj.RequestId != nil { + result["requestId"] = *obj.RequestId + } + if obj.ToolCallId != nil { + result["toolCallId"] = *obj.ToolCallId + } result["permission"] = obj.Permission result["approved"] = obj.Approved if obj.Reason != nil { result["reason"] = *obj.Reason } + if obj.Result != nil { + result["result"] = obj.Result + } return result } diff --git a/runtime/go/prompty/model/permission_completed_payload_test.go b/runtime/go/prompty/model/permission_completed_payload_test.go index 631de6d1..51a43cb4 100644 --- a/runtime/go/prompty/model/permission_completed_payload_test.go +++ b/runtime/go/prompty/model/permission_completed_payload_test.go @@ -15,6 +15,8 @@ import ( func TestPermissionCompletedPayloadLoadJSON(t *testing.T) { jsonData := ` { + "requestId": "perm_abc123", + "toolCallId": "call_abc123", "permission": "tool.execute", "approved": true, "reason": "user_approved" @@ -30,6 +32,12 @@ func TestPermissionCompletedPayloadLoadJSON(t *testing.T) { if err != nil { t.Fatalf("Failed to load PermissionCompletedPayload: %v", err) } + if instance.RequestId == nil || *instance.RequestId != "perm_abc123" { + t.Errorf(`Expected RequestId to be "perm_abc123", got %v`, instance.RequestId) + } + if instance.ToolCallId == nil || *instance.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, instance.ToolCallId) + } if instance.Permission != "tool.execute" { t.Errorf(`Expected Permission to be "tool.execute", got %v`, instance.Permission) } @@ -44,6 +52,8 @@ func TestPermissionCompletedPayloadLoadJSON(t *testing.T) { // TestPermissionCompletedPayloadLoadYAML tests loading PermissionCompletedPayload from YAML func TestPermissionCompletedPayloadLoadYAML(t *testing.T) { yamlData := ` +requestId: perm_abc123 +toolCallId: call_abc123 permission: tool.execute approved: true reason: user_approved @@ -59,6 +69,12 @@ reason: user_approved if err != nil { t.Fatalf("Failed to load PermissionCompletedPayload: %v", err) } + if instance.RequestId == nil || *instance.RequestId != "perm_abc123" { + t.Errorf(`Expected RequestId to be "perm_abc123", got %v`, instance.RequestId) + } + if instance.ToolCallId == nil || *instance.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, instance.ToolCallId) + } if instance.Permission != "tool.execute" { t.Errorf(`Expected Permission to be "tool.execute", got %v`, instance.Permission) } @@ -74,6 +90,8 @@ reason: user_approved func TestPermissionCompletedPayloadRoundtrip(t *testing.T) { jsonData := ` { + "requestId": "perm_abc123", + "toolCallId": "call_abc123", "permission": "tool.execute", "approved": true, "reason": "user_approved" @@ -96,6 +114,12 @@ func TestPermissionCompletedPayloadRoundtrip(t *testing.T) { if err != nil { t.Fatalf("Failed to reload PermissionCompletedPayload: %v", err) } + if reloaded.RequestId == nil || *reloaded.RequestId != "perm_abc123" { + t.Errorf(`Expected RequestId to be "perm_abc123", got %v`, reloaded.RequestId) + } + if reloaded.ToolCallId == nil || *reloaded.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, reloaded.ToolCallId) + } if reloaded.Permission != "tool.execute" { t.Errorf(`Expected Permission to be "tool.execute", got %v`, reloaded.Permission) } @@ -111,6 +135,8 @@ func TestPermissionCompletedPayloadRoundtrip(t *testing.T) { func TestPermissionCompletedPayloadToJSON(t *testing.T) { jsonData := ` { + "requestId": "perm_abc123", + "toolCallId": "call_abc123", "permission": "tool.execute", "approved": true, "reason": "user_approved" @@ -141,6 +167,8 @@ func TestPermissionCompletedPayloadToJSON(t *testing.T) { func TestPermissionCompletedPayloadToYAML(t *testing.T) { jsonData := ` { + "requestId": "perm_abc123", + "toolCallId": "call_abc123", "permission": "tool.execute", "approved": true, "reason": "user_approved" diff --git a/runtime/go/prompty/model/permission_decision.go b/runtime/go/prompty/model/permission_decision.go new file mode 100644 index 00000000..bf481cfb --- /dev/null +++ b/runtime/go/prompty/model/permission_decision.go @@ -0,0 +1,118 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: events + +package prompty + +import ( + "encoding/json" + + "gopkg.in/yaml.v3" +) + +// PermissionDecision represents Decision returned by a permission resolver. + +type PermissionDecision struct { + RequestId *string `json:"requestId,omitempty" yaml:"requestId,omitempty"` + ToolCallId *string `json:"toolCallId,omitempty" yaml:"toolCallId,omitempty"` + Permission string `json:"permission" yaml:"permission"` + Approved bool `json:"approved" yaml:"approved"` + Reason *string `json:"reason,omitempty" yaml:"reason,omitempty"` + Result map[string]interface{} `json:"result,omitempty" yaml:"result,omitempty"` +} + +// LoadPermissionDecision creates a PermissionDecision from a map[string]interface{} +func LoadPermissionDecision(data interface{}, ctx *LoadContext) (PermissionDecision, error) { + result := PermissionDecision{} + + // Load from map + if m, ok := data.(map[string]interface{}); ok { + if val, ok := m["requestId"]; ok && val != nil { + v := string(val.(string)) + result.RequestId = &v + } + if val, ok := m["toolCallId"]; ok && val != nil { + v := string(val.(string)) + result.ToolCallId = &v + } + if val, ok := m["permission"]; ok && val != nil { + result.Permission = string(val.(string)) + } + if val, ok := m["approved"]; ok && val != nil { + result.Approved = val.(bool) + } + if val, ok := m["reason"]; ok && val != nil { + v := string(val.(string)) + result.Reason = &v + } + if val, ok := m["result"]; ok && val != nil { + if m, ok := val.(map[string]interface{}); ok { + result.Result = m + } + } + } + + return result, nil +} + +// Save serializes PermissionDecision to map[string]interface{} +func (obj *PermissionDecision) Save(ctx *SaveContext) map[string]interface{} { + result := make(map[string]interface{}) + if obj.RequestId != nil { + result["requestId"] = *obj.RequestId + } + if obj.ToolCallId != nil { + result["toolCallId"] = *obj.ToolCallId + } + result["permission"] = obj.Permission + result["approved"] = obj.Approved + if obj.Reason != nil { + result["reason"] = *obj.Reason + } + if obj.Result != nil { + result["result"] = obj.Result + } + + return result +} + +// ToJSON serializes PermissionDecision to JSON string +func (obj *PermissionDecision) ToJSON() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := json.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// ToYAML serializes PermissionDecision to YAML string +func (obj *PermissionDecision) ToYAML() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := yaml.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// FromJSON creates PermissionDecision from JSON string +func PermissionDecisionFromJSON(jsonStr string) (PermissionDecision, error) { + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { + return PermissionDecision{}, err + } + ctx := NewLoadContext() + return LoadPermissionDecision(data, ctx) +} + +// FromYAML creates PermissionDecision from YAML string +func PermissionDecisionFromYAML(yamlStr string) (PermissionDecision, error) { + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlStr), &data); err != nil { + return PermissionDecision{}, err + } + ctx := NewLoadContext() + return LoadPermissionDecision(data, ctx) +} diff --git a/runtime/go/prompty/model/permission_decision_test.go b/runtime/go/prompty/model/permission_decision_test.go new file mode 100644 index 00000000..dbb58f0e --- /dev/null +++ b/runtime/go/prompty/model/permission_decision_test.go @@ -0,0 +1,196 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +package prompty_test + +import ( + "encoding/json" + "testing" + + "gopkg.in/yaml.v3" + + "prompty/model" +) + +// TestPermissionDecisionLoadJSON tests loading PermissionDecision from JSON +func TestPermissionDecisionLoadJSON(t *testing.T) { + jsonData := ` +{ + "requestId": "perm_abc123", + "toolCallId": "call_abc123", + "permission": "tool.execute", + "approved": true, + "reason": "user_approved" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadPermissionDecision(data, ctx) + if err != nil { + t.Fatalf("Failed to load PermissionDecision: %v", err) + } + if instance.RequestId == nil || *instance.RequestId != "perm_abc123" { + t.Errorf(`Expected RequestId to be "perm_abc123", got %v`, instance.RequestId) + } + if instance.ToolCallId == nil || *instance.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, instance.ToolCallId) + } + if instance.Permission != "tool.execute" { + t.Errorf(`Expected Permission to be "tool.execute", got %v`, instance.Permission) + } + if instance.Approved != true { + t.Errorf(`Expected Approved to be true, got %v`, instance.Approved) + } + if instance.Reason == nil || *instance.Reason != "user_approved" { + t.Errorf(`Expected Reason to be "user_approved", got %v`, instance.Reason) + } +} + +// TestPermissionDecisionLoadYAML tests loading PermissionDecision from YAML +func TestPermissionDecisionLoadYAML(t *testing.T) { + yamlData := ` +requestId: perm_abc123 +toolCallId: call_abc123 +permission: tool.execute +approved: true +reason: user_approved + +` + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlData), &data); err != nil { + t.Fatalf("Failed to parse YAML: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadPermissionDecision(data, ctx) + if err != nil { + t.Fatalf("Failed to load PermissionDecision: %v", err) + } + if instance.RequestId == nil || *instance.RequestId != "perm_abc123" { + t.Errorf(`Expected RequestId to be "perm_abc123", got %v`, instance.RequestId) + } + if instance.ToolCallId == nil || *instance.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, instance.ToolCallId) + } + if instance.Permission != "tool.execute" { + t.Errorf(`Expected Permission to be "tool.execute", got %v`, instance.Permission) + } + if instance.Approved != true { + t.Errorf(`Expected Approved to be true, got %v`, instance.Approved) + } + if instance.Reason == nil || *instance.Reason != "user_approved" { + t.Errorf(`Expected Reason to be "user_approved", got %v`, instance.Reason) + } +} + +// TestPermissionDecisionRoundtrip tests load -> save -> load produces equivalent data +func TestPermissionDecisionRoundtrip(t *testing.T) { + jsonData := ` +{ + "requestId": "perm_abc123", + "toolCallId": "call_abc123", + "permission": "tool.execute", + "approved": true, + "reason": "user_approved" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + loadCtx := prompty.NewLoadContext() + instance, err := prompty.LoadPermissionDecision(data, loadCtx) + if err != nil { + t.Fatalf("Failed to load PermissionDecision: %v", err) + } + saveCtx := prompty.NewSaveContext() + savedData := instance.Save(saveCtx) + + reloaded, err := prompty.LoadPermissionDecision(savedData, loadCtx) + if err != nil { + t.Fatalf("Failed to reload PermissionDecision: %v", err) + } + if reloaded.RequestId == nil || *reloaded.RequestId != "perm_abc123" { + t.Errorf(`Expected RequestId to be "perm_abc123", got %v`, reloaded.RequestId) + } + if reloaded.ToolCallId == nil || *reloaded.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, reloaded.ToolCallId) + } + if reloaded.Permission != "tool.execute" { + t.Errorf(`Expected Permission to be "tool.execute", got %v`, reloaded.Permission) + } + if reloaded.Approved != true { + t.Errorf(`Expected Approved to be true, got %v`, reloaded.Approved) + } + if reloaded.Reason == nil || *reloaded.Reason != "user_approved" { + t.Errorf(`Expected Reason to be "user_approved", got %v`, reloaded.Reason) + } +} + +// TestPermissionDecisionToJSON tests that ToJSON produces valid JSON +func TestPermissionDecisionToJSON(t *testing.T) { + jsonData := ` +{ + "requestId": "perm_abc123", + "toolCallId": "call_abc123", + "permission": "tool.execute", + "approved": true, + "reason": "user_approved" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadPermissionDecision(data, ctx) + if err != nil { + t.Fatalf("Failed to load PermissionDecision: %v", err) + } + jsonOutput, err := instance.ToJSON() + if err != nil { + t.Fatalf("Failed to convert to JSON: %v", err) + } + + var parsed map[string]interface{} + if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated JSON: %v", err) + } +} + +// TestPermissionDecisionToYAML tests that ToYAML produces valid YAML +func TestPermissionDecisionToYAML(t *testing.T) { + jsonData := ` +{ + "requestId": "perm_abc123", + "toolCallId": "call_abc123", + "permission": "tool.execute", + "approved": true, + "reason": "user_approved" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadPermissionDecision(data, ctx) + if err != nil { + t.Fatalf("Failed to load PermissionDecision: %v", err) + } + yamlOutput, err := instance.ToYAML() + if err != nil { + t.Fatalf("Failed to convert to YAML: %v", err) + } + + var parsed map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated YAML: %v", err) + } +} diff --git a/runtime/go/prompty/model/permission_request.go b/runtime/go/prompty/model/permission_request.go new file mode 100644 index 00000000..4c723889 --- /dev/null +++ b/runtime/go/prompty/model/permission_request.go @@ -0,0 +1,131 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: events + +package prompty + +import ( + "encoding/json" + + "gopkg.in/yaml.v3" +) + +// PermissionRequest represents Request passed to a permission resolver. This is the live protocol shape; the +// event payloads above can include trace-only metadata such as redaction state. + +type PermissionRequest struct { + RequestId *string `json:"requestId,omitempty" yaml:"requestId,omitempty"` + ToolCallId *string `json:"toolCallId,omitempty" yaml:"toolCallId,omitempty"` + Permission string `json:"permission" yaml:"permission"` + Target *string `json:"target,omitempty" yaml:"target,omitempty"` + Details map[string]interface{} `json:"details,omitempty" yaml:"details,omitempty"` + PromptRequest *string `json:"promptRequest,omitempty" yaml:"promptRequest,omitempty"` + Policy map[string]interface{} `json:"policy,omitempty" yaml:"policy,omitempty"` +} + +// LoadPermissionRequest creates a PermissionRequest from a map[string]interface{} +func LoadPermissionRequest(data interface{}, ctx *LoadContext) (PermissionRequest, error) { + result := PermissionRequest{} + + // Load from map + if m, ok := data.(map[string]interface{}); ok { + if val, ok := m["requestId"]; ok && val != nil { + v := string(val.(string)) + result.RequestId = &v + } + if val, ok := m["toolCallId"]; ok && val != nil { + v := string(val.(string)) + result.ToolCallId = &v + } + if val, ok := m["permission"]; ok && val != nil { + result.Permission = string(val.(string)) + } + if val, ok := m["target"]; ok && val != nil { + v := string(val.(string)) + result.Target = &v + } + if val, ok := m["details"]; ok && val != nil { + if m, ok := val.(map[string]interface{}); ok { + result.Details = m + } + } + if val, ok := m["promptRequest"]; ok && val != nil { + v := string(val.(string)) + result.PromptRequest = &v + } + if val, ok := m["policy"]; ok && val != nil { + if m, ok := val.(map[string]interface{}); ok { + result.Policy = m + } + } + } + + return result, nil +} + +// Save serializes PermissionRequest to map[string]interface{} +func (obj *PermissionRequest) Save(ctx *SaveContext) map[string]interface{} { + result := make(map[string]interface{}) + if obj.RequestId != nil { + result["requestId"] = *obj.RequestId + } + if obj.ToolCallId != nil { + result["toolCallId"] = *obj.ToolCallId + } + result["permission"] = obj.Permission + if obj.Target != nil { + result["target"] = *obj.Target + } + if obj.Details != nil { + result["details"] = obj.Details + } + if obj.PromptRequest != nil { + result["promptRequest"] = *obj.PromptRequest + } + if obj.Policy != nil { + result["policy"] = obj.Policy + } + + return result +} + +// ToJSON serializes PermissionRequest to JSON string +func (obj *PermissionRequest) ToJSON() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := json.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// ToYAML serializes PermissionRequest to YAML string +func (obj *PermissionRequest) ToYAML() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := yaml.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// FromJSON creates PermissionRequest from JSON string +func PermissionRequestFromJSON(jsonStr string) (PermissionRequest, error) { + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { + return PermissionRequest{}, err + } + ctx := NewLoadContext() + return LoadPermissionRequest(data, ctx) +} + +// FromYAML creates PermissionRequest from YAML string +func PermissionRequestFromYAML(yamlStr string) (PermissionRequest, error) { + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlStr), &data); err != nil { + return PermissionRequest{}, err + } + ctx := NewLoadContext() + return LoadPermissionRequest(data, ctx) +} diff --git a/runtime/go/prompty/model/permission_request_test.go b/runtime/go/prompty/model/permission_request_test.go new file mode 100644 index 00000000..16dc42ef --- /dev/null +++ b/runtime/go/prompty/model/permission_request_test.go @@ -0,0 +1,196 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +package prompty_test + +import ( + "encoding/json" + "testing" + + "gopkg.in/yaml.v3" + + "prompty/model" +) + +// TestPermissionRequestLoadJSON tests loading PermissionRequest from JSON +func TestPermissionRequestLoadJSON(t *testing.T) { + jsonData := ` +{ + "requestId": "perm_abc123", + "toolCallId": "call_abc123", + "permission": "tool.execute", + "target": "shell", + "promptRequest": "Allow shell to run tests?" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadPermissionRequest(data, ctx) + if err != nil { + t.Fatalf("Failed to load PermissionRequest: %v", err) + } + if instance.RequestId == nil || *instance.RequestId != "perm_abc123" { + t.Errorf(`Expected RequestId to be "perm_abc123", got %v`, instance.RequestId) + } + if instance.ToolCallId == nil || *instance.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, instance.ToolCallId) + } + if instance.Permission != "tool.execute" { + t.Errorf(`Expected Permission to be "tool.execute", got %v`, instance.Permission) + } + if instance.Target == nil || *instance.Target != "shell" { + t.Errorf(`Expected Target to be "shell", got %v`, instance.Target) + } + if instance.PromptRequest == nil || *instance.PromptRequest != "Allow shell to run tests?" { + t.Errorf(`Expected PromptRequest to be "Allow shell to run tests?", got %v`, instance.PromptRequest) + } +} + +// TestPermissionRequestLoadYAML tests loading PermissionRequest from YAML +func TestPermissionRequestLoadYAML(t *testing.T) { + yamlData := ` +requestId: perm_abc123 +toolCallId: call_abc123 +permission: tool.execute +target: shell +promptRequest: Allow shell to run tests? + +` + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlData), &data); err != nil { + t.Fatalf("Failed to parse YAML: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadPermissionRequest(data, ctx) + if err != nil { + t.Fatalf("Failed to load PermissionRequest: %v", err) + } + if instance.RequestId == nil || *instance.RequestId != "perm_abc123" { + t.Errorf(`Expected RequestId to be "perm_abc123", got %v`, instance.RequestId) + } + if instance.ToolCallId == nil || *instance.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, instance.ToolCallId) + } + if instance.Permission != "tool.execute" { + t.Errorf(`Expected Permission to be "tool.execute", got %v`, instance.Permission) + } + if instance.Target == nil || *instance.Target != "shell" { + t.Errorf(`Expected Target to be "shell", got %v`, instance.Target) + } + if instance.PromptRequest == nil || *instance.PromptRequest != "Allow shell to run tests?" { + t.Errorf(`Expected PromptRequest to be "Allow shell to run tests?", got %v`, instance.PromptRequest) + } +} + +// TestPermissionRequestRoundtrip tests load -> save -> load produces equivalent data +func TestPermissionRequestRoundtrip(t *testing.T) { + jsonData := ` +{ + "requestId": "perm_abc123", + "toolCallId": "call_abc123", + "permission": "tool.execute", + "target": "shell", + "promptRequest": "Allow shell to run tests?" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + loadCtx := prompty.NewLoadContext() + instance, err := prompty.LoadPermissionRequest(data, loadCtx) + if err != nil { + t.Fatalf("Failed to load PermissionRequest: %v", err) + } + saveCtx := prompty.NewSaveContext() + savedData := instance.Save(saveCtx) + + reloaded, err := prompty.LoadPermissionRequest(savedData, loadCtx) + if err != nil { + t.Fatalf("Failed to reload PermissionRequest: %v", err) + } + if reloaded.RequestId == nil || *reloaded.RequestId != "perm_abc123" { + t.Errorf(`Expected RequestId to be "perm_abc123", got %v`, reloaded.RequestId) + } + if reloaded.ToolCallId == nil || *reloaded.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, reloaded.ToolCallId) + } + if reloaded.Permission != "tool.execute" { + t.Errorf(`Expected Permission to be "tool.execute", got %v`, reloaded.Permission) + } + if reloaded.Target == nil || *reloaded.Target != "shell" { + t.Errorf(`Expected Target to be "shell", got %v`, reloaded.Target) + } + if reloaded.PromptRequest == nil || *reloaded.PromptRequest != "Allow shell to run tests?" { + t.Errorf(`Expected PromptRequest to be "Allow shell to run tests?", got %v`, reloaded.PromptRequest) + } +} + +// TestPermissionRequestToJSON tests that ToJSON produces valid JSON +func TestPermissionRequestToJSON(t *testing.T) { + jsonData := ` +{ + "requestId": "perm_abc123", + "toolCallId": "call_abc123", + "permission": "tool.execute", + "target": "shell", + "promptRequest": "Allow shell to run tests?" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadPermissionRequest(data, ctx) + if err != nil { + t.Fatalf("Failed to load PermissionRequest: %v", err) + } + jsonOutput, err := instance.ToJSON() + if err != nil { + t.Fatalf("Failed to convert to JSON: %v", err) + } + + var parsed map[string]interface{} + if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated JSON: %v", err) + } +} + +// TestPermissionRequestToYAML tests that ToYAML produces valid YAML +func TestPermissionRequestToYAML(t *testing.T) { + jsonData := ` +{ + "requestId": "perm_abc123", + "toolCallId": "call_abc123", + "permission": "tool.execute", + "target": "shell", + "promptRequest": "Allow shell to run tests?" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadPermissionRequest(data, ctx) + if err != nil { + t.Fatalf("Failed to load PermissionRequest: %v", err) + } + yamlOutput, err := instance.ToYAML() + if err != nil { + t.Fatalf("Failed to convert to YAML: %v", err) + } + + var parsed map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated YAML: %v", err) + } +} diff --git a/runtime/go/prompty/model/permission_requested_payload.go b/runtime/go/prompty/model/permission_requested_payload.go index 34c6dbf3..61276ab5 100644 --- a/runtime/go/prompty/model/permission_requested_payload.go +++ b/runtime/go/prompty/model/permission_requested_payload.go @@ -12,9 +12,14 @@ import ( // PermissionRequestedPayload represents Payload for permission request events — a host is asked to approve an action. type PermissionRequestedPayload struct { - Permission string `json:"permission" yaml:"permission"` - Target *string `json:"target,omitempty" yaml:"target,omitempty"` - Details map[string]interface{} `json:"details,omitempty" yaml:"details,omitempty"` + RequestId *string `json:"requestId,omitempty" yaml:"requestId,omitempty"` + ToolCallId *string `json:"toolCallId,omitempty" yaml:"toolCallId,omitempty"` + Permission string `json:"permission" yaml:"permission"` + Target *string `json:"target,omitempty" yaml:"target,omitempty"` + Details map[string]interface{} `json:"details,omitempty" yaml:"details,omitempty"` + PromptRequest *string `json:"promptRequest,omitempty" yaml:"promptRequest,omitempty"` + Policy map[string]interface{} `json:"policy,omitempty" yaml:"policy,omitempty"` + Redaction *RedactionMetadata `json:"redaction,omitempty" yaml:"redaction,omitempty"` } // LoadPermissionRequestedPayload creates a PermissionRequestedPayload from a map[string]interface{} @@ -23,6 +28,14 @@ func LoadPermissionRequestedPayload(data interface{}, ctx *LoadContext) (Permiss // Load from map if m, ok := data.(map[string]interface{}); ok { + if val, ok := m["requestId"]; ok && val != nil { + v := string(val.(string)) + result.RequestId = &v + } + if val, ok := m["toolCallId"]; ok && val != nil { + v := string(val.(string)) + result.ToolCallId = &v + } if val, ok := m["permission"]; ok && val != nil { result.Permission = string(val.(string)) } @@ -35,6 +48,21 @@ func LoadPermissionRequestedPayload(data interface{}, ctx *LoadContext) (Permiss result.Details = m } } + if val, ok := m["promptRequest"]; ok && val != nil { + v := string(val.(string)) + result.PromptRequest = &v + } + if val, ok := m["policy"]; ok && val != nil { + if m, ok := val.(map[string]interface{}); ok { + result.Policy = m + } + } + if val, ok := m["redaction"]; ok && val != nil { + if m, ok := val.(map[string]interface{}); ok { + loaded, _ := LoadRedactionMetadata(m, ctx) + result.Redaction = &loaded + } + } } return result, nil @@ -43,6 +71,12 @@ func LoadPermissionRequestedPayload(data interface{}, ctx *LoadContext) (Permiss // Save serializes PermissionRequestedPayload to map[string]interface{} func (obj *PermissionRequestedPayload) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) + if obj.RequestId != nil { + result["requestId"] = *obj.RequestId + } + if obj.ToolCallId != nil { + result["toolCallId"] = *obj.ToolCallId + } result["permission"] = obj.Permission if obj.Target != nil { result["target"] = *obj.Target @@ -50,6 +84,15 @@ func (obj *PermissionRequestedPayload) Save(ctx *SaveContext) map[string]interfa if obj.Details != nil { result["details"] = obj.Details } + if obj.PromptRequest != nil { + result["promptRequest"] = *obj.PromptRequest + } + if obj.Policy != nil { + result["policy"] = obj.Policy + } + if obj.Redaction != nil { + result["redaction"] = obj.Redaction.Save(ctx) + } return result } diff --git a/runtime/go/prompty/model/permission_requested_payload_test.go b/runtime/go/prompty/model/permission_requested_payload_test.go index 78be5e99..2e440c5e 100644 --- a/runtime/go/prompty/model/permission_requested_payload_test.go +++ b/runtime/go/prompty/model/permission_requested_payload_test.go @@ -15,8 +15,11 @@ import ( func TestPermissionRequestedPayloadLoadJSON(t *testing.T) { jsonData := ` { + "requestId": "perm_abc123", + "toolCallId": "call_abc123", "permission": "tool.execute", - "target": "shell" + "target": "shell", + "promptRequest": "Allow shell to run tests?" } ` var data map[string]interface{} @@ -29,19 +32,31 @@ func TestPermissionRequestedPayloadLoadJSON(t *testing.T) { if err != nil { t.Fatalf("Failed to load PermissionRequestedPayload: %v", err) } + if instance.RequestId == nil || *instance.RequestId != "perm_abc123" { + t.Errorf(`Expected RequestId to be "perm_abc123", got %v`, instance.RequestId) + } + if instance.ToolCallId == nil || *instance.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, instance.ToolCallId) + } if instance.Permission != "tool.execute" { t.Errorf(`Expected Permission to be "tool.execute", got %v`, instance.Permission) } if instance.Target == nil || *instance.Target != "shell" { t.Errorf(`Expected Target to be "shell", got %v`, instance.Target) } + if instance.PromptRequest == nil || *instance.PromptRequest != "Allow shell to run tests?" { + t.Errorf(`Expected PromptRequest to be "Allow shell to run tests?", got %v`, instance.PromptRequest) + } } // TestPermissionRequestedPayloadLoadYAML tests loading PermissionRequestedPayload from YAML func TestPermissionRequestedPayloadLoadYAML(t *testing.T) { yamlData := ` +requestId: perm_abc123 +toolCallId: call_abc123 permission: tool.execute target: shell +promptRequest: Allow shell to run tests? ` var data map[string]interface{} @@ -54,20 +69,32 @@ target: shell if err != nil { t.Fatalf("Failed to load PermissionRequestedPayload: %v", err) } + if instance.RequestId == nil || *instance.RequestId != "perm_abc123" { + t.Errorf(`Expected RequestId to be "perm_abc123", got %v`, instance.RequestId) + } + if instance.ToolCallId == nil || *instance.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, instance.ToolCallId) + } if instance.Permission != "tool.execute" { t.Errorf(`Expected Permission to be "tool.execute", got %v`, instance.Permission) } if instance.Target == nil || *instance.Target != "shell" { t.Errorf(`Expected Target to be "shell", got %v`, instance.Target) } + if instance.PromptRequest == nil || *instance.PromptRequest != "Allow shell to run tests?" { + t.Errorf(`Expected PromptRequest to be "Allow shell to run tests?", got %v`, instance.PromptRequest) + } } // TestPermissionRequestedPayloadRoundtrip tests load -> save -> load produces equivalent data func TestPermissionRequestedPayloadRoundtrip(t *testing.T) { jsonData := ` { + "requestId": "perm_abc123", + "toolCallId": "call_abc123", "permission": "tool.execute", - "target": "shell" + "target": "shell", + "promptRequest": "Allow shell to run tests?" } ` var data map[string]interface{} @@ -87,20 +114,32 @@ func TestPermissionRequestedPayloadRoundtrip(t *testing.T) { if err != nil { t.Fatalf("Failed to reload PermissionRequestedPayload: %v", err) } + if reloaded.RequestId == nil || *reloaded.RequestId != "perm_abc123" { + t.Errorf(`Expected RequestId to be "perm_abc123", got %v`, reloaded.RequestId) + } + if reloaded.ToolCallId == nil || *reloaded.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, reloaded.ToolCallId) + } if reloaded.Permission != "tool.execute" { t.Errorf(`Expected Permission to be "tool.execute", got %v`, reloaded.Permission) } if reloaded.Target == nil || *reloaded.Target != "shell" { t.Errorf(`Expected Target to be "shell", got %v`, reloaded.Target) } + if reloaded.PromptRequest == nil || *reloaded.PromptRequest != "Allow shell to run tests?" { + t.Errorf(`Expected PromptRequest to be "Allow shell to run tests?", got %v`, reloaded.PromptRequest) + } } // TestPermissionRequestedPayloadToJSON tests that ToJSON produces valid JSON func TestPermissionRequestedPayloadToJSON(t *testing.T) { jsonData := ` { + "requestId": "perm_abc123", + "toolCallId": "call_abc123", "permission": "tool.execute", - "target": "shell" + "target": "shell", + "promptRequest": "Allow shell to run tests?" } ` var data map[string]interface{} @@ -128,8 +167,11 @@ func TestPermissionRequestedPayloadToJSON(t *testing.T) { func TestPermissionRequestedPayloadToYAML(t *testing.T) { jsonData := ` { + "requestId": "perm_abc123", + "toolCallId": "call_abc123", "permission": "tool.execute", - "target": "shell" + "target": "shell", + "promptRequest": "Allow shell to run tests?" } ` var data map[string]interface{} diff --git a/runtime/go/prompty/model/permission_resolver.go b/runtime/go/prompty/model/permission_resolver.go new file mode 100644 index 00000000..1ea77c71 --- /dev/null +++ b/runtime/go/prompty/model/permission_resolver.go @@ -0,0 +1,11 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: pipeline + +package prompty + +// PermissionResolver represents Resolves host permission requests for potentially sensitive actions. + +type PermissionResolver interface { + // Request — Resolve a host permission request + Request(request PermissionRequest) (PermissionDecision, error) +} diff --git a/runtime/go/prompty/model/redacted_field.go b/runtime/go/prompty/model/redacted_field.go new file mode 100644 index 00000000..41534104 --- /dev/null +++ b/runtime/go/prompty/model/redacted_field.go @@ -0,0 +1,104 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: events + +package prompty + +import ( + "encoding/json" + + "gopkg.in/yaml.v3" +) + +// RedactionMode represents the allowed values for RedactionMode. +type RedactionMode string + +const ( + RedactionModeNone RedactionMode = "none" + RedactionModeRedacted RedactionMode = "redacted" + RedactionModeHashed RedactionMode = "hashed" + RedactionModeSummary RedactionMode = "summary" + RedactionModeReference RedactionMode = "reference" +) + +// RedactedField represents Redaction handling for one JSON-shaped field path. + +type RedactedField struct { + Path string `json:"path" yaml:"path"` + Mode RedactionMode `json:"mode" yaml:"mode"` + Reason *string `json:"reason,omitempty" yaml:"reason,omitempty"` +} + +// LoadRedactedField creates a RedactedField from a map[string]interface{} +func LoadRedactedField(data interface{}, ctx *LoadContext) (RedactedField, error) { + result := RedactedField{} + + // Load from map + if m, ok := data.(map[string]interface{}); ok { + if val, ok := m["path"]; ok && val != nil { + result.Path = string(val.(string)) + } + if val, ok := m["mode"]; ok && val != nil { + result.Mode = RedactionMode(val.(string)) + } + if val, ok := m["reason"]; ok && val != nil { + v := string(val.(string)) + result.Reason = &v + } + } + + return result, nil +} + +// Save serializes RedactedField to map[string]interface{} +func (obj *RedactedField) Save(ctx *SaveContext) map[string]interface{} { + result := make(map[string]interface{}) + result["path"] = obj.Path + result["mode"] = string(obj.Mode) + if obj.Reason != nil { + result["reason"] = *obj.Reason + } + + return result +} + +// ToJSON serializes RedactedField to JSON string +func (obj *RedactedField) ToJSON() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := json.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// ToYAML serializes RedactedField to YAML string +func (obj *RedactedField) ToYAML() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := yaml.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// FromJSON creates RedactedField from JSON string +func RedactedFieldFromJSON(jsonStr string) (RedactedField, error) { + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { + return RedactedField{}, err + } + ctx := NewLoadContext() + return LoadRedactedField(data, ctx) +} + +// FromYAML creates RedactedField from YAML string +func RedactedFieldFromYAML(yamlStr string) (RedactedField, error) { + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlStr), &data); err != nil { + return RedactedField{}, err + } + ctx := NewLoadContext() + return LoadRedactedField(data, ctx) +} diff --git a/runtime/go/prompty/model/redacted_field_test.go b/runtime/go/prompty/model/redacted_field_test.go new file mode 100644 index 00000000..399a44ee --- /dev/null +++ b/runtime/go/prompty/model/redacted_field_test.go @@ -0,0 +1,168 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +package prompty_test + +import ( + "encoding/json" + "testing" + + "gopkg.in/yaml.v3" + + "prompty/model" +) + +// TestRedactedFieldLoadJSON tests loading RedactedField from JSON +func TestRedactedFieldLoadJSON(t *testing.T) { + jsonData := ` +{ + "path": "$.arguments.apiKey", + "mode": "redacted", + "reason": "secret" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadRedactedField(data, ctx) + if err != nil { + t.Fatalf("Failed to load RedactedField: %v", err) + } + if instance.Path != "$.arguments.apiKey" { + t.Errorf(`Expected Path to be "$.arguments.apiKey", got %v`, instance.Path) + } + if instance.Mode != "redacted" { + t.Errorf(`Expected Mode to be "redacted", got %v`, instance.Mode) + } + if instance.Reason == nil || *instance.Reason != "secret" { + t.Errorf(`Expected Reason to be "secret", got %v`, instance.Reason) + } +} + +// TestRedactedFieldLoadYAML tests loading RedactedField from YAML +func TestRedactedFieldLoadYAML(t *testing.T) { + yamlData := ` +path: $.arguments.apiKey +mode: redacted +reason: secret + +` + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlData), &data); err != nil { + t.Fatalf("Failed to parse YAML: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadRedactedField(data, ctx) + if err != nil { + t.Fatalf("Failed to load RedactedField: %v", err) + } + if instance.Path != "$.arguments.apiKey" { + t.Errorf(`Expected Path to be "$.arguments.apiKey", got %v`, instance.Path) + } + if instance.Mode != "redacted" { + t.Errorf(`Expected Mode to be "redacted", got %v`, instance.Mode) + } + if instance.Reason == nil || *instance.Reason != "secret" { + t.Errorf(`Expected Reason to be "secret", got %v`, instance.Reason) + } +} + +// TestRedactedFieldRoundtrip tests load -> save -> load produces equivalent data +func TestRedactedFieldRoundtrip(t *testing.T) { + jsonData := ` +{ + "path": "$.arguments.apiKey", + "mode": "redacted", + "reason": "secret" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + loadCtx := prompty.NewLoadContext() + instance, err := prompty.LoadRedactedField(data, loadCtx) + if err != nil { + t.Fatalf("Failed to load RedactedField: %v", err) + } + saveCtx := prompty.NewSaveContext() + savedData := instance.Save(saveCtx) + + reloaded, err := prompty.LoadRedactedField(savedData, loadCtx) + if err != nil { + t.Fatalf("Failed to reload RedactedField: %v", err) + } + if reloaded.Path != "$.arguments.apiKey" { + t.Errorf(`Expected Path to be "$.arguments.apiKey", got %v`, reloaded.Path) + } + if reloaded.Mode != "redacted" { + t.Errorf(`Expected Mode to be "redacted", got %v`, reloaded.Mode) + } + if reloaded.Reason == nil || *reloaded.Reason != "secret" { + t.Errorf(`Expected Reason to be "secret", got %v`, reloaded.Reason) + } +} + +// TestRedactedFieldToJSON tests that ToJSON produces valid JSON +func TestRedactedFieldToJSON(t *testing.T) { + jsonData := ` +{ + "path": "$.arguments.apiKey", + "mode": "redacted", + "reason": "secret" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadRedactedField(data, ctx) + if err != nil { + t.Fatalf("Failed to load RedactedField: %v", err) + } + jsonOutput, err := instance.ToJSON() + if err != nil { + t.Fatalf("Failed to convert to JSON: %v", err) + } + + var parsed map[string]interface{} + if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated JSON: %v", err) + } +} + +// TestRedactedFieldToYAML tests that ToYAML produces valid YAML +func TestRedactedFieldToYAML(t *testing.T) { + jsonData := ` +{ + "path": "$.arguments.apiKey", + "mode": "redacted", + "reason": "secret" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadRedactedField(data, ctx) + if err != nil { + t.Fatalf("Failed to load RedactedField: %v", err) + } + yamlOutput, err := instance.ToYAML() + if err != nil { + t.Fatalf("Failed to convert to YAML: %v", err) + } + + var parsed map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated YAML: %v", err) + } +} diff --git a/runtime/go/prompty/model/redaction_metadata.go b/runtime/go/prompty/model/redaction_metadata.go new file mode 100644 index 00000000..dad963c2 --- /dev/null +++ b/runtime/go/prompty/model/redaction_metadata.go @@ -0,0 +1,110 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: events + +package prompty + +import ( + "encoding/json" + + "gopkg.in/yaml.v3" +) + +// RedactionMetadata represents Metadata describing whether and how a payload was sanitized. + +type RedactionMetadata struct { + Sanitized *bool `json:"sanitized,omitempty" yaml:"sanitized,omitempty"` + Fields []RedactedField `json:"fields,omitempty" yaml:"fields,omitempty"` + Policy *string `json:"policy,omitempty" yaml:"policy,omitempty"` +} + +// LoadRedactionMetadata creates a RedactionMetadata from a map[string]interface{} +func LoadRedactionMetadata(data interface{}, ctx *LoadContext) (RedactionMetadata, error) { + result := RedactionMetadata{} + + // Load from map + if m, ok := data.(map[string]interface{}); ok { + if val, ok := m["sanitized"]; ok && val != nil { + v := val.(bool) + result.Sanitized = &v + } + if val, ok := m["fields"]; ok && val != nil { + if arr, ok := val.([]interface{}); ok { + result.Fields = make([]RedactedField, len(arr)) + for i, v := range arr { + if item, ok := v.(map[string]interface{}); ok { + loaded, _ := LoadRedactedField(item, ctx) + result.Fields[i] = loaded + } + } + } + } + if val, ok := m["policy"]; ok && val != nil { + v := string(val.(string)) + result.Policy = &v + } + } + + return result, nil +} + +// Save serializes RedactionMetadata to map[string]interface{} +func (obj *RedactionMetadata) Save(ctx *SaveContext) map[string]interface{} { + result := make(map[string]interface{}) + if obj.Sanitized != nil { + result["sanitized"] = *obj.Sanitized + } + if obj.Fields != nil { + arr := make([]interface{}, len(obj.Fields)) + for i, item := range obj.Fields { + arr[i] = item.Save(ctx) + } + result["fields"] = arr + } + if obj.Policy != nil { + result["policy"] = *obj.Policy + } + + return result +} + +// ToJSON serializes RedactionMetadata to JSON string +func (obj *RedactionMetadata) ToJSON() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := json.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// ToYAML serializes RedactionMetadata to YAML string +func (obj *RedactionMetadata) ToYAML() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := yaml.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// FromJSON creates RedactionMetadata from JSON string +func RedactionMetadataFromJSON(jsonStr string) (RedactionMetadata, error) { + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { + return RedactionMetadata{}, err + } + ctx := NewLoadContext() + return LoadRedactionMetadata(data, ctx) +} + +// FromYAML creates RedactionMetadata from YAML string +func RedactionMetadataFromYAML(yamlStr string) (RedactionMetadata, error) { + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlStr), &data); err != nil { + return RedactionMetadata{}, err + } + ctx := NewLoadContext() + return LoadRedactionMetadata(data, ctx) +} diff --git a/runtime/go/prompty/model/redaction_metadata_test.go b/runtime/go/prompty/model/redaction_metadata_test.go new file mode 100644 index 00000000..35bc3e6f --- /dev/null +++ b/runtime/go/prompty/model/redaction_metadata_test.go @@ -0,0 +1,154 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +package prompty_test + +import ( + "encoding/json" + "testing" + + "gopkg.in/yaml.v3" + + "prompty/model" +) + +// TestRedactionMetadataLoadJSON tests loading RedactionMetadata from JSON +func TestRedactionMetadataLoadJSON(t *testing.T) { + jsonData := ` +{ + "sanitized": true, + "policy": "default-v1" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadRedactionMetadata(data, ctx) + if err != nil { + t.Fatalf("Failed to load RedactionMetadata: %v", err) + } + if instance.Sanitized == nil || *instance.Sanitized != true { + t.Errorf(`Expected Sanitized to be true, got %v`, instance.Sanitized) + } + if instance.Policy == nil || *instance.Policy != "default-v1" { + t.Errorf(`Expected Policy to be "default-v1", got %v`, instance.Policy) + } +} + +// TestRedactionMetadataLoadYAML tests loading RedactionMetadata from YAML +func TestRedactionMetadataLoadYAML(t *testing.T) { + yamlData := ` +sanitized: true +policy: default-v1 + +` + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlData), &data); err != nil { + t.Fatalf("Failed to parse YAML: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadRedactionMetadata(data, ctx) + if err != nil { + t.Fatalf("Failed to load RedactionMetadata: %v", err) + } + if instance.Sanitized == nil || *instance.Sanitized != true { + t.Errorf(`Expected Sanitized to be true, got %v`, instance.Sanitized) + } + if instance.Policy == nil || *instance.Policy != "default-v1" { + t.Errorf(`Expected Policy to be "default-v1", got %v`, instance.Policy) + } +} + +// TestRedactionMetadataRoundtrip tests load -> save -> load produces equivalent data +func TestRedactionMetadataRoundtrip(t *testing.T) { + jsonData := ` +{ + "sanitized": true, + "policy": "default-v1" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + loadCtx := prompty.NewLoadContext() + instance, err := prompty.LoadRedactionMetadata(data, loadCtx) + if err != nil { + t.Fatalf("Failed to load RedactionMetadata: %v", err) + } + saveCtx := prompty.NewSaveContext() + savedData := instance.Save(saveCtx) + + reloaded, err := prompty.LoadRedactionMetadata(savedData, loadCtx) + if err != nil { + t.Fatalf("Failed to reload RedactionMetadata: %v", err) + } + if reloaded.Sanitized == nil || *reloaded.Sanitized != true { + t.Errorf(`Expected Sanitized to be true, got %v`, reloaded.Sanitized) + } + if reloaded.Policy == nil || *reloaded.Policy != "default-v1" { + t.Errorf(`Expected Policy to be "default-v1", got %v`, reloaded.Policy) + } +} + +// TestRedactionMetadataToJSON tests that ToJSON produces valid JSON +func TestRedactionMetadataToJSON(t *testing.T) { + jsonData := ` +{ + "sanitized": true, + "policy": "default-v1" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadRedactionMetadata(data, ctx) + if err != nil { + t.Fatalf("Failed to load RedactionMetadata: %v", err) + } + jsonOutput, err := instance.ToJSON() + if err != nil { + t.Fatalf("Failed to convert to JSON: %v", err) + } + + var parsed map[string]interface{} + if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated JSON: %v", err) + } +} + +// TestRedactionMetadataToYAML tests that ToYAML produces valid YAML +func TestRedactionMetadataToYAML(t *testing.T) { + jsonData := ` +{ + "sanitized": true, + "policy": "default-v1" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadRedactionMetadata(data, ctx) + if err != nil { + t.Fatalf("Failed to load RedactionMetadata: %v", err) + } + yamlOutput, err := instance.ToYAML() + if err != nil { + t.Fatalf("Failed to convert to YAML: %v", err) + } + + var parsed map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated YAML: %v", err) + } +} diff --git a/runtime/go/prompty/model/session_end_payload.go b/runtime/go/prompty/model/session_end_payload.go new file mode 100644 index 00000000..0eb61674 --- /dev/null +++ b/runtime/go/prompty/model/session_end_payload.go @@ -0,0 +1,129 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: events + +package prompty + +import ( + "encoding/json" + + "gopkg.in/yaml.v3" +) + +// SessionEndStatus represents the allowed values for SessionEndStatus. +type SessionEndStatus string + +const ( + SessionEndStatusSuccess SessionEndStatus = "success" + SessionEndStatusError SessionEndStatus = "error" + SessionEndStatusCancelled SessionEndStatus = "cancelled" + SessionEndStatusInterrupted SessionEndStatus = "interrupted" +) + +// SessionEndPayload represents Payload for "session_end" events. + +type SessionEndPayload struct { + SessionId *string `json:"sessionId,omitempty" yaml:"sessionId,omitempty"` + Status *SessionEndStatus `json:"status,omitempty" yaml:"status,omitempty"` + Reason *string `json:"reason,omitempty" yaml:"reason,omitempty"` + DurationMs *float64 `json:"durationMs,omitempty" yaml:"durationMs,omitempty"` +} + +// LoadSessionEndPayload creates a SessionEndPayload from a map[string]interface{} +func LoadSessionEndPayload(data interface{}, ctx *LoadContext) (SessionEndPayload, error) { + result := SessionEndPayload{} + + // Load from map + if m, ok := data.(map[string]interface{}); ok { + if val, ok := m["sessionId"]; ok && val != nil { + v := string(val.(string)) + result.SessionId = &v + } + if val, ok := m["status"]; ok && val != nil { + v := SessionEndStatus(val.(string)) + result.Status = &v + } + if val, ok := m["reason"]; ok && val != nil { + v := string(val.(string)) + result.Reason = &v + } + if val, ok := m["durationMs"]; ok && val != nil { // Handle various numeric types from JSON/YAML/roundtrip + var v float64 + switch n := val.(type) { + case int: + v = float64(n) + case int32: + v = float64(n) + case int64: + v = float64(n) + case float32: + v = float64(n) + case float64: + v = n + } + result.DurationMs = &v + } + } + + return result, nil +} + +// Save serializes SessionEndPayload to map[string]interface{} +func (obj *SessionEndPayload) Save(ctx *SaveContext) map[string]interface{} { + result := make(map[string]interface{}) + if obj.SessionId != nil { + result["sessionId"] = *obj.SessionId + } + if obj.Status != nil { + result["status"] = string(*obj.Status) + } + if obj.Reason != nil { + result["reason"] = *obj.Reason + } + if obj.DurationMs != nil { + result["durationMs"] = *obj.DurationMs + } + + return result +} + +// ToJSON serializes SessionEndPayload to JSON string +func (obj *SessionEndPayload) ToJSON() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := json.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// ToYAML serializes SessionEndPayload to YAML string +func (obj *SessionEndPayload) ToYAML() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := yaml.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// FromJSON creates SessionEndPayload from JSON string +func SessionEndPayloadFromJSON(jsonStr string) (SessionEndPayload, error) { + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { + return SessionEndPayload{}, err + } + ctx := NewLoadContext() + return LoadSessionEndPayload(data, ctx) +} + +// FromYAML creates SessionEndPayload from YAML string +func SessionEndPayloadFromYAML(yamlStr string) (SessionEndPayload, error) { + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlStr), &data); err != nil { + return SessionEndPayload{}, err + } + ctx := NewLoadContext() + return LoadSessionEndPayload(data, ctx) +} diff --git a/runtime/go/prompty/model/session_end_payload_test.go b/runtime/go/prompty/model/session_end_payload_test.go new file mode 100644 index 00000000..a31a3629 --- /dev/null +++ b/runtime/go/prompty/model/session_end_payload_test.go @@ -0,0 +1,182 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +package prompty_test + +import ( + "encoding/json" + "testing" + + "gopkg.in/yaml.v3" + + "prompty/model" +) + +// TestSessionEndPayloadLoadJSON tests loading SessionEndPayload from JSON +func TestSessionEndPayloadLoadJSON(t *testing.T) { + jsonData := ` +{ + "sessionId": "sess_abc123", + "status": "success", + "reason": "complete", + "durationMs": 12500 +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionEndPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load SessionEndPayload: %v", err) + } + if instance.SessionId == nil || *instance.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, instance.SessionId) + } + if instance.Status == nil || *instance.Status != "success" { + t.Errorf(`Expected Status to be "success", got %v`, instance.Status) + } + if instance.Reason == nil || *instance.Reason != "complete" { + t.Errorf(`Expected Reason to be "complete", got %v`, instance.Reason) + } + if instance.DurationMs == nil || *instance.DurationMs != 12500 { + t.Errorf(`Expected DurationMs to be 12500, got %v`, instance.DurationMs) + } +} + +// TestSessionEndPayloadLoadYAML tests loading SessionEndPayload from YAML +func TestSessionEndPayloadLoadYAML(t *testing.T) { + yamlData := ` +sessionId: sess_abc123 +status: success +reason: complete +durationMs: 12500 + +` + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlData), &data); err != nil { + t.Fatalf("Failed to parse YAML: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionEndPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load SessionEndPayload: %v", err) + } + if instance.SessionId == nil || *instance.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, instance.SessionId) + } + if instance.Status == nil || *instance.Status != "success" { + t.Errorf(`Expected Status to be "success", got %v`, instance.Status) + } + if instance.Reason == nil || *instance.Reason != "complete" { + t.Errorf(`Expected Reason to be "complete", got %v`, instance.Reason) + } + if instance.DurationMs == nil || *instance.DurationMs != 12500 { + t.Errorf(`Expected DurationMs to be 12500, got %v`, instance.DurationMs) + } +} + +// TestSessionEndPayloadRoundtrip tests load -> save -> load produces equivalent data +func TestSessionEndPayloadRoundtrip(t *testing.T) { + jsonData := ` +{ + "sessionId": "sess_abc123", + "status": "success", + "reason": "complete", + "durationMs": 12500 +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + loadCtx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionEndPayload(data, loadCtx) + if err != nil { + t.Fatalf("Failed to load SessionEndPayload: %v", err) + } + saveCtx := prompty.NewSaveContext() + savedData := instance.Save(saveCtx) + + reloaded, err := prompty.LoadSessionEndPayload(savedData, loadCtx) + if err != nil { + t.Fatalf("Failed to reload SessionEndPayload: %v", err) + } + if reloaded.SessionId == nil || *reloaded.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, reloaded.SessionId) + } + if reloaded.Status == nil || *reloaded.Status != "success" { + t.Errorf(`Expected Status to be "success", got %v`, reloaded.Status) + } + if reloaded.Reason == nil || *reloaded.Reason != "complete" { + t.Errorf(`Expected Reason to be "complete", got %v`, reloaded.Reason) + } + if reloaded.DurationMs == nil || *reloaded.DurationMs != 12500 { + t.Errorf(`Expected DurationMs to be 12500, got %v`, reloaded.DurationMs) + } +} + +// TestSessionEndPayloadToJSON tests that ToJSON produces valid JSON +func TestSessionEndPayloadToJSON(t *testing.T) { + jsonData := ` +{ + "sessionId": "sess_abc123", + "status": "success", + "reason": "complete", + "durationMs": 12500 +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionEndPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load SessionEndPayload: %v", err) + } + jsonOutput, err := instance.ToJSON() + if err != nil { + t.Fatalf("Failed to convert to JSON: %v", err) + } + + var parsed map[string]interface{} + if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated JSON: %v", err) + } +} + +// TestSessionEndPayloadToYAML tests that ToYAML produces valid YAML +func TestSessionEndPayloadToYAML(t *testing.T) { + jsonData := ` +{ + "sessionId": "sess_abc123", + "status": "success", + "reason": "complete", + "durationMs": 12500 +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionEndPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load SessionEndPayload: %v", err) + } + yamlOutput, err := instance.ToYAML() + if err != nil { + t.Fatalf("Failed to convert to YAML: %v", err) + } + + var parsed map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated YAML: %v", err) + } +} diff --git a/runtime/go/prompty/model/session_event.go b/runtime/go/prompty/model/session_event.go new file mode 100644 index 00000000..63fb67f5 --- /dev/null +++ b/runtime/go/prompty/model/session_event.go @@ -0,0 +1,152 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: events + +package prompty + +import ( + "encoding/json" + + "gopkg.in/yaml.v3" +) + +// SessionEventType represents the allowed values for SessionEventType. +type SessionEventType string + +const ( + SessionEventTypeSessionStart SessionEventType = "session_start" + SessionEventTypeSessionEnd SessionEventType = "session_end" + SessionEventTypeSessionWarning SessionEventType = "session_warning" + SessionEventTypeSessionHookStart SessionEventType = "session_hook_start" + SessionEventTypeSessionHookEnd SessionEventType = "session_hook_end" + SessionEventTypeCheckpointCreated SessionEventType = "checkpoint_created" + SessionEventTypeTrajectoryEvent SessionEventType = "trajectory_event" +) + +// SessionEvent represents A canonical event envelope emitted by an outer harness session. + +type SessionEvent struct { + Id string `json:"id" yaml:"id"` + Type SessionEventType `json:"type" yaml:"type"` + Timestamp string `json:"timestamp" yaml:"timestamp"` + SessionId *string `json:"sessionId,omitempty" yaml:"sessionId,omitempty"` + TurnId *string `json:"turnId,omitempty" yaml:"turnId,omitempty"` + ParentId *string `json:"parentId,omitempty" yaml:"parentId,omitempty"` + SpanId *string `json:"spanId,omitempty" yaml:"spanId,omitempty"` + Payload map[string]interface{} `json:"payload" yaml:"payload"` + Redaction *RedactionMetadata `json:"redaction,omitempty" yaml:"redaction,omitempty"` +} + +// LoadSessionEvent creates a SessionEvent from a map[string]interface{} +func LoadSessionEvent(data interface{}, ctx *LoadContext) (SessionEvent, error) { + result := SessionEvent{} + + // Load from map + if m, ok := data.(map[string]interface{}); ok { + if val, ok := m["id"]; ok && val != nil { + result.Id = string(val.(string)) + } + if val, ok := m["type"]; ok && val != nil { + result.Type = SessionEventType(val.(string)) + } + if val, ok := m["timestamp"]; ok && val != nil { + result.Timestamp = string(val.(string)) + } + if val, ok := m["sessionId"]; ok && val != nil { + v := string(val.(string)) + result.SessionId = &v + } + if val, ok := m["turnId"]; ok && val != nil { + v := string(val.(string)) + result.TurnId = &v + } + if val, ok := m["parentId"]; ok && val != nil { + v := string(val.(string)) + result.ParentId = &v + } + if val, ok := m["spanId"]; ok && val != nil { + v := string(val.(string)) + result.SpanId = &v + } + if val, ok := m["payload"]; ok && val != nil { + if m, ok := val.(map[string]interface{}); ok { + result.Payload = m + } + } + if val, ok := m["redaction"]; ok && val != nil { + if m, ok := val.(map[string]interface{}); ok { + loaded, _ := LoadRedactionMetadata(m, ctx) + result.Redaction = &loaded + } + } + } + + return result, nil +} + +// Save serializes SessionEvent to map[string]interface{} +func (obj *SessionEvent) Save(ctx *SaveContext) map[string]interface{} { + result := make(map[string]interface{}) + result["id"] = obj.Id + result["type"] = string(obj.Type) + result["timestamp"] = obj.Timestamp + if obj.SessionId != nil { + result["sessionId"] = *obj.SessionId + } + if obj.TurnId != nil { + result["turnId"] = *obj.TurnId + } + if obj.ParentId != nil { + result["parentId"] = *obj.ParentId + } + if obj.SpanId != nil { + result["spanId"] = *obj.SpanId + } + result["payload"] = obj.Payload + if obj.Redaction != nil { + result["redaction"] = obj.Redaction.Save(ctx) + } + + return result +} + +// ToJSON serializes SessionEvent to JSON string +func (obj *SessionEvent) ToJSON() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := json.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// ToYAML serializes SessionEvent to YAML string +func (obj *SessionEvent) ToYAML() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := yaml.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// FromJSON creates SessionEvent from JSON string +func SessionEventFromJSON(jsonStr string) (SessionEvent, error) { + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { + return SessionEvent{}, err + } + ctx := NewLoadContext() + return LoadSessionEvent(data, ctx) +} + +// FromYAML creates SessionEvent from YAML string +func SessionEventFromYAML(yamlStr string) (SessionEvent, error) { + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlStr), &data); err != nil { + return SessionEvent{}, err + } + ctx := NewLoadContext() + return LoadSessionEvent(data, ctx) +} diff --git a/runtime/go/prompty/model/session_event_test.go b/runtime/go/prompty/model/session_event_test.go new file mode 100644 index 00000000..af9f2d90 --- /dev/null +++ b/runtime/go/prompty/model/session_event_test.go @@ -0,0 +1,210 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +package prompty_test + +import ( + "encoding/json" + "testing" + + "gopkg.in/yaml.v3" + + "prompty/model" +) + +// TestSessionEventLoadJSON tests loading SessionEvent from JSON +func TestSessionEventLoadJSON(t *testing.T) { + jsonData := ` +{ + "id": "evt_abc123", + "timestamp": "2026-06-09T20:00:00Z", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "parentId": "evt_parent", + "spanId": "span_hook_001" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionEvent(data, ctx) + if err != nil { + t.Fatalf("Failed to load SessionEvent: %v", err) + } + if instance.Id != "evt_abc123" { + t.Errorf(`Expected Id to be "evt_abc123", got %v`, instance.Id) + } + if instance.Timestamp != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected Timestamp to be "2026-06-09T20:00:00Z", got %v`, instance.Timestamp) + } + if instance.SessionId == nil || *instance.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, instance.SessionId) + } + if instance.TurnId == nil || *instance.TurnId != "turn_001" { + t.Errorf(`Expected TurnId to be "turn_001", got %v`, instance.TurnId) + } + if instance.ParentId == nil || *instance.ParentId != "evt_parent" { + t.Errorf(`Expected ParentId to be "evt_parent", got %v`, instance.ParentId) + } + if instance.SpanId == nil || *instance.SpanId != "span_hook_001" { + t.Errorf(`Expected SpanId to be "span_hook_001", got %v`, instance.SpanId) + } +} + +// TestSessionEventLoadYAML tests loading SessionEvent from YAML +func TestSessionEventLoadYAML(t *testing.T) { + yamlData := ` +id: evt_abc123 +timestamp: "2026-06-09T20:00:00Z" +sessionId: sess_abc123 +turnId: turn_001 +parentId: evt_parent +spanId: span_hook_001 + +` + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlData), &data); err != nil { + t.Fatalf("Failed to parse YAML: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionEvent(data, ctx) + if err != nil { + t.Fatalf("Failed to load SessionEvent: %v", err) + } + if instance.Id != "evt_abc123" { + t.Errorf(`Expected Id to be "evt_abc123", got %v`, instance.Id) + } + if instance.Timestamp != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected Timestamp to be "2026-06-09T20:00:00Z", got %v`, instance.Timestamp) + } + if instance.SessionId == nil || *instance.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, instance.SessionId) + } + if instance.TurnId == nil || *instance.TurnId != "turn_001" { + t.Errorf(`Expected TurnId to be "turn_001", got %v`, instance.TurnId) + } + if instance.ParentId == nil || *instance.ParentId != "evt_parent" { + t.Errorf(`Expected ParentId to be "evt_parent", got %v`, instance.ParentId) + } + if instance.SpanId == nil || *instance.SpanId != "span_hook_001" { + t.Errorf(`Expected SpanId to be "span_hook_001", got %v`, instance.SpanId) + } +} + +// TestSessionEventRoundtrip tests load -> save -> load produces equivalent data +func TestSessionEventRoundtrip(t *testing.T) { + jsonData := ` +{ + "id": "evt_abc123", + "timestamp": "2026-06-09T20:00:00Z", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "parentId": "evt_parent", + "spanId": "span_hook_001" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + loadCtx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionEvent(data, loadCtx) + if err != nil { + t.Fatalf("Failed to load SessionEvent: %v", err) + } + saveCtx := prompty.NewSaveContext() + savedData := instance.Save(saveCtx) + + reloaded, err := prompty.LoadSessionEvent(savedData, loadCtx) + if err != nil { + t.Fatalf("Failed to reload SessionEvent: %v", err) + } + if reloaded.Id != "evt_abc123" { + t.Errorf(`Expected Id to be "evt_abc123", got %v`, reloaded.Id) + } + if reloaded.Timestamp != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected Timestamp to be "2026-06-09T20:00:00Z", got %v`, reloaded.Timestamp) + } + if reloaded.SessionId == nil || *reloaded.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, reloaded.SessionId) + } + if reloaded.TurnId == nil || *reloaded.TurnId != "turn_001" { + t.Errorf(`Expected TurnId to be "turn_001", got %v`, reloaded.TurnId) + } + if reloaded.ParentId == nil || *reloaded.ParentId != "evt_parent" { + t.Errorf(`Expected ParentId to be "evt_parent", got %v`, reloaded.ParentId) + } + if reloaded.SpanId == nil || *reloaded.SpanId != "span_hook_001" { + t.Errorf(`Expected SpanId to be "span_hook_001", got %v`, reloaded.SpanId) + } +} + +// TestSessionEventToJSON tests that ToJSON produces valid JSON +func TestSessionEventToJSON(t *testing.T) { + jsonData := ` +{ + "id": "evt_abc123", + "timestamp": "2026-06-09T20:00:00Z", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "parentId": "evt_parent", + "spanId": "span_hook_001" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionEvent(data, ctx) + if err != nil { + t.Fatalf("Failed to load SessionEvent: %v", err) + } + jsonOutput, err := instance.ToJSON() + if err != nil { + t.Fatalf("Failed to convert to JSON: %v", err) + } + + var parsed map[string]interface{} + if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated JSON: %v", err) + } +} + +// TestSessionEventToYAML tests that ToYAML produces valid YAML +func TestSessionEventToYAML(t *testing.T) { + jsonData := ` +{ + "id": "evt_abc123", + "timestamp": "2026-06-09T20:00:00Z", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "parentId": "evt_parent", + "spanId": "span_hook_001" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionEvent(data, ctx) + if err != nil { + t.Fatalf("Failed to load SessionEvent: %v", err) + } + yamlOutput, err := instance.ToYAML() + if err != nil { + t.Fatalf("Failed to convert to YAML: %v", err) + } + + var parsed map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated YAML: %v", err) + } +} diff --git a/runtime/go/prompty/model/session_file_ref.go b/runtime/go/prompty/model/session_file_ref.go new file mode 100644 index 00000000..bee2bde6 --- /dev/null +++ b/runtime/go/prompty/model/session_file_ref.go @@ -0,0 +1,122 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: events + +package prompty + +import ( + "encoding/json" + + "gopkg.in/yaml.v3" +) + +// SessionFileRef represents A file observed or touched by a harness session. + +type SessionFileRef struct { + SessionId *string `json:"sessionId,omitempty" yaml:"sessionId,omitempty"` + Path string `json:"path" yaml:"path"` + ToolName *string `json:"toolName,omitempty" yaml:"toolName,omitempty"` + TurnIndex *int32 `json:"turnIndex,omitempty" yaml:"turnIndex,omitempty"` + FirstSeenAt *string `json:"firstSeenAt,omitempty" yaml:"firstSeenAt,omitempty"` +} + +// LoadSessionFileRef creates a SessionFileRef from a map[string]interface{} +func LoadSessionFileRef(data interface{}, ctx *LoadContext) (SessionFileRef, error) { + result := SessionFileRef{} + + // Load from map + if m, ok := data.(map[string]interface{}); ok { + if val, ok := m["sessionId"]; ok && val != nil { + v := string(val.(string)) + result.SessionId = &v + } + if val, ok := m["path"]; ok && val != nil { + result.Path = string(val.(string)) + } + if val, ok := m["toolName"]; ok && val != nil { + v := string(val.(string)) + result.ToolName = &v + } + if val, ok := m["turnIndex"]; ok && val != nil { // Handle various numeric types from JSON/YAML/roundtrip + var v int32 + switch n := val.(type) { + case int: + v = int32(n) + case int32: + v = int32(n) + case int64: + v = int32(n) + case float64: + v = int32(n) + } + result.TurnIndex = &v + } + if val, ok := m["firstSeenAt"]; ok && val != nil { + v := string(val.(string)) + result.FirstSeenAt = &v + } + } + + return result, nil +} + +// Save serializes SessionFileRef to map[string]interface{} +func (obj *SessionFileRef) Save(ctx *SaveContext) map[string]interface{} { + result := make(map[string]interface{}) + if obj.SessionId != nil { + result["sessionId"] = *obj.SessionId + } + result["path"] = obj.Path + if obj.ToolName != nil { + result["toolName"] = *obj.ToolName + } + if obj.TurnIndex != nil { + result["turnIndex"] = *obj.TurnIndex + } + if obj.FirstSeenAt != nil { + result["firstSeenAt"] = *obj.FirstSeenAt + } + + return result +} + +// ToJSON serializes SessionFileRef to JSON string +func (obj *SessionFileRef) ToJSON() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := json.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// ToYAML serializes SessionFileRef to YAML string +func (obj *SessionFileRef) ToYAML() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := yaml.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// FromJSON creates SessionFileRef from JSON string +func SessionFileRefFromJSON(jsonStr string) (SessionFileRef, error) { + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { + return SessionFileRef{}, err + } + ctx := NewLoadContext() + return LoadSessionFileRef(data, ctx) +} + +// FromYAML creates SessionFileRef from YAML string +func SessionFileRefFromYAML(yamlStr string) (SessionFileRef, error) { + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlStr), &data); err != nil { + return SessionFileRef{}, err + } + ctx := NewLoadContext() + return LoadSessionFileRef(data, ctx) +} diff --git a/runtime/go/prompty/model/session_file_ref_test.go b/runtime/go/prompty/model/session_file_ref_test.go new file mode 100644 index 00000000..82b0f3b0 --- /dev/null +++ b/runtime/go/prompty/model/session_file_ref_test.go @@ -0,0 +1,196 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +package prompty_test + +import ( + "encoding/json" + "testing" + + "gopkg.in/yaml.v3" + + "prompty/model" +) + +// TestSessionFileRefLoadJSON tests loading SessionFileRef from JSON +func TestSessionFileRefLoadJSON(t *testing.T) { + jsonData := ` +{ + "sessionId": "sess_abc123", + "path": "src/index.ts", + "toolName": "view", + "turnIndex": 2, + "firstSeenAt": "2026-06-09T20:00:00Z" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionFileRef(data, ctx) + if err != nil { + t.Fatalf("Failed to load SessionFileRef: %v", err) + } + if instance.SessionId == nil || *instance.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, instance.SessionId) + } + if instance.Path != "src/index.ts" { + t.Errorf(`Expected Path to be "src/index.ts", got %v`, instance.Path) + } + if instance.ToolName == nil || *instance.ToolName != "view" { + t.Errorf(`Expected ToolName to be "view", got %v`, instance.ToolName) + } + if instance.TurnIndex == nil || *instance.TurnIndex != 2 { + t.Errorf(`Expected TurnIndex to be 2, got %v`, instance.TurnIndex) + } + if instance.FirstSeenAt == nil || *instance.FirstSeenAt != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected FirstSeenAt to be "2026-06-09T20:00:00Z", got %v`, instance.FirstSeenAt) + } +} + +// TestSessionFileRefLoadYAML tests loading SessionFileRef from YAML +func TestSessionFileRefLoadYAML(t *testing.T) { + yamlData := ` +sessionId: sess_abc123 +path: src/index.ts +toolName: view +turnIndex: 2 +firstSeenAt: "2026-06-09T20:00:00Z" + +` + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlData), &data); err != nil { + t.Fatalf("Failed to parse YAML: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionFileRef(data, ctx) + if err != nil { + t.Fatalf("Failed to load SessionFileRef: %v", err) + } + if instance.SessionId == nil || *instance.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, instance.SessionId) + } + if instance.Path != "src/index.ts" { + t.Errorf(`Expected Path to be "src/index.ts", got %v`, instance.Path) + } + if instance.ToolName == nil || *instance.ToolName != "view" { + t.Errorf(`Expected ToolName to be "view", got %v`, instance.ToolName) + } + if instance.TurnIndex == nil || *instance.TurnIndex != 2 { + t.Errorf(`Expected TurnIndex to be 2, got %v`, instance.TurnIndex) + } + if instance.FirstSeenAt == nil || *instance.FirstSeenAt != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected FirstSeenAt to be "2026-06-09T20:00:00Z", got %v`, instance.FirstSeenAt) + } +} + +// TestSessionFileRefRoundtrip tests load -> save -> load produces equivalent data +func TestSessionFileRefRoundtrip(t *testing.T) { + jsonData := ` +{ + "sessionId": "sess_abc123", + "path": "src/index.ts", + "toolName": "view", + "turnIndex": 2, + "firstSeenAt": "2026-06-09T20:00:00Z" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + loadCtx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionFileRef(data, loadCtx) + if err != nil { + t.Fatalf("Failed to load SessionFileRef: %v", err) + } + saveCtx := prompty.NewSaveContext() + savedData := instance.Save(saveCtx) + + reloaded, err := prompty.LoadSessionFileRef(savedData, loadCtx) + if err != nil { + t.Fatalf("Failed to reload SessionFileRef: %v", err) + } + if reloaded.SessionId == nil || *reloaded.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, reloaded.SessionId) + } + if reloaded.Path != "src/index.ts" { + t.Errorf(`Expected Path to be "src/index.ts", got %v`, reloaded.Path) + } + if reloaded.ToolName == nil || *reloaded.ToolName != "view" { + t.Errorf(`Expected ToolName to be "view", got %v`, reloaded.ToolName) + } + if reloaded.TurnIndex == nil || *reloaded.TurnIndex != 2 { + t.Errorf(`Expected TurnIndex to be 2, got %v`, reloaded.TurnIndex) + } + if reloaded.FirstSeenAt == nil || *reloaded.FirstSeenAt != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected FirstSeenAt to be "2026-06-09T20:00:00Z", got %v`, reloaded.FirstSeenAt) + } +} + +// TestSessionFileRefToJSON tests that ToJSON produces valid JSON +func TestSessionFileRefToJSON(t *testing.T) { + jsonData := ` +{ + "sessionId": "sess_abc123", + "path": "src/index.ts", + "toolName": "view", + "turnIndex": 2, + "firstSeenAt": "2026-06-09T20:00:00Z" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionFileRef(data, ctx) + if err != nil { + t.Fatalf("Failed to load SessionFileRef: %v", err) + } + jsonOutput, err := instance.ToJSON() + if err != nil { + t.Fatalf("Failed to convert to JSON: %v", err) + } + + var parsed map[string]interface{} + if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated JSON: %v", err) + } +} + +// TestSessionFileRefToYAML tests that ToYAML produces valid YAML +func TestSessionFileRefToYAML(t *testing.T) { + jsonData := ` +{ + "sessionId": "sess_abc123", + "path": "src/index.ts", + "toolName": "view", + "turnIndex": 2, + "firstSeenAt": "2026-06-09T20:00:00Z" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionFileRef(data, ctx) + if err != nil { + t.Fatalf("Failed to load SessionFileRef: %v", err) + } + yamlOutput, err := instance.ToYAML() + if err != nil { + t.Fatalf("Failed to convert to YAML: %v", err) + } + + var parsed map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated YAML: %v", err) + } +} diff --git a/runtime/go/prompty/model/session_ref.go b/runtime/go/prompty/model/session_ref.go new file mode 100644 index 00000000..3d116c82 --- /dev/null +++ b/runtime/go/prompty/model/session_ref.go @@ -0,0 +1,119 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: events + +package prompty + +import ( + "encoding/json" + + "gopkg.in/yaml.v3" +) + +// SessionRef represents A non-file reference observed by a harness session. + +type SessionRef struct { + SessionId *string `json:"sessionId,omitempty" yaml:"sessionId,omitempty"` + RefType string `json:"refType" yaml:"refType"` + RefValue string `json:"refValue" yaml:"refValue"` + TurnIndex *int32 `json:"turnIndex,omitempty" yaml:"turnIndex,omitempty"` + CreatedAt *string `json:"createdAt,omitempty" yaml:"createdAt,omitempty"` +} + +// LoadSessionRef creates a SessionRef from a map[string]interface{} +func LoadSessionRef(data interface{}, ctx *LoadContext) (SessionRef, error) { + result := SessionRef{} + + // Load from map + if m, ok := data.(map[string]interface{}); ok { + if val, ok := m["sessionId"]; ok && val != nil { + v := string(val.(string)) + result.SessionId = &v + } + if val, ok := m["refType"]; ok && val != nil { + result.RefType = string(val.(string)) + } + if val, ok := m["refValue"]; ok && val != nil { + result.RefValue = string(val.(string)) + } + if val, ok := m["turnIndex"]; ok && val != nil { // Handle various numeric types from JSON/YAML/roundtrip + var v int32 + switch n := val.(type) { + case int: + v = int32(n) + case int32: + v = int32(n) + case int64: + v = int32(n) + case float64: + v = int32(n) + } + result.TurnIndex = &v + } + if val, ok := m["createdAt"]; ok && val != nil { + v := string(val.(string)) + result.CreatedAt = &v + } + } + + return result, nil +} + +// Save serializes SessionRef to map[string]interface{} +func (obj *SessionRef) Save(ctx *SaveContext) map[string]interface{} { + result := make(map[string]interface{}) + if obj.SessionId != nil { + result["sessionId"] = *obj.SessionId + } + result["refType"] = obj.RefType + result["refValue"] = obj.RefValue + if obj.TurnIndex != nil { + result["turnIndex"] = *obj.TurnIndex + } + if obj.CreatedAt != nil { + result["createdAt"] = *obj.CreatedAt + } + + return result +} + +// ToJSON serializes SessionRef to JSON string +func (obj *SessionRef) ToJSON() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := json.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// ToYAML serializes SessionRef to YAML string +func (obj *SessionRef) ToYAML() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := yaml.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// FromJSON creates SessionRef from JSON string +func SessionRefFromJSON(jsonStr string) (SessionRef, error) { + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { + return SessionRef{}, err + } + ctx := NewLoadContext() + return LoadSessionRef(data, ctx) +} + +// FromYAML creates SessionRef from YAML string +func SessionRefFromYAML(yamlStr string) (SessionRef, error) { + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlStr), &data); err != nil { + return SessionRef{}, err + } + ctx := NewLoadContext() + return LoadSessionRef(data, ctx) +} diff --git a/runtime/go/prompty/model/session_ref_test.go b/runtime/go/prompty/model/session_ref_test.go new file mode 100644 index 00000000..b9aed1fc --- /dev/null +++ b/runtime/go/prompty/model/session_ref_test.go @@ -0,0 +1,196 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +package prompty_test + +import ( + "encoding/json" + "testing" + + "gopkg.in/yaml.v3" + + "prompty/model" +) + +// TestSessionRefLoadJSON tests loading SessionRef from JSON +func TestSessionRefLoadJSON(t *testing.T) { + jsonData := ` +{ + "sessionId": "sess_abc123", + "refType": "issue", + "refValue": "owner/repo#123", + "turnIndex": 2, + "createdAt": "2026-06-09T20:00:00Z" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionRef(data, ctx) + if err != nil { + t.Fatalf("Failed to load SessionRef: %v", err) + } + if instance.SessionId == nil || *instance.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, instance.SessionId) + } + if instance.RefType != "issue" { + t.Errorf(`Expected RefType to be "issue", got %v`, instance.RefType) + } + if instance.RefValue != "owner/repo#123" { + t.Errorf(`Expected RefValue to be "owner/repo#123", got %v`, instance.RefValue) + } + if instance.TurnIndex == nil || *instance.TurnIndex != 2 { + t.Errorf(`Expected TurnIndex to be 2, got %v`, instance.TurnIndex) + } + if instance.CreatedAt == nil || *instance.CreatedAt != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected CreatedAt to be "2026-06-09T20:00:00Z", got %v`, instance.CreatedAt) + } +} + +// TestSessionRefLoadYAML tests loading SessionRef from YAML +func TestSessionRefLoadYAML(t *testing.T) { + yamlData := ` +sessionId: sess_abc123 +refType: issue +refValue: "owner/repo#123" +turnIndex: 2 +createdAt: "2026-06-09T20:00:00Z" + +` + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlData), &data); err != nil { + t.Fatalf("Failed to parse YAML: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionRef(data, ctx) + if err != nil { + t.Fatalf("Failed to load SessionRef: %v", err) + } + if instance.SessionId == nil || *instance.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, instance.SessionId) + } + if instance.RefType != "issue" { + t.Errorf(`Expected RefType to be "issue", got %v`, instance.RefType) + } + if instance.RefValue != "owner/repo#123" { + t.Errorf(`Expected RefValue to be "owner/repo#123", got %v`, instance.RefValue) + } + if instance.TurnIndex == nil || *instance.TurnIndex != 2 { + t.Errorf(`Expected TurnIndex to be 2, got %v`, instance.TurnIndex) + } + if instance.CreatedAt == nil || *instance.CreatedAt != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected CreatedAt to be "2026-06-09T20:00:00Z", got %v`, instance.CreatedAt) + } +} + +// TestSessionRefRoundtrip tests load -> save -> load produces equivalent data +func TestSessionRefRoundtrip(t *testing.T) { + jsonData := ` +{ + "sessionId": "sess_abc123", + "refType": "issue", + "refValue": "owner/repo#123", + "turnIndex": 2, + "createdAt": "2026-06-09T20:00:00Z" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + loadCtx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionRef(data, loadCtx) + if err != nil { + t.Fatalf("Failed to load SessionRef: %v", err) + } + saveCtx := prompty.NewSaveContext() + savedData := instance.Save(saveCtx) + + reloaded, err := prompty.LoadSessionRef(savedData, loadCtx) + if err != nil { + t.Fatalf("Failed to reload SessionRef: %v", err) + } + if reloaded.SessionId == nil || *reloaded.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, reloaded.SessionId) + } + if reloaded.RefType != "issue" { + t.Errorf(`Expected RefType to be "issue", got %v`, reloaded.RefType) + } + if reloaded.RefValue != "owner/repo#123" { + t.Errorf(`Expected RefValue to be "owner/repo#123", got %v`, reloaded.RefValue) + } + if reloaded.TurnIndex == nil || *reloaded.TurnIndex != 2 { + t.Errorf(`Expected TurnIndex to be 2, got %v`, reloaded.TurnIndex) + } + if reloaded.CreatedAt == nil || *reloaded.CreatedAt != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected CreatedAt to be "2026-06-09T20:00:00Z", got %v`, reloaded.CreatedAt) + } +} + +// TestSessionRefToJSON tests that ToJSON produces valid JSON +func TestSessionRefToJSON(t *testing.T) { + jsonData := ` +{ + "sessionId": "sess_abc123", + "refType": "issue", + "refValue": "owner/repo#123", + "turnIndex": 2, + "createdAt": "2026-06-09T20:00:00Z" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionRef(data, ctx) + if err != nil { + t.Fatalf("Failed to load SessionRef: %v", err) + } + jsonOutput, err := instance.ToJSON() + if err != nil { + t.Fatalf("Failed to convert to JSON: %v", err) + } + + var parsed map[string]interface{} + if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated JSON: %v", err) + } +} + +// TestSessionRefToYAML tests that ToYAML produces valid YAML +func TestSessionRefToYAML(t *testing.T) { + jsonData := ` +{ + "sessionId": "sess_abc123", + "refType": "issue", + "refValue": "owner/repo#123", + "turnIndex": 2, + "createdAt": "2026-06-09T20:00:00Z" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionRef(data, ctx) + if err != nil { + t.Fatalf("Failed to load SessionRef: %v", err) + } + yamlOutput, err := instance.ToYAML() + if err != nil { + t.Fatalf("Failed to convert to YAML: %v", err) + } + + var parsed map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated YAML: %v", err) + } +} diff --git a/runtime/go/prompty/model/session_start_payload.go b/runtime/go/prompty/model/session_start_payload.go new file mode 100644 index 00000000..38c60d7b --- /dev/null +++ b/runtime/go/prompty/model/session_start_payload.go @@ -0,0 +1,156 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: events + +package prompty + +import ( + "encoding/json" + + "gopkg.in/yaml.v3" +) + +// SessionStartPayload represents Payload for "session_start" events. + +type SessionStartPayload struct { + SessionId string `json:"sessionId" yaml:"sessionId"` + Version *int32 `json:"version,omitempty" yaml:"version,omitempty"` + Producer *string `json:"producer,omitempty" yaml:"producer,omitempty"` + Runtime *string `json:"runtime,omitempty" yaml:"runtime,omitempty"` + PromptyVersion *string `json:"promptyVersion,omitempty" yaml:"promptyVersion,omitempty"` + StartTime *string `json:"startTime,omitempty" yaml:"startTime,omitempty"` + SelectedModel *string `json:"selectedModel,omitempty" yaml:"selectedModel,omitempty"` + ReasoningEffort *string `json:"reasoningEffort,omitempty" yaml:"reasoningEffort,omitempty"` + Context *HarnessContext `json:"context,omitempty" yaml:"context,omitempty"` +} + +// LoadSessionStartPayload creates a SessionStartPayload from a map[string]interface{} +func LoadSessionStartPayload(data interface{}, ctx *LoadContext) (SessionStartPayload, error) { + result := SessionStartPayload{} + + // Load from map + if m, ok := data.(map[string]interface{}); ok { + if val, ok := m["sessionId"]; ok && val != nil { + result.SessionId = string(val.(string)) + } + if val, ok := m["version"]; ok && val != nil { // Handle various numeric types from JSON/YAML/roundtrip + var v int32 + switch n := val.(type) { + case int: + v = int32(n) + case int32: + v = int32(n) + case int64: + v = int32(n) + case float64: + v = int32(n) + } + result.Version = &v + } + if val, ok := m["producer"]; ok && val != nil { + v := string(val.(string)) + result.Producer = &v + } + if val, ok := m["runtime"]; ok && val != nil { + v := string(val.(string)) + result.Runtime = &v + } + if val, ok := m["promptyVersion"]; ok && val != nil { + v := string(val.(string)) + result.PromptyVersion = &v + } + if val, ok := m["startTime"]; ok && val != nil { + v := string(val.(string)) + result.StartTime = &v + } + if val, ok := m["selectedModel"]; ok && val != nil { + v := string(val.(string)) + result.SelectedModel = &v + } + if val, ok := m["reasoningEffort"]; ok && val != nil { + v := string(val.(string)) + result.ReasoningEffort = &v + } + if val, ok := m["context"]; ok && val != nil { + if m, ok := val.(map[string]interface{}); ok { + loaded, _ := LoadHarnessContext(m, ctx) + result.Context = &loaded + } + } + } + + return result, nil +} + +// Save serializes SessionStartPayload to map[string]interface{} +func (obj *SessionStartPayload) Save(ctx *SaveContext) map[string]interface{} { + result := make(map[string]interface{}) + result["sessionId"] = obj.SessionId + if obj.Version != nil { + result["version"] = *obj.Version + } + if obj.Producer != nil { + result["producer"] = *obj.Producer + } + if obj.Runtime != nil { + result["runtime"] = *obj.Runtime + } + if obj.PromptyVersion != nil { + result["promptyVersion"] = *obj.PromptyVersion + } + if obj.StartTime != nil { + result["startTime"] = *obj.StartTime + } + if obj.SelectedModel != nil { + result["selectedModel"] = *obj.SelectedModel + } + if obj.ReasoningEffort != nil { + result["reasoningEffort"] = *obj.ReasoningEffort + } + if obj.Context != nil { + result["context"] = obj.Context.Save(ctx) + } + + return result +} + +// ToJSON serializes SessionStartPayload to JSON string +func (obj *SessionStartPayload) ToJSON() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := json.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// ToYAML serializes SessionStartPayload to YAML string +func (obj *SessionStartPayload) ToYAML() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := yaml.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// FromJSON creates SessionStartPayload from JSON string +func SessionStartPayloadFromJSON(jsonStr string) (SessionStartPayload, error) { + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { + return SessionStartPayload{}, err + } + ctx := NewLoadContext() + return LoadSessionStartPayload(data, ctx) +} + +// FromYAML creates SessionStartPayload from YAML string +func SessionStartPayloadFromYAML(yamlStr string) (SessionStartPayload, error) { + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlStr), &data); err != nil { + return SessionStartPayload{}, err + } + ctx := NewLoadContext() + return LoadSessionStartPayload(data, ctx) +} diff --git a/runtime/go/prompty/model/session_start_payload_test.go b/runtime/go/prompty/model/session_start_payload_test.go new file mode 100644 index 00000000..8cea9baa --- /dev/null +++ b/runtime/go/prompty/model/session_start_payload_test.go @@ -0,0 +1,238 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +package prompty_test + +import ( + "encoding/json" + "testing" + + "gopkg.in/yaml.v3" + + "prompty/model" +) + +// TestSessionStartPayloadLoadJSON tests loading SessionStartPayload from JSON +func TestSessionStartPayloadLoadJSON(t *testing.T) { + jsonData := ` +{ + "sessionId": "sess_abc123", + "version": 1, + "producer": "prompty-agent", + "runtime": "typescript", + "promptyVersion": "2.0.0", + "startTime": "2026-06-09T20:00:00Z", + "selectedModel": "gpt-4o-mini", + "reasoningEffort": "medium" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionStartPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load SessionStartPayload: %v", err) + } + if instance.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, instance.SessionId) + } + if instance.Version == nil || *instance.Version != 1 { + t.Errorf(`Expected Version to be 1, got %v`, instance.Version) + } + if instance.Producer == nil || *instance.Producer != "prompty-agent" { + t.Errorf(`Expected Producer to be "prompty-agent", got %v`, instance.Producer) + } + if instance.Runtime == nil || *instance.Runtime != "typescript" { + t.Errorf(`Expected Runtime to be "typescript", got %v`, instance.Runtime) + } + if instance.PromptyVersion == nil || *instance.PromptyVersion != "2.0.0" { + t.Errorf(`Expected PromptyVersion to be "2.0.0", got %v`, instance.PromptyVersion) + } + if instance.StartTime == nil || *instance.StartTime != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected StartTime to be "2026-06-09T20:00:00Z", got %v`, instance.StartTime) + } + if instance.SelectedModel == nil || *instance.SelectedModel != "gpt-4o-mini" { + t.Errorf(`Expected SelectedModel to be "gpt-4o-mini", got %v`, instance.SelectedModel) + } + if instance.ReasoningEffort == nil || *instance.ReasoningEffort != "medium" { + t.Errorf(`Expected ReasoningEffort to be "medium", got %v`, instance.ReasoningEffort) + } +} + +// TestSessionStartPayloadLoadYAML tests loading SessionStartPayload from YAML +func TestSessionStartPayloadLoadYAML(t *testing.T) { + yamlData := ` +sessionId: sess_abc123 +version: 1 +producer: prompty-agent +runtime: typescript +promptyVersion: 2.0.0 +startTime: "2026-06-09T20:00:00Z" +selectedModel: gpt-4o-mini +reasoningEffort: medium + +` + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlData), &data); err != nil { + t.Fatalf("Failed to parse YAML: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionStartPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load SessionStartPayload: %v", err) + } + if instance.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, instance.SessionId) + } + if instance.Version == nil || *instance.Version != 1 { + t.Errorf(`Expected Version to be 1, got %v`, instance.Version) + } + if instance.Producer == nil || *instance.Producer != "prompty-agent" { + t.Errorf(`Expected Producer to be "prompty-agent", got %v`, instance.Producer) + } + if instance.Runtime == nil || *instance.Runtime != "typescript" { + t.Errorf(`Expected Runtime to be "typescript", got %v`, instance.Runtime) + } + if instance.PromptyVersion == nil || *instance.PromptyVersion != "2.0.0" { + t.Errorf(`Expected PromptyVersion to be "2.0.0", got %v`, instance.PromptyVersion) + } + if instance.StartTime == nil || *instance.StartTime != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected StartTime to be "2026-06-09T20:00:00Z", got %v`, instance.StartTime) + } + if instance.SelectedModel == nil || *instance.SelectedModel != "gpt-4o-mini" { + t.Errorf(`Expected SelectedModel to be "gpt-4o-mini", got %v`, instance.SelectedModel) + } + if instance.ReasoningEffort == nil || *instance.ReasoningEffort != "medium" { + t.Errorf(`Expected ReasoningEffort to be "medium", got %v`, instance.ReasoningEffort) + } +} + +// TestSessionStartPayloadRoundtrip tests load -> save -> load produces equivalent data +func TestSessionStartPayloadRoundtrip(t *testing.T) { + jsonData := ` +{ + "sessionId": "sess_abc123", + "version": 1, + "producer": "prompty-agent", + "runtime": "typescript", + "promptyVersion": "2.0.0", + "startTime": "2026-06-09T20:00:00Z", + "selectedModel": "gpt-4o-mini", + "reasoningEffort": "medium" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + loadCtx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionStartPayload(data, loadCtx) + if err != nil { + t.Fatalf("Failed to load SessionStartPayload: %v", err) + } + saveCtx := prompty.NewSaveContext() + savedData := instance.Save(saveCtx) + + reloaded, err := prompty.LoadSessionStartPayload(savedData, loadCtx) + if err != nil { + t.Fatalf("Failed to reload SessionStartPayload: %v", err) + } + if reloaded.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, reloaded.SessionId) + } + if reloaded.Version == nil || *reloaded.Version != 1 { + t.Errorf(`Expected Version to be 1, got %v`, reloaded.Version) + } + if reloaded.Producer == nil || *reloaded.Producer != "prompty-agent" { + t.Errorf(`Expected Producer to be "prompty-agent", got %v`, reloaded.Producer) + } + if reloaded.Runtime == nil || *reloaded.Runtime != "typescript" { + t.Errorf(`Expected Runtime to be "typescript", got %v`, reloaded.Runtime) + } + if reloaded.PromptyVersion == nil || *reloaded.PromptyVersion != "2.0.0" { + t.Errorf(`Expected PromptyVersion to be "2.0.0", got %v`, reloaded.PromptyVersion) + } + if reloaded.StartTime == nil || *reloaded.StartTime != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected StartTime to be "2026-06-09T20:00:00Z", got %v`, reloaded.StartTime) + } + if reloaded.SelectedModel == nil || *reloaded.SelectedModel != "gpt-4o-mini" { + t.Errorf(`Expected SelectedModel to be "gpt-4o-mini", got %v`, reloaded.SelectedModel) + } + if reloaded.ReasoningEffort == nil || *reloaded.ReasoningEffort != "medium" { + t.Errorf(`Expected ReasoningEffort to be "medium", got %v`, reloaded.ReasoningEffort) + } +} + +// TestSessionStartPayloadToJSON tests that ToJSON produces valid JSON +func TestSessionStartPayloadToJSON(t *testing.T) { + jsonData := ` +{ + "sessionId": "sess_abc123", + "version": 1, + "producer": "prompty-agent", + "runtime": "typescript", + "promptyVersion": "2.0.0", + "startTime": "2026-06-09T20:00:00Z", + "selectedModel": "gpt-4o-mini", + "reasoningEffort": "medium" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionStartPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load SessionStartPayload: %v", err) + } + jsonOutput, err := instance.ToJSON() + if err != nil { + t.Fatalf("Failed to convert to JSON: %v", err) + } + + var parsed map[string]interface{} + if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated JSON: %v", err) + } +} + +// TestSessionStartPayloadToYAML tests that ToYAML produces valid YAML +func TestSessionStartPayloadToYAML(t *testing.T) { + jsonData := ` +{ + "sessionId": "sess_abc123", + "version": 1, + "producer": "prompty-agent", + "runtime": "typescript", + "promptyVersion": "2.0.0", + "startTime": "2026-06-09T20:00:00Z", + "selectedModel": "gpt-4o-mini", + "reasoningEffort": "medium" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionStartPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load SessionStartPayload: %v", err) + } + yamlOutput, err := instance.ToYAML() + if err != nil { + t.Fatalf("Failed to convert to YAML: %v", err) + } + + var parsed map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated YAML: %v", err) + } +} diff --git a/runtime/go/prompty/model/session_summary.go b/runtime/go/prompty/model/session_summary.go new file mode 100644 index 00000000..9f0f9b50 --- /dev/null +++ b/runtime/go/prompty/model/session_summary.go @@ -0,0 +1,164 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: events + +package prompty + +import ( + "encoding/json" + + "gopkg.in/yaml.v3" +) + +// SessionSummaryStatus represents the allowed values for SessionSummaryStatus. +type SessionSummaryStatus string + +const ( + SessionSummaryStatusSuccess SessionSummaryStatus = "success" + SessionSummaryStatusError SessionSummaryStatus = "error" + SessionSummaryStatusCancelled SessionSummaryStatus = "cancelled" + SessionSummaryStatusInterrupted SessionSummaryStatus = "interrupted" +) + +// SessionSummary represents Summary statistics for a completed session trace. + +type SessionSummary struct { + SessionId string `json:"sessionId" yaml:"sessionId"` + Status *SessionSummaryStatus `json:"status,omitempty" yaml:"status,omitempty"` + Turns *int32 `json:"turns,omitempty" yaml:"turns,omitempty"` + Checkpoints *int32 `json:"checkpoints,omitempty" yaml:"checkpoints,omitempty"` + Usage *TokenUsage `json:"usage,omitempty" yaml:"usage,omitempty"` + DurationMs *float64 `json:"durationMs,omitempty" yaml:"durationMs,omitempty"` +} + +// LoadSessionSummary creates a SessionSummary from a map[string]interface{} +func LoadSessionSummary(data interface{}, ctx *LoadContext) (SessionSummary, error) { + result := SessionSummary{} + + // Load from map + if m, ok := data.(map[string]interface{}); ok { + if val, ok := m["sessionId"]; ok && val != nil { + result.SessionId = string(val.(string)) + } + if val, ok := m["status"]; ok && val != nil { + v := SessionSummaryStatus(val.(string)) + result.Status = &v + } + if val, ok := m["turns"]; ok && val != nil { // Handle various numeric types from JSON/YAML/roundtrip + var v int32 + switch n := val.(type) { + case int: + v = int32(n) + case int32: + v = int32(n) + case int64: + v = int32(n) + case float64: + v = int32(n) + } + result.Turns = &v + } + if val, ok := m["checkpoints"]; ok && val != nil { // Handle various numeric types from JSON/YAML/roundtrip + var v int32 + switch n := val.(type) { + case int: + v = int32(n) + case int32: + v = int32(n) + case int64: + v = int32(n) + case float64: + v = int32(n) + } + result.Checkpoints = &v + } + if val, ok := m["usage"]; ok && val != nil { + if m, ok := val.(map[string]interface{}); ok { + loaded, _ := LoadTokenUsage(m, ctx) + result.Usage = &loaded + } + } + if val, ok := m["durationMs"]; ok && val != nil { // Handle various numeric types from JSON/YAML/roundtrip + var v float64 + switch n := val.(type) { + case int: + v = float64(n) + case int32: + v = float64(n) + case int64: + v = float64(n) + case float32: + v = float64(n) + case float64: + v = n + } + result.DurationMs = &v + } + } + + return result, nil +} + +// Save serializes SessionSummary to map[string]interface{} +func (obj *SessionSummary) Save(ctx *SaveContext) map[string]interface{} { + result := make(map[string]interface{}) + result["sessionId"] = obj.SessionId + if obj.Status != nil { + result["status"] = string(*obj.Status) + } + if obj.Turns != nil { + result["turns"] = *obj.Turns + } + if obj.Checkpoints != nil { + result["checkpoints"] = *obj.Checkpoints + } + if obj.Usage != nil { + result["usage"] = obj.Usage.Save(ctx) + } + if obj.DurationMs != nil { + result["durationMs"] = *obj.DurationMs + } + + return result +} + +// ToJSON serializes SessionSummary to JSON string +func (obj *SessionSummary) ToJSON() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := json.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// ToYAML serializes SessionSummary to YAML string +func (obj *SessionSummary) ToYAML() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := yaml.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// FromJSON creates SessionSummary from JSON string +func SessionSummaryFromJSON(jsonStr string) (SessionSummary, error) { + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { + return SessionSummary{}, err + } + ctx := NewLoadContext() + return LoadSessionSummary(data, ctx) +} + +// FromYAML creates SessionSummary from YAML string +func SessionSummaryFromYAML(yamlStr string) (SessionSummary, error) { + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlStr), &data); err != nil { + return SessionSummary{}, err + } + ctx := NewLoadContext() + return LoadSessionSummary(data, ctx) +} diff --git a/runtime/go/prompty/model/session_summary_test.go b/runtime/go/prompty/model/session_summary_test.go new file mode 100644 index 00000000..3e9e9ca7 --- /dev/null +++ b/runtime/go/prompty/model/session_summary_test.go @@ -0,0 +1,196 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +package prompty_test + +import ( + "encoding/json" + "testing" + + "gopkg.in/yaml.v3" + + "prompty/model" +) + +// TestSessionSummaryLoadJSON tests loading SessionSummary from JSON +func TestSessionSummaryLoadJSON(t *testing.T) { + jsonData := ` +{ + "sessionId": "sess_abc123", + "status": "success", + "turns": 5, + "checkpoints": 2, + "durationMs": 12500 +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionSummary(data, ctx) + if err != nil { + t.Fatalf("Failed to load SessionSummary: %v", err) + } + if instance.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, instance.SessionId) + } + if instance.Status == nil || *instance.Status != "success" { + t.Errorf(`Expected Status to be "success", got %v`, instance.Status) + } + if instance.Turns == nil || *instance.Turns != 5 { + t.Errorf(`Expected Turns to be 5, got %v`, instance.Turns) + } + if instance.Checkpoints == nil || *instance.Checkpoints != 2 { + t.Errorf(`Expected Checkpoints to be 2, got %v`, instance.Checkpoints) + } + if instance.DurationMs == nil || *instance.DurationMs != 12500 { + t.Errorf(`Expected DurationMs to be 12500, got %v`, instance.DurationMs) + } +} + +// TestSessionSummaryLoadYAML tests loading SessionSummary from YAML +func TestSessionSummaryLoadYAML(t *testing.T) { + yamlData := ` +sessionId: sess_abc123 +status: success +turns: 5 +checkpoints: 2 +durationMs: 12500 + +` + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlData), &data); err != nil { + t.Fatalf("Failed to parse YAML: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionSummary(data, ctx) + if err != nil { + t.Fatalf("Failed to load SessionSummary: %v", err) + } + if instance.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, instance.SessionId) + } + if instance.Status == nil || *instance.Status != "success" { + t.Errorf(`Expected Status to be "success", got %v`, instance.Status) + } + if instance.Turns == nil || *instance.Turns != 5 { + t.Errorf(`Expected Turns to be 5, got %v`, instance.Turns) + } + if instance.Checkpoints == nil || *instance.Checkpoints != 2 { + t.Errorf(`Expected Checkpoints to be 2, got %v`, instance.Checkpoints) + } + if instance.DurationMs == nil || *instance.DurationMs != 12500 { + t.Errorf(`Expected DurationMs to be 12500, got %v`, instance.DurationMs) + } +} + +// TestSessionSummaryRoundtrip tests load -> save -> load produces equivalent data +func TestSessionSummaryRoundtrip(t *testing.T) { + jsonData := ` +{ + "sessionId": "sess_abc123", + "status": "success", + "turns": 5, + "checkpoints": 2, + "durationMs": 12500 +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + loadCtx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionSummary(data, loadCtx) + if err != nil { + t.Fatalf("Failed to load SessionSummary: %v", err) + } + saveCtx := prompty.NewSaveContext() + savedData := instance.Save(saveCtx) + + reloaded, err := prompty.LoadSessionSummary(savedData, loadCtx) + if err != nil { + t.Fatalf("Failed to reload SessionSummary: %v", err) + } + if reloaded.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, reloaded.SessionId) + } + if reloaded.Status == nil || *reloaded.Status != "success" { + t.Errorf(`Expected Status to be "success", got %v`, reloaded.Status) + } + if reloaded.Turns == nil || *reloaded.Turns != 5 { + t.Errorf(`Expected Turns to be 5, got %v`, reloaded.Turns) + } + if reloaded.Checkpoints == nil || *reloaded.Checkpoints != 2 { + t.Errorf(`Expected Checkpoints to be 2, got %v`, reloaded.Checkpoints) + } + if reloaded.DurationMs == nil || *reloaded.DurationMs != 12500 { + t.Errorf(`Expected DurationMs to be 12500, got %v`, reloaded.DurationMs) + } +} + +// TestSessionSummaryToJSON tests that ToJSON produces valid JSON +func TestSessionSummaryToJSON(t *testing.T) { + jsonData := ` +{ + "sessionId": "sess_abc123", + "status": "success", + "turns": 5, + "checkpoints": 2, + "durationMs": 12500 +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionSummary(data, ctx) + if err != nil { + t.Fatalf("Failed to load SessionSummary: %v", err) + } + jsonOutput, err := instance.ToJSON() + if err != nil { + t.Fatalf("Failed to convert to JSON: %v", err) + } + + var parsed map[string]interface{} + if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated JSON: %v", err) + } +} + +// TestSessionSummaryToYAML tests that ToYAML produces valid YAML +func TestSessionSummaryToYAML(t *testing.T) { + jsonData := ` +{ + "sessionId": "sess_abc123", + "status": "success", + "turns": 5, + "checkpoints": 2, + "durationMs": 12500 +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionSummary(data, ctx) + if err != nil { + t.Fatalf("Failed to load SessionSummary: %v", err) + } + yamlOutput, err := instance.ToYAML() + if err != nil { + t.Fatalf("Failed to convert to YAML: %v", err) + } + + var parsed map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated YAML: %v", err) + } +} diff --git a/runtime/go/prompty/model/session_trace.go b/runtime/go/prompty/model/session_trace.go new file mode 100644 index 00000000..48f2e6ee --- /dev/null +++ b/runtime/go/prompty/model/session_trace.go @@ -0,0 +1,228 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: events + +package prompty + +import ( + "encoding/json" + + "gopkg.in/yaml.v3" +) + +// SessionTrace represents Portable replay container for an outer harness session. + +type SessionTrace struct { + Version string `json:"version" yaml:"version"` + Runtime *string `json:"runtime,omitempty" yaml:"runtime,omitempty"` + PromptyVersion *string `json:"promptyVersion,omitempty" yaml:"promptyVersion,omitempty"` + SessionId *string `json:"sessionId,omitempty" yaml:"sessionId,omitempty"` + Events []SessionEvent `json:"events" yaml:"events"` + Turns []TurnTrace `json:"turns,omitempty" yaml:"turns,omitempty"` + Checkpoints []Checkpoint `json:"checkpoints,omitempty" yaml:"checkpoints,omitempty"` + Trajectory []TrajectoryEvent `json:"trajectory,omitempty" yaml:"trajectory,omitempty"` + Files []SessionFileRef `json:"files,omitempty" yaml:"files,omitempty"` + Refs []SessionRef `json:"refs,omitempty" yaml:"refs,omitempty"` + Summary *SessionSummary `json:"summary,omitempty" yaml:"summary,omitempty"` +} + +// LoadSessionTrace creates a SessionTrace from a map[string]interface{} +func LoadSessionTrace(data interface{}, ctx *LoadContext) (SessionTrace, error) { + result := SessionTrace{} + + // Load from map + if m, ok := data.(map[string]interface{}); ok { + if val, ok := m["version"]; ok && val != nil { + result.Version = string(val.(string)) + } + if val, ok := m["runtime"]; ok && val != nil { + v := string(val.(string)) + result.Runtime = &v + } + if val, ok := m["promptyVersion"]; ok && val != nil { + v := string(val.(string)) + result.PromptyVersion = &v + } + if val, ok := m["sessionId"]; ok && val != nil { + v := string(val.(string)) + result.SessionId = &v + } + if val, ok := m["events"]; ok && val != nil { + if arr, ok := val.([]interface{}); ok { + result.Events = make([]SessionEvent, len(arr)) + for i, v := range arr { + if item, ok := v.(map[string]interface{}); ok { + loaded, _ := LoadSessionEvent(item, ctx) + result.Events[i] = loaded + } + } + } + } + if val, ok := m["turns"]; ok && val != nil { + if arr, ok := val.([]interface{}); ok { + result.Turns = make([]TurnTrace, len(arr)) + for i, v := range arr { + if item, ok := v.(map[string]interface{}); ok { + loaded, _ := LoadTurnTrace(item, ctx) + result.Turns[i] = loaded + } + } + } + } + if val, ok := m["checkpoints"]; ok && val != nil { + if arr, ok := val.([]interface{}); ok { + result.Checkpoints = make([]Checkpoint, len(arr)) + for i, v := range arr { + if item, ok := v.(map[string]interface{}); ok { + loaded, _ := LoadCheckpoint(item, ctx) + result.Checkpoints[i] = loaded + } + } + } + } + if val, ok := m["trajectory"]; ok && val != nil { + if arr, ok := val.([]interface{}); ok { + result.Trajectory = make([]TrajectoryEvent, len(arr)) + for i, v := range arr { + if item, ok := v.(map[string]interface{}); ok { + loaded, _ := LoadTrajectoryEvent(item, ctx) + result.Trajectory[i] = loaded + } + } + } + } + if val, ok := m["files"]; ok && val != nil { + if arr, ok := val.([]interface{}); ok { + result.Files = make([]SessionFileRef, len(arr)) + for i, v := range arr { + if item, ok := v.(map[string]interface{}); ok { + loaded, _ := LoadSessionFileRef(item, ctx) + result.Files[i] = loaded + } + } + } + } + if val, ok := m["refs"]; ok && val != nil { + if arr, ok := val.([]interface{}); ok { + result.Refs = make([]SessionRef, len(arr)) + for i, v := range arr { + if item, ok := v.(map[string]interface{}); ok { + loaded, _ := LoadSessionRef(item, ctx) + result.Refs[i] = loaded + } + } + } + } + if val, ok := m["summary"]; ok && val != nil { + if m, ok := val.(map[string]interface{}); ok { + loaded, _ := LoadSessionSummary(m, ctx) + result.Summary = &loaded + } + } + } + + return result, nil +} + +// Save serializes SessionTrace to map[string]interface{} +func (obj *SessionTrace) Save(ctx *SaveContext) map[string]interface{} { + result := make(map[string]interface{}) + result["version"] = obj.Version + if obj.Runtime != nil { + result["runtime"] = *obj.Runtime + } + if obj.PromptyVersion != nil { + result["promptyVersion"] = *obj.PromptyVersion + } + if obj.SessionId != nil { + result["sessionId"] = *obj.SessionId + } + if obj.Events != nil { + arr := make([]interface{}, len(obj.Events)) + for i, item := range obj.Events { + arr[i] = item.Save(ctx) + } + result["events"] = arr + } + if obj.Turns != nil { + arr := make([]interface{}, len(obj.Turns)) + for i, item := range obj.Turns { + arr[i] = item.Save(ctx) + } + result["turns"] = arr + } + if obj.Checkpoints != nil { + arr := make([]interface{}, len(obj.Checkpoints)) + for i, item := range obj.Checkpoints { + arr[i] = item.Save(ctx) + } + result["checkpoints"] = arr + } + if obj.Trajectory != nil { + arr := make([]interface{}, len(obj.Trajectory)) + for i, item := range obj.Trajectory { + arr[i] = item.Save(ctx) + } + result["trajectory"] = arr + } + if obj.Files != nil { + arr := make([]interface{}, len(obj.Files)) + for i, item := range obj.Files { + arr[i] = item.Save(ctx) + } + result["files"] = arr + } + if obj.Refs != nil { + arr := make([]interface{}, len(obj.Refs)) + for i, item := range obj.Refs { + arr[i] = item.Save(ctx) + } + result["refs"] = arr + } + if obj.Summary != nil { + result["summary"] = obj.Summary.Save(ctx) + } + + return result +} + +// ToJSON serializes SessionTrace to JSON string +func (obj *SessionTrace) ToJSON() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := json.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// ToYAML serializes SessionTrace to YAML string +func (obj *SessionTrace) ToYAML() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := yaml.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// FromJSON creates SessionTrace from JSON string +func SessionTraceFromJSON(jsonStr string) (SessionTrace, error) { + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { + return SessionTrace{}, err + } + ctx := NewLoadContext() + return LoadSessionTrace(data, ctx) +} + +// FromYAML creates SessionTrace from YAML string +func SessionTraceFromYAML(yamlStr string) (SessionTrace, error) { + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlStr), &data); err != nil { + return SessionTrace{}, err + } + ctx := NewLoadContext() + return LoadSessionTrace(data, ctx) +} diff --git a/runtime/go/prompty/model/session_trace_test.go b/runtime/go/prompty/model/session_trace_test.go new file mode 100644 index 00000000..9996b709 --- /dev/null +++ b/runtime/go/prompty/model/session_trace_test.go @@ -0,0 +1,182 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +package prompty_test + +import ( + "encoding/json" + "testing" + + "gopkg.in/yaml.v3" + + "prompty/model" +) + +// TestSessionTraceLoadJSON tests loading SessionTrace from JSON +func TestSessionTraceLoadJSON(t *testing.T) { + jsonData := ` +{ + "version": "1", + "runtime": "typescript", + "promptyVersion": "2.0.0", + "sessionId": "sess_abc123" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionTrace(data, ctx) + if err != nil { + t.Fatalf("Failed to load SessionTrace: %v", err) + } + if instance.Version != "1" { + t.Errorf(`Expected Version to be "1", got %v`, instance.Version) + } + if instance.Runtime == nil || *instance.Runtime != "typescript" { + t.Errorf(`Expected Runtime to be "typescript", got %v`, instance.Runtime) + } + if instance.PromptyVersion == nil || *instance.PromptyVersion != "2.0.0" { + t.Errorf(`Expected PromptyVersion to be "2.0.0", got %v`, instance.PromptyVersion) + } + if instance.SessionId == nil || *instance.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, instance.SessionId) + } +} + +// TestSessionTraceLoadYAML tests loading SessionTrace from YAML +func TestSessionTraceLoadYAML(t *testing.T) { + yamlData := ` +version: "1" +runtime: typescript +promptyVersion: 2.0.0 +sessionId: sess_abc123 + +` + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlData), &data); err != nil { + t.Fatalf("Failed to parse YAML: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionTrace(data, ctx) + if err != nil { + t.Fatalf("Failed to load SessionTrace: %v", err) + } + if instance.Version != "1" { + t.Errorf(`Expected Version to be "1", got %v`, instance.Version) + } + if instance.Runtime == nil || *instance.Runtime != "typescript" { + t.Errorf(`Expected Runtime to be "typescript", got %v`, instance.Runtime) + } + if instance.PromptyVersion == nil || *instance.PromptyVersion != "2.0.0" { + t.Errorf(`Expected PromptyVersion to be "2.0.0", got %v`, instance.PromptyVersion) + } + if instance.SessionId == nil || *instance.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, instance.SessionId) + } +} + +// TestSessionTraceRoundtrip tests load -> save -> load produces equivalent data +func TestSessionTraceRoundtrip(t *testing.T) { + jsonData := ` +{ + "version": "1", + "runtime": "typescript", + "promptyVersion": "2.0.0", + "sessionId": "sess_abc123" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + loadCtx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionTrace(data, loadCtx) + if err != nil { + t.Fatalf("Failed to load SessionTrace: %v", err) + } + saveCtx := prompty.NewSaveContext() + savedData := instance.Save(saveCtx) + + reloaded, err := prompty.LoadSessionTrace(savedData, loadCtx) + if err != nil { + t.Fatalf("Failed to reload SessionTrace: %v", err) + } + if reloaded.Version != "1" { + t.Errorf(`Expected Version to be "1", got %v`, reloaded.Version) + } + if reloaded.Runtime == nil || *reloaded.Runtime != "typescript" { + t.Errorf(`Expected Runtime to be "typescript", got %v`, reloaded.Runtime) + } + if reloaded.PromptyVersion == nil || *reloaded.PromptyVersion != "2.0.0" { + t.Errorf(`Expected PromptyVersion to be "2.0.0", got %v`, reloaded.PromptyVersion) + } + if reloaded.SessionId == nil || *reloaded.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, reloaded.SessionId) + } +} + +// TestSessionTraceToJSON tests that ToJSON produces valid JSON +func TestSessionTraceToJSON(t *testing.T) { + jsonData := ` +{ + "version": "1", + "runtime": "typescript", + "promptyVersion": "2.0.0", + "sessionId": "sess_abc123" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionTrace(data, ctx) + if err != nil { + t.Fatalf("Failed to load SessionTrace: %v", err) + } + jsonOutput, err := instance.ToJSON() + if err != nil { + t.Fatalf("Failed to convert to JSON: %v", err) + } + + var parsed map[string]interface{} + if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated JSON: %v", err) + } +} + +// TestSessionTraceToYAML tests that ToYAML produces valid YAML +func TestSessionTraceToYAML(t *testing.T) { + jsonData := ` +{ + "version": "1", + "runtime": "typescript", + "promptyVersion": "2.0.0", + "sessionId": "sess_abc123" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionTrace(data, ctx) + if err != nil { + t.Fatalf("Failed to load SessionTrace: %v", err) + } + yamlOutput, err := instance.ToYAML() + if err != nil { + t.Fatalf("Failed to convert to YAML: %v", err) + } + + var parsed map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated YAML: %v", err) + } +} diff --git a/runtime/go/prompty/model/session_warning_payload.go b/runtime/go/prompty/model/session_warning_payload.go new file mode 100644 index 00000000..b11ff11d --- /dev/null +++ b/runtime/go/prompty/model/session_warning_payload.go @@ -0,0 +1,94 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: events + +package prompty + +import ( + "encoding/json" + + "gopkg.in/yaml.v3" +) + +// SessionWarningPayload represents Payload for "session_warning" events. + +type SessionWarningPayload struct { + WarningType string `json:"warningType" yaml:"warningType"` + Message string `json:"message" yaml:"message"` + Details map[string]interface{} `json:"details,omitempty" yaml:"details,omitempty"` +} + +// LoadSessionWarningPayload creates a SessionWarningPayload from a map[string]interface{} +func LoadSessionWarningPayload(data interface{}, ctx *LoadContext) (SessionWarningPayload, error) { + result := SessionWarningPayload{} + + // Load from map + if m, ok := data.(map[string]interface{}); ok { + if val, ok := m["warningType"]; ok && val != nil { + result.WarningType = string(val.(string)) + } + if val, ok := m["message"]; ok && val != nil { + result.Message = string(val.(string)) + } + if val, ok := m["details"]; ok && val != nil { + if m, ok := val.(map[string]interface{}); ok { + result.Details = m + } + } + } + + return result, nil +} + +// Save serializes SessionWarningPayload to map[string]interface{} +func (obj *SessionWarningPayload) Save(ctx *SaveContext) map[string]interface{} { + result := make(map[string]interface{}) + result["warningType"] = obj.WarningType + result["message"] = obj.Message + if obj.Details != nil { + result["details"] = obj.Details + } + + return result +} + +// ToJSON serializes SessionWarningPayload to JSON string +func (obj *SessionWarningPayload) ToJSON() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := json.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// ToYAML serializes SessionWarningPayload to YAML string +func (obj *SessionWarningPayload) ToYAML() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := yaml.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// FromJSON creates SessionWarningPayload from JSON string +func SessionWarningPayloadFromJSON(jsonStr string) (SessionWarningPayload, error) { + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { + return SessionWarningPayload{}, err + } + ctx := NewLoadContext() + return LoadSessionWarningPayload(data, ctx) +} + +// FromYAML creates SessionWarningPayload from YAML string +func SessionWarningPayloadFromYAML(yamlStr string) (SessionWarningPayload, error) { + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlStr), &data); err != nil { + return SessionWarningPayload{}, err + } + ctx := NewLoadContext() + return LoadSessionWarningPayload(data, ctx) +} diff --git a/runtime/go/prompty/model/session_warning_payload_test.go b/runtime/go/prompty/model/session_warning_payload_test.go new file mode 100644 index 00000000..ad8bae01 --- /dev/null +++ b/runtime/go/prompty/model/session_warning_payload_test.go @@ -0,0 +1,154 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +package prompty_test + +import ( + "encoding/json" + "testing" + + "gopkg.in/yaml.v3" + + "prompty/model" +) + +// TestSessionWarningPayloadLoadJSON tests loading SessionWarningPayload from JSON +func TestSessionWarningPayloadLoadJSON(t *testing.T) { + jsonData := ` +{ + "warningType": "remote", + "message": "Remote session disabled" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionWarningPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load SessionWarningPayload: %v", err) + } + if instance.WarningType != "remote" { + t.Errorf(`Expected WarningType to be "remote", got %v`, instance.WarningType) + } + if instance.Message != "Remote session disabled" { + t.Errorf(`Expected Message to be "Remote session disabled", got %v`, instance.Message) + } +} + +// TestSessionWarningPayloadLoadYAML tests loading SessionWarningPayload from YAML +func TestSessionWarningPayloadLoadYAML(t *testing.T) { + yamlData := ` +warningType: remote +message: Remote session disabled + +` + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlData), &data); err != nil { + t.Fatalf("Failed to parse YAML: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionWarningPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load SessionWarningPayload: %v", err) + } + if instance.WarningType != "remote" { + t.Errorf(`Expected WarningType to be "remote", got %v`, instance.WarningType) + } + if instance.Message != "Remote session disabled" { + t.Errorf(`Expected Message to be "Remote session disabled", got %v`, instance.Message) + } +} + +// TestSessionWarningPayloadRoundtrip tests load -> save -> load produces equivalent data +func TestSessionWarningPayloadRoundtrip(t *testing.T) { + jsonData := ` +{ + "warningType": "remote", + "message": "Remote session disabled" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + loadCtx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionWarningPayload(data, loadCtx) + if err != nil { + t.Fatalf("Failed to load SessionWarningPayload: %v", err) + } + saveCtx := prompty.NewSaveContext() + savedData := instance.Save(saveCtx) + + reloaded, err := prompty.LoadSessionWarningPayload(savedData, loadCtx) + if err != nil { + t.Fatalf("Failed to reload SessionWarningPayload: %v", err) + } + if reloaded.WarningType != "remote" { + t.Errorf(`Expected WarningType to be "remote", got %v`, reloaded.WarningType) + } + if reloaded.Message != "Remote session disabled" { + t.Errorf(`Expected Message to be "Remote session disabled", got %v`, reloaded.Message) + } +} + +// TestSessionWarningPayloadToJSON tests that ToJSON produces valid JSON +func TestSessionWarningPayloadToJSON(t *testing.T) { + jsonData := ` +{ + "warningType": "remote", + "message": "Remote session disabled" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionWarningPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load SessionWarningPayload: %v", err) + } + jsonOutput, err := instance.ToJSON() + if err != nil { + t.Fatalf("Failed to convert to JSON: %v", err) + } + + var parsed map[string]interface{} + if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated JSON: %v", err) + } +} + +// TestSessionWarningPayloadToYAML tests that ToYAML produces valid YAML +func TestSessionWarningPayloadToYAML(t *testing.T) { + jsonData := ` +{ + "warningType": "remote", + "message": "Remote session disabled" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadSessionWarningPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load SessionWarningPayload: %v", err) + } + yamlOutput, err := instance.ToYAML() + if err != nil { + t.Fatalf("Failed to convert to YAML: %v", err) + } + + var parsed map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated YAML: %v", err) + } +} diff --git a/runtime/go/prompty/model/tool_execution_complete_payload.go b/runtime/go/prompty/model/tool_execution_complete_payload.go new file mode 100644 index 00000000..b0a05e4f --- /dev/null +++ b/runtime/go/prompty/model/tool_execution_complete_payload.go @@ -0,0 +1,173 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: events + +package prompty + +import ( + "encoding/json" + + "gopkg.in/yaml.v3" +) + +// ToolExecutionCompletePayload represents Payload for "tool_execution_complete" events — a concrete host tool execution finished. + +type ToolExecutionCompletePayload struct { + RequestId *string `json:"requestId,omitempty" yaml:"requestId,omitempty"` + ToolCallId *string `json:"toolCallId,omitempty" yaml:"toolCallId,omitempty"` + ToolName string `json:"toolName" yaml:"toolName"` + Success bool `json:"success" yaml:"success"` + Result *interface{} `json:"result,omitempty" yaml:"result,omitempty"` + ExitCode *int32 `json:"exitCode,omitempty" yaml:"exitCode,omitempty"` + DurationMs *float64 `json:"durationMs,omitempty" yaml:"durationMs,omitempty"` + ErrorKind *string `json:"errorKind,omitempty" yaml:"errorKind,omitempty"` + Telemetry map[string]interface{} `json:"telemetry,omitempty" yaml:"telemetry,omitempty"` + Redaction *RedactionMetadata `json:"redaction,omitempty" yaml:"redaction,omitempty"` +} + +// LoadToolExecutionCompletePayload creates a ToolExecutionCompletePayload from a map[string]interface{} +func LoadToolExecutionCompletePayload(data interface{}, ctx *LoadContext) (ToolExecutionCompletePayload, error) { + result := ToolExecutionCompletePayload{} + + // Load from map + if m, ok := data.(map[string]interface{}); ok { + if val, ok := m["requestId"]; ok && val != nil { + v := string(val.(string)) + result.RequestId = &v + } + if val, ok := m["toolCallId"]; ok && val != nil { + v := string(val.(string)) + result.ToolCallId = &v + } + if val, ok := m["toolName"]; ok && val != nil { + result.ToolName = string(val.(string)) + } + if val, ok := m["success"]; ok && val != nil { + result.Success = val.(bool) + } + if val, ok := m["result"]; ok && val != nil { + result.Result = &val + } + if val, ok := m["exitCode"]; ok && val != nil { // Handle various numeric types from JSON/YAML/roundtrip + var v int32 + switch n := val.(type) { + case int: + v = int32(n) + case int32: + v = int32(n) + case int64: + v = int32(n) + case float64: + v = int32(n) + } + result.ExitCode = &v + } + if val, ok := m["durationMs"]; ok && val != nil { // Handle various numeric types from JSON/YAML/roundtrip + var v float64 + switch n := val.(type) { + case int: + v = float64(n) + case int32: + v = float64(n) + case int64: + v = float64(n) + case float32: + v = float64(n) + case float64: + v = n + } + result.DurationMs = &v + } + if val, ok := m["errorKind"]; ok && val != nil { + v := string(val.(string)) + result.ErrorKind = &v + } + if val, ok := m["telemetry"]; ok && val != nil { + if m, ok := val.(map[string]interface{}); ok { + result.Telemetry = m + } + } + if val, ok := m["redaction"]; ok && val != nil { + if m, ok := val.(map[string]interface{}); ok { + loaded, _ := LoadRedactionMetadata(m, ctx) + result.Redaction = &loaded + } + } + } + + return result, nil +} + +// Save serializes ToolExecutionCompletePayload to map[string]interface{} +func (obj *ToolExecutionCompletePayload) Save(ctx *SaveContext) map[string]interface{} { + result := make(map[string]interface{}) + if obj.RequestId != nil { + result["requestId"] = *obj.RequestId + } + if obj.ToolCallId != nil { + result["toolCallId"] = *obj.ToolCallId + } + result["toolName"] = obj.ToolName + result["success"] = obj.Success + if obj.Result != nil { + result["result"] = *obj.Result + } + if obj.ExitCode != nil { + result["exitCode"] = *obj.ExitCode + } + if obj.DurationMs != nil { + result["durationMs"] = *obj.DurationMs + } + if obj.ErrorKind != nil { + result["errorKind"] = *obj.ErrorKind + } + if obj.Telemetry != nil { + result["telemetry"] = obj.Telemetry + } + if obj.Redaction != nil { + result["redaction"] = obj.Redaction.Save(ctx) + } + + return result +} + +// ToJSON serializes ToolExecutionCompletePayload to JSON string +func (obj *ToolExecutionCompletePayload) ToJSON() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := json.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// ToYAML serializes ToolExecutionCompletePayload to YAML string +func (obj *ToolExecutionCompletePayload) ToYAML() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := yaml.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// FromJSON creates ToolExecutionCompletePayload from JSON string +func ToolExecutionCompletePayloadFromJSON(jsonStr string) (ToolExecutionCompletePayload, error) { + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { + return ToolExecutionCompletePayload{}, err + } + ctx := NewLoadContext() + return LoadToolExecutionCompletePayload(data, ctx) +} + +// FromYAML creates ToolExecutionCompletePayload from YAML string +func ToolExecutionCompletePayloadFromYAML(yamlStr string) (ToolExecutionCompletePayload, error) { + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlStr), &data); err != nil { + return ToolExecutionCompletePayload{}, err + } + ctx := NewLoadContext() + return LoadToolExecutionCompletePayload(data, ctx) +} diff --git a/runtime/go/prompty/model/tool_execution_complete_payload_test.go b/runtime/go/prompty/model/tool_execution_complete_payload_test.go new file mode 100644 index 00000000..f15d0a22 --- /dev/null +++ b/runtime/go/prompty/model/tool_execution_complete_payload_test.go @@ -0,0 +1,224 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +package prompty_test + +import ( + "encoding/json" + "testing" + + "gopkg.in/yaml.v3" + + "prompty/model" +) + +// TestToolExecutionCompletePayloadLoadJSON tests loading ToolExecutionCompletePayload from JSON +func TestToolExecutionCompletePayloadLoadJSON(t *testing.T) { + jsonData := ` +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "success": true, + "exitCode": 0, + "durationMs": 250, + "errorKind": "timeout" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadToolExecutionCompletePayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load ToolExecutionCompletePayload: %v", err) + } + if instance.RequestId == nil || *instance.RequestId != "exec_abc123" { + t.Errorf(`Expected RequestId to be "exec_abc123", got %v`, instance.RequestId) + } + if instance.ToolCallId == nil || *instance.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, instance.ToolCallId) + } + if instance.ToolName != "powershell" { + t.Errorf(`Expected ToolName to be "powershell", got %v`, instance.ToolName) + } + if instance.Success != true { + t.Errorf(`Expected Success to be true, got %v`, instance.Success) + } + if instance.ExitCode == nil || *instance.ExitCode != 0 { + t.Errorf(`Expected ExitCode to be 0, got %v`, instance.ExitCode) + } + if instance.DurationMs == nil || *instance.DurationMs != 250 { + t.Errorf(`Expected DurationMs to be 250, got %v`, instance.DurationMs) + } + if instance.ErrorKind == nil || *instance.ErrorKind != "timeout" { + t.Errorf(`Expected ErrorKind to be "timeout", got %v`, instance.ErrorKind) + } +} + +// TestToolExecutionCompletePayloadLoadYAML tests loading ToolExecutionCompletePayload from YAML +func TestToolExecutionCompletePayloadLoadYAML(t *testing.T) { + yamlData := ` +requestId: exec_abc123 +toolCallId: call_abc123 +toolName: powershell +success: true +exitCode: 0 +durationMs: 250 +errorKind: timeout + +` + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlData), &data); err != nil { + t.Fatalf("Failed to parse YAML: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadToolExecutionCompletePayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load ToolExecutionCompletePayload: %v", err) + } + if instance.RequestId == nil || *instance.RequestId != "exec_abc123" { + t.Errorf(`Expected RequestId to be "exec_abc123", got %v`, instance.RequestId) + } + if instance.ToolCallId == nil || *instance.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, instance.ToolCallId) + } + if instance.ToolName != "powershell" { + t.Errorf(`Expected ToolName to be "powershell", got %v`, instance.ToolName) + } + if instance.Success != true { + t.Errorf(`Expected Success to be true, got %v`, instance.Success) + } + if instance.ExitCode == nil || *instance.ExitCode != 0 { + t.Errorf(`Expected ExitCode to be 0, got %v`, instance.ExitCode) + } + if instance.DurationMs == nil || *instance.DurationMs != 250 { + t.Errorf(`Expected DurationMs to be 250, got %v`, instance.DurationMs) + } + if instance.ErrorKind == nil || *instance.ErrorKind != "timeout" { + t.Errorf(`Expected ErrorKind to be "timeout", got %v`, instance.ErrorKind) + } +} + +// TestToolExecutionCompletePayloadRoundtrip tests load -> save -> load produces equivalent data +func TestToolExecutionCompletePayloadRoundtrip(t *testing.T) { + jsonData := ` +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "success": true, + "exitCode": 0, + "durationMs": 250, + "errorKind": "timeout" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + loadCtx := prompty.NewLoadContext() + instance, err := prompty.LoadToolExecutionCompletePayload(data, loadCtx) + if err != nil { + t.Fatalf("Failed to load ToolExecutionCompletePayload: %v", err) + } + saveCtx := prompty.NewSaveContext() + savedData := instance.Save(saveCtx) + + reloaded, err := prompty.LoadToolExecutionCompletePayload(savedData, loadCtx) + if err != nil { + t.Fatalf("Failed to reload ToolExecutionCompletePayload: %v", err) + } + if reloaded.RequestId == nil || *reloaded.RequestId != "exec_abc123" { + t.Errorf(`Expected RequestId to be "exec_abc123", got %v`, reloaded.RequestId) + } + if reloaded.ToolCallId == nil || *reloaded.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, reloaded.ToolCallId) + } + if reloaded.ToolName != "powershell" { + t.Errorf(`Expected ToolName to be "powershell", got %v`, reloaded.ToolName) + } + if reloaded.Success != true { + t.Errorf(`Expected Success to be true, got %v`, reloaded.Success) + } + if reloaded.ExitCode == nil || *reloaded.ExitCode != 0 { + t.Errorf(`Expected ExitCode to be 0, got %v`, reloaded.ExitCode) + } + if reloaded.DurationMs == nil || *reloaded.DurationMs != 250 { + t.Errorf(`Expected DurationMs to be 250, got %v`, reloaded.DurationMs) + } + if reloaded.ErrorKind == nil || *reloaded.ErrorKind != "timeout" { + t.Errorf(`Expected ErrorKind to be "timeout", got %v`, reloaded.ErrorKind) + } +} + +// TestToolExecutionCompletePayloadToJSON tests that ToJSON produces valid JSON +func TestToolExecutionCompletePayloadToJSON(t *testing.T) { + jsonData := ` +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "success": true, + "exitCode": 0, + "durationMs": 250, + "errorKind": "timeout" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadToolExecutionCompletePayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load ToolExecutionCompletePayload: %v", err) + } + jsonOutput, err := instance.ToJSON() + if err != nil { + t.Fatalf("Failed to convert to JSON: %v", err) + } + + var parsed map[string]interface{} + if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated JSON: %v", err) + } +} + +// TestToolExecutionCompletePayloadToYAML tests that ToYAML produces valid YAML +func TestToolExecutionCompletePayloadToYAML(t *testing.T) { + jsonData := ` +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "success": true, + "exitCode": 0, + "durationMs": 250, + "errorKind": "timeout" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadToolExecutionCompletePayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load ToolExecutionCompletePayload: %v", err) + } + yamlOutput, err := instance.ToYAML() + if err != nil { + t.Fatalf("Failed to convert to YAML: %v", err) + } + + var parsed map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated YAML: %v", err) + } +} diff --git a/runtime/go/prompty/model/tool_execution_start_payload.go b/runtime/go/prompty/model/tool_execution_start_payload.go new file mode 100644 index 00000000..7ac5c4d1 --- /dev/null +++ b/runtime/go/prompty/model/tool_execution_start_payload.go @@ -0,0 +1,126 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: events + +package prompty + +import ( + "encoding/json" + + "gopkg.in/yaml.v3" +) + +// ToolExecutionStartPayload represents Payload for "tool_execution_start" events — the host is about to execute a concrete tool request. +// +// This is distinct from "tool_call_start", which records the model requesting a tool. +// Tool execution events capture the harness-side action after policy and permission checks. + +type ToolExecutionStartPayload struct { + RequestId *string `json:"requestId,omitempty" yaml:"requestId,omitempty"` + ToolCallId *string `json:"toolCallId,omitempty" yaml:"toolCallId,omitempty"` + ToolName string `json:"toolName" yaml:"toolName"` + Arguments map[string]interface{} `json:"arguments,omitempty" yaml:"arguments,omitempty"` + WorkingDirectory *string `json:"workingDirectory,omitempty" yaml:"workingDirectory,omitempty"` + Redaction *RedactionMetadata `json:"redaction,omitempty" yaml:"redaction,omitempty"` +} + +// LoadToolExecutionStartPayload creates a ToolExecutionStartPayload from a map[string]interface{} +func LoadToolExecutionStartPayload(data interface{}, ctx *LoadContext) (ToolExecutionStartPayload, error) { + result := ToolExecutionStartPayload{} + + // Load from map + if m, ok := data.(map[string]interface{}); ok { + if val, ok := m["requestId"]; ok && val != nil { + v := string(val.(string)) + result.RequestId = &v + } + if val, ok := m["toolCallId"]; ok && val != nil { + v := string(val.(string)) + result.ToolCallId = &v + } + if val, ok := m["toolName"]; ok && val != nil { + result.ToolName = string(val.(string)) + } + if val, ok := m["arguments"]; ok && val != nil { + if m, ok := val.(map[string]interface{}); ok { + result.Arguments = m + } + } + if val, ok := m["workingDirectory"]; ok && val != nil { + v := string(val.(string)) + result.WorkingDirectory = &v + } + if val, ok := m["redaction"]; ok && val != nil { + if m, ok := val.(map[string]interface{}); ok { + loaded, _ := LoadRedactionMetadata(m, ctx) + result.Redaction = &loaded + } + } + } + + return result, nil +} + +// Save serializes ToolExecutionStartPayload to map[string]interface{} +func (obj *ToolExecutionStartPayload) Save(ctx *SaveContext) map[string]interface{} { + result := make(map[string]interface{}) + if obj.RequestId != nil { + result["requestId"] = *obj.RequestId + } + if obj.ToolCallId != nil { + result["toolCallId"] = *obj.ToolCallId + } + result["toolName"] = obj.ToolName + if obj.Arguments != nil { + result["arguments"] = obj.Arguments + } + if obj.WorkingDirectory != nil { + result["workingDirectory"] = *obj.WorkingDirectory + } + if obj.Redaction != nil { + result["redaction"] = obj.Redaction.Save(ctx) + } + + return result +} + +// ToJSON serializes ToolExecutionStartPayload to JSON string +func (obj *ToolExecutionStartPayload) ToJSON() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := json.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// ToYAML serializes ToolExecutionStartPayload to YAML string +func (obj *ToolExecutionStartPayload) ToYAML() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := yaml.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// FromJSON creates ToolExecutionStartPayload from JSON string +func ToolExecutionStartPayloadFromJSON(jsonStr string) (ToolExecutionStartPayload, error) { + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { + return ToolExecutionStartPayload{}, err + } + ctx := NewLoadContext() + return LoadToolExecutionStartPayload(data, ctx) +} + +// FromYAML creates ToolExecutionStartPayload from YAML string +func ToolExecutionStartPayloadFromYAML(yamlStr string) (ToolExecutionStartPayload, error) { + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlStr), &data); err != nil { + return ToolExecutionStartPayload{}, err + } + ctx := NewLoadContext() + return LoadToolExecutionStartPayload(data, ctx) +} diff --git a/runtime/go/prompty/model/tool_execution_start_payload_test.go b/runtime/go/prompty/model/tool_execution_start_payload_test.go new file mode 100644 index 00000000..1e1392e6 --- /dev/null +++ b/runtime/go/prompty/model/tool_execution_start_payload_test.go @@ -0,0 +1,182 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +package prompty_test + +import ( + "encoding/json" + "testing" + + "gopkg.in/yaml.v3" + + "prompty/model" +) + +// TestToolExecutionStartPayloadLoadJSON tests loading ToolExecutionStartPayload from JSON +func TestToolExecutionStartPayloadLoadJSON(t *testing.T) { + jsonData := ` +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "workingDirectory": "/workspace/project" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadToolExecutionStartPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load ToolExecutionStartPayload: %v", err) + } + if instance.RequestId == nil || *instance.RequestId != "exec_abc123" { + t.Errorf(`Expected RequestId to be "exec_abc123", got %v`, instance.RequestId) + } + if instance.ToolCallId == nil || *instance.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, instance.ToolCallId) + } + if instance.ToolName != "powershell" { + t.Errorf(`Expected ToolName to be "powershell", got %v`, instance.ToolName) + } + if instance.WorkingDirectory == nil || *instance.WorkingDirectory != "/workspace/project" { + t.Errorf(`Expected WorkingDirectory to be "/workspace/project", got %v`, instance.WorkingDirectory) + } +} + +// TestToolExecutionStartPayloadLoadYAML tests loading ToolExecutionStartPayload from YAML +func TestToolExecutionStartPayloadLoadYAML(t *testing.T) { + yamlData := ` +requestId: exec_abc123 +toolCallId: call_abc123 +toolName: powershell +workingDirectory: /workspace/project + +` + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlData), &data); err != nil { + t.Fatalf("Failed to parse YAML: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadToolExecutionStartPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load ToolExecutionStartPayload: %v", err) + } + if instance.RequestId == nil || *instance.RequestId != "exec_abc123" { + t.Errorf(`Expected RequestId to be "exec_abc123", got %v`, instance.RequestId) + } + if instance.ToolCallId == nil || *instance.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, instance.ToolCallId) + } + if instance.ToolName != "powershell" { + t.Errorf(`Expected ToolName to be "powershell", got %v`, instance.ToolName) + } + if instance.WorkingDirectory == nil || *instance.WorkingDirectory != "/workspace/project" { + t.Errorf(`Expected WorkingDirectory to be "/workspace/project", got %v`, instance.WorkingDirectory) + } +} + +// TestToolExecutionStartPayloadRoundtrip tests load -> save -> load produces equivalent data +func TestToolExecutionStartPayloadRoundtrip(t *testing.T) { + jsonData := ` +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "workingDirectory": "/workspace/project" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + loadCtx := prompty.NewLoadContext() + instance, err := prompty.LoadToolExecutionStartPayload(data, loadCtx) + if err != nil { + t.Fatalf("Failed to load ToolExecutionStartPayload: %v", err) + } + saveCtx := prompty.NewSaveContext() + savedData := instance.Save(saveCtx) + + reloaded, err := prompty.LoadToolExecutionStartPayload(savedData, loadCtx) + if err != nil { + t.Fatalf("Failed to reload ToolExecutionStartPayload: %v", err) + } + if reloaded.RequestId == nil || *reloaded.RequestId != "exec_abc123" { + t.Errorf(`Expected RequestId to be "exec_abc123", got %v`, reloaded.RequestId) + } + if reloaded.ToolCallId == nil || *reloaded.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, reloaded.ToolCallId) + } + if reloaded.ToolName != "powershell" { + t.Errorf(`Expected ToolName to be "powershell", got %v`, reloaded.ToolName) + } + if reloaded.WorkingDirectory == nil || *reloaded.WorkingDirectory != "/workspace/project" { + t.Errorf(`Expected WorkingDirectory to be "/workspace/project", got %v`, reloaded.WorkingDirectory) + } +} + +// TestToolExecutionStartPayloadToJSON tests that ToJSON produces valid JSON +func TestToolExecutionStartPayloadToJSON(t *testing.T) { + jsonData := ` +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "workingDirectory": "/workspace/project" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadToolExecutionStartPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load ToolExecutionStartPayload: %v", err) + } + jsonOutput, err := instance.ToJSON() + if err != nil { + t.Fatalf("Failed to convert to JSON: %v", err) + } + + var parsed map[string]interface{} + if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated JSON: %v", err) + } +} + +// TestToolExecutionStartPayloadToYAML tests that ToYAML produces valid YAML +func TestToolExecutionStartPayloadToYAML(t *testing.T) { + jsonData := ` +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "workingDirectory": "/workspace/project" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadToolExecutionStartPayload(data, ctx) + if err != nil { + t.Fatalf("Failed to load ToolExecutionStartPayload: %v", err) + } + yamlOutput, err := instance.ToYAML() + if err != nil { + t.Fatalf("Failed to convert to YAML: %v", err) + } + + var parsed map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated YAML: %v", err) + } +} diff --git a/runtime/go/prompty/model/trace_writer.go b/runtime/go/prompty/model/trace_writer.go new file mode 100644 index 00000000..ec0695f7 --- /dev/null +++ b/runtime/go/prompty/model/trace_writer.go @@ -0,0 +1,15 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: pipeline + +package prompty + +// TraceWriter represents Persists typed events to a replayable trace. + +type TraceWriter interface { + // AppendTurn — Append a turn event to a replayable trace + AppendTurn(turnEvent TurnEvent) (bool, error) + // AppendSession — Append a session event to a replayable trace + AppendSession(sessionEvent SessionEvent) (bool, error) + // Close — Finalize the trace with an optional session summary + Close(summary *SessionSummary) (bool, error) +} diff --git a/runtime/go/prompty/model/trajectory_event.go b/runtime/go/prompty/model/trajectory_event.go new file mode 100644 index 00000000..b49a8c07 --- /dev/null +++ b/runtime/go/prompty/model/trajectory_event.go @@ -0,0 +1,157 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: events + +package prompty + +import ( + "encoding/json" + + "gopkg.in/yaml.v3" +) + +// TrajectoryEvent represents A compact, replay-oriented record of one harness-side action or observation. + +type TrajectoryEvent struct { + Id *string `json:"id,omitempty" yaml:"id,omitempty"` + SessionId *string `json:"sessionId,omitempty" yaml:"sessionId,omitempty"` + TurnId *string `json:"turnId,omitempty" yaml:"turnId,omitempty"` + ToolCallId *string `json:"toolCallId,omitempty" yaml:"toolCallId,omitempty"` + TurnIndex *int32 `json:"turnIndex,omitempty" yaml:"turnIndex,omitempty"` + EventType string `json:"eventType" yaml:"eventType"` + Data map[string]interface{} `json:"data,omitempty" yaml:"data,omitempty"` + CreatedAt *string `json:"createdAt,omitempty" yaml:"createdAt,omitempty"` + Redaction *RedactionMetadata `json:"redaction,omitempty" yaml:"redaction,omitempty"` +} + +// LoadTrajectoryEvent creates a TrajectoryEvent from a map[string]interface{} +func LoadTrajectoryEvent(data interface{}, ctx *LoadContext) (TrajectoryEvent, error) { + result := TrajectoryEvent{} + + // Load from map + if m, ok := data.(map[string]interface{}); ok { + if val, ok := m["id"]; ok && val != nil { + v := string(val.(string)) + result.Id = &v + } + if val, ok := m["sessionId"]; ok && val != nil { + v := string(val.(string)) + result.SessionId = &v + } + if val, ok := m["turnId"]; ok && val != nil { + v := string(val.(string)) + result.TurnId = &v + } + if val, ok := m["toolCallId"]; ok && val != nil { + v := string(val.(string)) + result.ToolCallId = &v + } + if val, ok := m["turnIndex"]; ok && val != nil { // Handle various numeric types from JSON/YAML/roundtrip + var v int32 + switch n := val.(type) { + case int: + v = int32(n) + case int32: + v = int32(n) + case int64: + v = int32(n) + case float64: + v = int32(n) + } + result.TurnIndex = &v + } + if val, ok := m["eventType"]; ok && val != nil { + result.EventType = string(val.(string)) + } + if val, ok := m["data"]; ok && val != nil { + if m, ok := val.(map[string]interface{}); ok { + result.Data = m + } + } + if val, ok := m["createdAt"]; ok && val != nil { + v := string(val.(string)) + result.CreatedAt = &v + } + if val, ok := m["redaction"]; ok && val != nil { + if m, ok := val.(map[string]interface{}); ok { + loaded, _ := LoadRedactionMetadata(m, ctx) + result.Redaction = &loaded + } + } + } + + return result, nil +} + +// Save serializes TrajectoryEvent to map[string]interface{} +func (obj *TrajectoryEvent) Save(ctx *SaveContext) map[string]interface{} { + result := make(map[string]interface{}) + if obj.Id != nil { + result["id"] = *obj.Id + } + if obj.SessionId != nil { + result["sessionId"] = *obj.SessionId + } + if obj.TurnId != nil { + result["turnId"] = *obj.TurnId + } + if obj.ToolCallId != nil { + result["toolCallId"] = *obj.ToolCallId + } + if obj.TurnIndex != nil { + result["turnIndex"] = *obj.TurnIndex + } + result["eventType"] = obj.EventType + if obj.Data != nil { + result["data"] = obj.Data + } + if obj.CreatedAt != nil { + result["createdAt"] = *obj.CreatedAt + } + if obj.Redaction != nil { + result["redaction"] = obj.Redaction.Save(ctx) + } + + return result +} + +// ToJSON serializes TrajectoryEvent to JSON string +func (obj *TrajectoryEvent) ToJSON() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := json.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// ToYAML serializes TrajectoryEvent to YAML string +func (obj *TrajectoryEvent) ToYAML() (string, error) { + ctx := NewSaveContext() + data := obj.Save(ctx) + bytes, err := yaml.Marshal(data) + if err != nil { + return "", err + } + return string(bytes), nil +} + +// FromJSON creates TrajectoryEvent from JSON string +func TrajectoryEventFromJSON(jsonStr string) (TrajectoryEvent, error) { + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { + return TrajectoryEvent{}, err + } + ctx := NewLoadContext() + return LoadTrajectoryEvent(data, ctx) +} + +// FromYAML creates TrajectoryEvent from YAML string +func TrajectoryEventFromYAML(yamlStr string) (TrajectoryEvent, error) { + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlStr), &data); err != nil { + return TrajectoryEvent{}, err + } + ctx := NewLoadContext() + return LoadTrajectoryEvent(data, ctx) +} diff --git a/runtime/go/prompty/model/trajectory_event_test.go b/runtime/go/prompty/model/trajectory_event_test.go new file mode 100644 index 00000000..cdf24bdf --- /dev/null +++ b/runtime/go/prompty/model/trajectory_event_test.go @@ -0,0 +1,224 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +package prompty_test + +import ( + "encoding/json" + "testing" + + "gopkg.in/yaml.v3" + + "prompty/model" +) + +// TestTrajectoryEventLoadJSON tests loading TrajectoryEvent from JSON +func TestTrajectoryEventLoadJSON(t *testing.T) { + jsonData := ` +{ + "id": "traj_abc123", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "toolCallId": "call_abc123", + "turnIndex": 4, + "eventType": "command", + "createdAt": "2026-06-09T20:00:00Z" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadTrajectoryEvent(data, ctx) + if err != nil { + t.Fatalf("Failed to load TrajectoryEvent: %v", err) + } + if instance.Id == nil || *instance.Id != "traj_abc123" { + t.Errorf(`Expected Id to be "traj_abc123", got %v`, instance.Id) + } + if instance.SessionId == nil || *instance.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, instance.SessionId) + } + if instance.TurnId == nil || *instance.TurnId != "turn_001" { + t.Errorf(`Expected TurnId to be "turn_001", got %v`, instance.TurnId) + } + if instance.ToolCallId == nil || *instance.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, instance.ToolCallId) + } + if instance.TurnIndex == nil || *instance.TurnIndex != 4 { + t.Errorf(`Expected TurnIndex to be 4, got %v`, instance.TurnIndex) + } + if instance.EventType != "command" { + t.Errorf(`Expected EventType to be "command", got %v`, instance.EventType) + } + if instance.CreatedAt == nil || *instance.CreatedAt != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected CreatedAt to be "2026-06-09T20:00:00Z", got %v`, instance.CreatedAt) + } +} + +// TestTrajectoryEventLoadYAML tests loading TrajectoryEvent from YAML +func TestTrajectoryEventLoadYAML(t *testing.T) { + yamlData := ` +id: traj_abc123 +sessionId: sess_abc123 +turnId: turn_001 +toolCallId: call_abc123 +turnIndex: 4 +eventType: command +createdAt: "2026-06-09T20:00:00Z" + +` + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlData), &data); err != nil { + t.Fatalf("Failed to parse YAML: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadTrajectoryEvent(data, ctx) + if err != nil { + t.Fatalf("Failed to load TrajectoryEvent: %v", err) + } + if instance.Id == nil || *instance.Id != "traj_abc123" { + t.Errorf(`Expected Id to be "traj_abc123", got %v`, instance.Id) + } + if instance.SessionId == nil || *instance.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, instance.SessionId) + } + if instance.TurnId == nil || *instance.TurnId != "turn_001" { + t.Errorf(`Expected TurnId to be "turn_001", got %v`, instance.TurnId) + } + if instance.ToolCallId == nil || *instance.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, instance.ToolCallId) + } + if instance.TurnIndex == nil || *instance.TurnIndex != 4 { + t.Errorf(`Expected TurnIndex to be 4, got %v`, instance.TurnIndex) + } + if instance.EventType != "command" { + t.Errorf(`Expected EventType to be "command", got %v`, instance.EventType) + } + if instance.CreatedAt == nil || *instance.CreatedAt != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected CreatedAt to be "2026-06-09T20:00:00Z", got %v`, instance.CreatedAt) + } +} + +// TestTrajectoryEventRoundtrip tests load -> save -> load produces equivalent data +func TestTrajectoryEventRoundtrip(t *testing.T) { + jsonData := ` +{ + "id": "traj_abc123", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "toolCallId": "call_abc123", + "turnIndex": 4, + "eventType": "command", + "createdAt": "2026-06-09T20:00:00Z" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + loadCtx := prompty.NewLoadContext() + instance, err := prompty.LoadTrajectoryEvent(data, loadCtx) + if err != nil { + t.Fatalf("Failed to load TrajectoryEvent: %v", err) + } + saveCtx := prompty.NewSaveContext() + savedData := instance.Save(saveCtx) + + reloaded, err := prompty.LoadTrajectoryEvent(savedData, loadCtx) + if err != nil { + t.Fatalf("Failed to reload TrajectoryEvent: %v", err) + } + if reloaded.Id == nil || *reloaded.Id != "traj_abc123" { + t.Errorf(`Expected Id to be "traj_abc123", got %v`, reloaded.Id) + } + if reloaded.SessionId == nil || *reloaded.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, reloaded.SessionId) + } + if reloaded.TurnId == nil || *reloaded.TurnId != "turn_001" { + t.Errorf(`Expected TurnId to be "turn_001", got %v`, reloaded.TurnId) + } + if reloaded.ToolCallId == nil || *reloaded.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, reloaded.ToolCallId) + } + if reloaded.TurnIndex == nil || *reloaded.TurnIndex != 4 { + t.Errorf(`Expected TurnIndex to be 4, got %v`, reloaded.TurnIndex) + } + if reloaded.EventType != "command" { + t.Errorf(`Expected EventType to be "command", got %v`, reloaded.EventType) + } + if reloaded.CreatedAt == nil || *reloaded.CreatedAt != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected CreatedAt to be "2026-06-09T20:00:00Z", got %v`, reloaded.CreatedAt) + } +} + +// TestTrajectoryEventToJSON tests that ToJSON produces valid JSON +func TestTrajectoryEventToJSON(t *testing.T) { + jsonData := ` +{ + "id": "traj_abc123", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "toolCallId": "call_abc123", + "turnIndex": 4, + "eventType": "command", + "createdAt": "2026-06-09T20:00:00Z" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadTrajectoryEvent(data, ctx) + if err != nil { + t.Fatalf("Failed to load TrajectoryEvent: %v", err) + } + jsonOutput, err := instance.ToJSON() + if err != nil { + t.Fatalf("Failed to convert to JSON: %v", err) + } + + var parsed map[string]interface{} + if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated JSON: %v", err) + } +} + +// TestTrajectoryEventToYAML tests that ToYAML produces valid YAML +func TestTrajectoryEventToYAML(t *testing.T) { + jsonData := ` +{ + "id": "traj_abc123", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "toolCallId": "call_abc123", + "turnIndex": 4, + "eventType": "command", + "createdAt": "2026-06-09T20:00:00Z" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadTrajectoryEvent(data, ctx) + if err != nil { + t.Fatalf("Failed to load TrajectoryEvent: %v", err) + } + yamlOutput, err := instance.ToYAML() + if err != nil { + t.Fatalf("Failed to convert to YAML: %v", err) + } + + var parsed map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated YAML: %v", err) + } +} diff --git a/runtime/go/prompty/model/turn_event.go b/runtime/go/prompty/model/turn_event.go index cd85e959..c9f4b5d0 100644 --- a/runtime/go/prompty/model/turn_event.go +++ b/runtime/go/prompty/model/turn_event.go @@ -13,26 +13,30 @@ import ( type TurnEventType string const ( - TurnEventTypeTurnStart TurnEventType = "turn_start" - TurnEventTypeTurnEnd TurnEventType = "turn_end" - TurnEventTypeLlmStart TurnEventType = "llm_start" - TurnEventTypeLlmComplete TurnEventType = "llm_complete" - TurnEventTypeRetry TurnEventType = "retry" - TurnEventTypePermissionRequested TurnEventType = "permission_requested" - TurnEventTypePermissionCompleted TurnEventType = "permission_completed" - TurnEventTypeToken TurnEventType = "token" - TurnEventTypeThinking TurnEventType = "thinking" - TurnEventTypeToolCallStart TurnEventType = "tool_call_start" - TurnEventTypeToolCallComplete TurnEventType = "tool_call_complete" - TurnEventTypeToolResult TurnEventType = "tool_result" - TurnEventTypeStatus TurnEventType = "status" - TurnEventTypeMessagesUpdated TurnEventType = "messages_updated" - TurnEventTypeDone TurnEventType = "done" - TurnEventTypeError TurnEventType = "error" - TurnEventTypeCancelled TurnEventType = "cancelled" - TurnEventTypeCompactionStart TurnEventType = "compaction_start" - TurnEventTypeCompactionComplete TurnEventType = "compaction_complete" - TurnEventTypeCompactionFailed TurnEventType = "compaction_failed" + TurnEventTypeTurnStart TurnEventType = "turn_start" + TurnEventTypeTurnEnd TurnEventType = "turn_end" + TurnEventTypeLlmStart TurnEventType = "llm_start" + TurnEventTypeLlmComplete TurnEventType = "llm_complete" + TurnEventTypeRetry TurnEventType = "retry" + TurnEventTypePermissionRequested TurnEventType = "permission_requested" + TurnEventTypePermissionCompleted TurnEventType = "permission_completed" + TurnEventTypeToken TurnEventType = "token" + TurnEventTypeThinking TurnEventType = "thinking" + TurnEventTypeToolCallStart TurnEventType = "tool_call_start" + TurnEventTypeToolCallComplete TurnEventType = "tool_call_complete" + TurnEventTypeToolExecutionStart TurnEventType = "tool_execution_start" + TurnEventTypeToolExecutionComplete TurnEventType = "tool_execution_complete" + TurnEventTypeToolResult TurnEventType = "tool_result" + TurnEventTypeHookStart TurnEventType = "hook_start" + TurnEventTypeHookEnd TurnEventType = "hook_end" + TurnEventTypeStatus TurnEventType = "status" + TurnEventTypeMessagesUpdated TurnEventType = "messages_updated" + TurnEventTypeDone TurnEventType = "done" + TurnEventTypeError TurnEventType = "error" + TurnEventTypeCancelled TurnEventType = "cancelled" + TurnEventTypeCompactionStart TurnEventType = "compaction_start" + TurnEventTypeCompactionComplete TurnEventType = "compaction_complete" + TurnEventTypeCompactionFailed TurnEventType = "compaction_failed" ) // TurnEvent represents A canonical event envelope emitted by the turn harness. The payload is kept diff --git a/runtime/python/prompty/prompty/model/__init__.py b/runtime/python/prompty/prompty/model/__init__.py index b98b42e7..8b61065b 100644 --- a/runtime/python/prompty/prompty/model/__init__.py +++ b/runtime/python/prompty/prompty/model/__init__.py @@ -40,18 +40,36 @@ ValidationResult, ) from .events import ( + Checkpoint, CompactionCompletePayload, CompactionFailedPayload, CompactionStartPayload, DoneEventPayload, ErrorChunk, ErrorEventPayload, + HarnessContext, + HookEndPayload, + HookStartPayload, + HostToolRequest, + HostToolResult, LlmCompletePayload, LlmStartPayload, MessagesUpdatedPayload, PermissionCompletedPayload, + PermissionDecision, + PermissionRequest, PermissionRequestedPayload, + RedactedField, + RedactionMetadata, RetryPayload, + SessionEndPayload, + SessionEvent, + SessionFileRef, + SessionRef, + SessionStartPayload, + SessionSummary, + SessionTrace, + SessionWarningPayload, StatusEventPayload, StreamChunk, TextChunk, @@ -61,7 +79,10 @@ ToolCallCompletePayload, ToolCallStartPayload, ToolChunk, + ToolExecutionCompletePayload, + ToolExecutionStartPayload, ToolResultPayload, + TrajectoryEvent, TurnEndPayload, TurnEvent, TurnStartPayload, @@ -75,11 +96,16 @@ TokenUsage, ) from .pipeline import ( + CheckpointStore, CompactionConfig, + EventSink, Executor, + HostToolExecutor, Parser, + PermissionResolver, Processor, Renderer, + TraceWriter, TurnOptions, ) from .streaming import ( @@ -173,18 +199,33 @@ "Parser", "Executor", "Processor", + "EventSink", + "TraceWriter", + "PermissionResolver", + "CheckpointStore", + "HostToolExecutor", "TurnEvent", "TurnStartPayload", "TurnEndPayload", "LlmStartPayload", "LlmCompletePayload", "RetryPayload", + "RedactedField", + "RedactionMetadata", "PermissionRequestedPayload", "PermissionCompletedPayload", + "PermissionRequest", + "PermissionDecision", "TokenEventPayload", "ThinkingEventPayload", "ToolCallStartPayload", "ToolCallCompletePayload", + "ToolExecutionStartPayload", + "ToolExecutionCompletePayload", + "HostToolRequest", + "HostToolResult", + "HookStartPayload", + "HookEndPayload", "ToolResultPayload", "StatusEventPayload", "MessagesUpdatedPayload", @@ -195,6 +236,17 @@ "CompactionFailedPayload", "TurnSummary", "TurnTrace", + "HarnessContext", + "SessionStartPayload", + "SessionEndPayload", + "SessionWarningPayload", + "SessionEvent", + "Checkpoint", + "TrajectoryEvent", + "SessionFileRef", + "SessionRef", + "SessionSummary", + "SessionTrace", "StreamChunk", "TextChunk", "ThinkingChunk", diff --git a/runtime/python/prompty/prompty/model/events/_Checkpoint.py b/runtime/python/prompty/prompty/model/events/_Checkpoint.py new file mode 100644 index 00000000..b9dca919 --- /dev/null +++ b/runtime/python/prompty/prompty/model/events/_Checkpoint.py @@ -0,0 +1,168 @@ +########################################## +# WARNING: This is an auto-generated file. +# DO NOT EDIT THIS FILE DIRECTLY +# ANY EDITS WILL BE LOST +########################################## + +from dataclasses import dataclass, field +from typing import Any, ClassVar + +from .._context import LoadContext, SaveContext +from ._RedactionMetadata import RedactionMetadata + + +@dataclass +class Checkpoint: + """A persisted handoff point for a harness session. + + Attributes + ---------- + id : Optional[str] + Stable checkpoint identifier + session_id : Optional[str] + Stable session identifier + turn_id : Optional[str] + Associated turn identifier, when the checkpoint was created inside a turn + checkpoint_number : Optional[int] + Monotonic checkpoint number within the session + title : str + Short checkpoint title + overview : Optional[str] + Short human-readable overview + state : Optional[dict[str, Any]] + Portable checkpoint state needed to resume or hand off the session + summary : Optional[str] + Optional host-authored summary or handoff note + metadata : Optional[dict[str, Any]] + Host-defined checkpoint metadata + created_at : Optional[str] + ISO 8601 UTC timestamp when the checkpoint was created + redaction : Optional[RedactionMetadata] + Redaction state for sensitive checkpoint fields + """ + + _shorthand_property: ClassVar[str | None] = None + + id: str | None = None + session_id: str | None = None + turn_id: str | None = None + checkpoint_number: int | None = None + title: str = field(default="") + overview: str | None = None + state: dict[str, Any] | None = None + summary: str | None = None + metadata: dict[str, Any] | None = None + created_at: str | None = None + redaction: RedactionMetadata | None = None + + @staticmethod + def load(data: Any, context: LoadContext | None = None) -> "Checkpoint": + """Load a Checkpoint instance. + Args: + data (Any): The data to load the instance from. + context (Optional[LoadContext]): Optional context with pre/post processing callbacks. + Returns: + Checkpoint: The loaded Checkpoint instance. + + """ + + if context is not None: + data = context.process_input(data) + + if not isinstance(data, dict): + raise ValueError(f"Invalid data for Checkpoint: {data}") + + # create new instance + instance = Checkpoint() + + if data is not None and "id" in data: + instance.id = data["id"] + if data is not None and "sessionId" in data: + instance.session_id = data["sessionId"] + if data is not None and "turnId" in data: + instance.turn_id = data["turnId"] + if data is not None and "checkpointNumber" in data: + instance.checkpoint_number = data["checkpointNumber"] + if data is not None and "title" in data: + instance.title = data["title"] + if data is not None and "overview" in data: + instance.overview = data["overview"] + if data is not None and "state" in data: + instance.state = data["state"] + if data is not None and "summary" in data: + instance.summary = data["summary"] + if data is not None and "metadata" in data: + instance.metadata = data["metadata"] + if data is not None and "createdAt" in data: + instance.created_at = data["createdAt"] + if data is not None and "redaction" in data: + instance.redaction = RedactionMetadata.load(data["redaction"], context) + if context is not None: + instance = context.process_output(instance) + return instance + + def save(self, context: SaveContext | None = None) -> dict[str, Any]: + """Save the Checkpoint instance to a dictionary. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + dict[str, Any]: The dictionary representation of this instance. + + """ + obj = self + if context is not None: + obj = context.process_object(obj) + + result: dict[str, Any] = {} + + if obj.id is not None: + result["id"] = obj.id + if obj.session_id is not None: + result["sessionId"] = obj.session_id + if obj.turn_id is not None: + result["turnId"] = obj.turn_id + if obj.checkpoint_number is not None: + result["checkpointNumber"] = obj.checkpoint_number + if obj.title is not None: + result["title"] = obj.title + if obj.overview is not None: + result["overview"] = obj.overview + if obj.state is not None: + result["state"] = obj.state + if obj.summary is not None: + result["summary"] = obj.summary + if obj.metadata is not None: + result["metadata"] = obj.metadata + if obj.created_at is not None: + result["createdAt"] = obj.created_at + if obj.redaction is not None: + result["redaction"] = obj.redaction.save(context) + + if context is not None: + result = context.process_dict(result) + return result + + def to_yaml(self, context: SaveContext | None = None) -> str: + """Convert the Checkpoint instance to a YAML string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + str: The YAML string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_yaml(self.save(context)) + + def to_json(self, context: SaveContext | None = None, indent: int = 2) -> str: + """Convert the Checkpoint instance to a JSON string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + indent (int): Number of spaces for indentation. Defaults to 2. + Returns: + str: The JSON string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_json(self.save(context), indent) diff --git a/runtime/python/prompty/prompty/model/events/_HarnessContext.py b/runtime/python/prompty/prompty/model/events/_HarnessContext.py new file mode 100644 index 00000000..da7c5be9 --- /dev/null +++ b/runtime/python/prompty/prompty/model/events/_HarnessContext.py @@ -0,0 +1,113 @@ +########################################## +# WARNING: This is an auto-generated file. +# DO NOT EDIT THIS FILE DIRECTLY +# ANY EDITS WILL BE LOST +########################################## + +from dataclasses import dataclass +from typing import Any, ClassVar + +from .._context import LoadContext, SaveContext + + +@dataclass +class HarnessContext: + """Execution context associated with a harness session. Host-specific + environments can store detailed profiles in metadata without making the core + contract depend on one source-control provider or workspace shape. + + Attributes + ---------- + cwd : Optional[str] + Current working directory for the harness + git_root : Optional[str] + Git repository root, when known + metadata : Optional[dict[str, Any]] + Host-defined context metadata, such as source-control or sandbox details + """ + + _shorthand_property: ClassVar[str | None] = None + + cwd: str | None = None + git_root: str | None = None + metadata: dict[str, Any] | None = None + + @staticmethod + def load(data: Any, context: LoadContext | None = None) -> "HarnessContext": + """Load a HarnessContext instance. + Args: + data (Any): The data to load the instance from. + context (Optional[LoadContext]): Optional context with pre/post processing callbacks. + Returns: + HarnessContext: The loaded HarnessContext instance. + + """ + + if context is not None: + data = context.process_input(data) + + if not isinstance(data, dict): + raise ValueError(f"Invalid data for HarnessContext: {data}") + + # create new instance + instance = HarnessContext() + + if data is not None and "cwd" in data: + instance.cwd = data["cwd"] + if data is not None and "gitRoot" in data: + instance.git_root = data["gitRoot"] + if data is not None and "metadata" in data: + instance.metadata = data["metadata"] + if context is not None: + instance = context.process_output(instance) + return instance + + def save(self, context: SaveContext | None = None) -> dict[str, Any]: + """Save the HarnessContext instance to a dictionary. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + dict[str, Any]: The dictionary representation of this instance. + + """ + obj = self + if context is not None: + obj = context.process_object(obj) + + result: dict[str, Any] = {} + + if obj.cwd is not None: + result["cwd"] = obj.cwd + if obj.git_root is not None: + result["gitRoot"] = obj.git_root + if obj.metadata is not None: + result["metadata"] = obj.metadata + + if context is not None: + result = context.process_dict(result) + return result + + def to_yaml(self, context: SaveContext | None = None) -> str: + """Convert the HarnessContext instance to a YAML string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + str: The YAML string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_yaml(self.save(context)) + + def to_json(self, context: SaveContext | None = None, indent: int = 2) -> str: + """Convert the HarnessContext instance to a JSON string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + indent (int): Number of spaces for indentation. Defaults to 2. + Returns: + str: The JSON string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_json(self.save(context), indent) diff --git a/runtime/python/prompty/prompty/model/events/_HookEndPayload.py b/runtime/python/prompty/prompty/model/events/_HookEndPayload.py new file mode 100644 index 00000000..91151cee --- /dev/null +++ b/runtime/python/prompty/prompty/model/events/_HookEndPayload.py @@ -0,0 +1,140 @@ +########################################## +# WARNING: This is an auto-generated file. +# DO NOT EDIT THIS FILE DIRECTLY +# ANY EDITS WILL BE LOST +########################################## + +from dataclasses import dataclass, field +from typing import Any, ClassVar + +from .._context import LoadContext, SaveContext +from ._RedactionMetadata import RedactionMetadata + + +@dataclass +class HookEndPayload: + """Payload for "hook_end" events — a host lifecycle hook finished. + + Attributes + ---------- + hook_invocation_id : str + Stable hook invocation identifier + hook_type : str + Host-defined hook type + success : bool + Whether the hook completed successfully + output : Optional[dict[str, Any]] + Hook output after host-side sanitization + duration_ms : Optional[float] + Hook execution duration in milliseconds + error : Optional[str] + Human-readable error when success is false + redaction : Optional[RedactionMetadata] + Redaction state for sensitive hook output fields + """ + + _shorthand_property: ClassVar[str | None] = None + + hook_invocation_id: str = field(default="") + hook_type: str = field(default="") + success: bool = field(default=False) + output: dict[str, Any] | None = None + duration_ms: float | None = None + error: str | None = None + redaction: RedactionMetadata | None = None + + @staticmethod + def load(data: Any, context: LoadContext | None = None) -> "HookEndPayload": + """Load a HookEndPayload instance. + Args: + data (Any): The data to load the instance from. + context (Optional[LoadContext]): Optional context with pre/post processing callbacks. + Returns: + HookEndPayload: The loaded HookEndPayload instance. + + """ + + if context is not None: + data = context.process_input(data) + + if not isinstance(data, dict): + raise ValueError(f"Invalid data for HookEndPayload: {data}") + + # create new instance + instance = HookEndPayload() + + if data is not None and "hookInvocationId" in data: + instance.hook_invocation_id = data["hookInvocationId"] + if data is not None and "hookType" in data: + instance.hook_type = data["hookType"] + if data is not None and "success" in data: + instance.success = data["success"] + if data is not None and "output" in data: + instance.output = data["output"] + if data is not None and "durationMs" in data: + instance.duration_ms = data["durationMs"] + if data is not None and "error" in data: + instance.error = data["error"] + if data is not None and "redaction" in data: + instance.redaction = RedactionMetadata.load(data["redaction"], context) + if context is not None: + instance = context.process_output(instance) + return instance + + def save(self, context: SaveContext | None = None) -> dict[str, Any]: + """Save the HookEndPayload instance to a dictionary. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + dict[str, Any]: The dictionary representation of this instance. + + """ + obj = self + if context is not None: + obj = context.process_object(obj) + + result: dict[str, Any] = {} + + if obj.hook_invocation_id is not None: + result["hookInvocationId"] = obj.hook_invocation_id + if obj.hook_type is not None: + result["hookType"] = obj.hook_type + if obj.success is not None: + result["success"] = obj.success + if obj.output is not None: + result["output"] = obj.output + if obj.duration_ms is not None: + result["durationMs"] = obj.duration_ms + if obj.error is not None: + result["error"] = obj.error + if obj.redaction is not None: + result["redaction"] = obj.redaction.save(context) + + if context is not None: + result = context.process_dict(result) + return result + + def to_yaml(self, context: SaveContext | None = None) -> str: + """Convert the HookEndPayload instance to a YAML string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + str: The YAML string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_yaml(self.save(context)) + + def to_json(self, context: SaveContext | None = None, indent: int = 2) -> str: + """Convert the HookEndPayload instance to a JSON string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + indent (int): Number of spaces for indentation. Defaults to 2. + Returns: + str: The JSON string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_json(self.save(context), indent) diff --git a/runtime/python/prompty/prompty/model/events/_HookStartPayload.py b/runtime/python/prompty/prompty/model/events/_HookStartPayload.py new file mode 100644 index 00000000..f06e7b77 --- /dev/null +++ b/runtime/python/prompty/prompty/model/events/_HookStartPayload.py @@ -0,0 +1,119 @@ +########################################## +# WARNING: This is an auto-generated file. +# DO NOT EDIT THIS FILE DIRECTLY +# ANY EDITS WILL BE LOST +########################################## + +from dataclasses import dataclass, field +from typing import Any, ClassVar + +from .._context import LoadContext, SaveContext +from ._RedactionMetadata import RedactionMetadata + + +@dataclass +class HookStartPayload: + """Payload for "hook_start" events — a host lifecycle hook is beginning. + + Attributes + ---------- + hook_invocation_id : str + Stable hook invocation identifier + hook_type : str + Host-defined hook type + input : Optional[dict[str, Any]] + Hook input after host-side sanitization + redaction : Optional[RedactionMetadata] + Redaction state for sensitive hook input fields + """ + + _shorthand_property: ClassVar[str | None] = None + + hook_invocation_id: str = field(default="") + hook_type: str = field(default="") + input: dict[str, Any] | None = None + redaction: RedactionMetadata | None = None + + @staticmethod + def load(data: Any, context: LoadContext | None = None) -> "HookStartPayload": + """Load a HookStartPayload instance. + Args: + data (Any): The data to load the instance from. + context (Optional[LoadContext]): Optional context with pre/post processing callbacks. + Returns: + HookStartPayload: The loaded HookStartPayload instance. + + """ + + if context is not None: + data = context.process_input(data) + + if not isinstance(data, dict): + raise ValueError(f"Invalid data for HookStartPayload: {data}") + + # create new instance + instance = HookStartPayload() + + if data is not None and "hookInvocationId" in data: + instance.hook_invocation_id = data["hookInvocationId"] + if data is not None and "hookType" in data: + instance.hook_type = data["hookType"] + if data is not None and "input" in data: + instance.input = data["input"] + if data is not None and "redaction" in data: + instance.redaction = RedactionMetadata.load(data["redaction"], context) + if context is not None: + instance = context.process_output(instance) + return instance + + def save(self, context: SaveContext | None = None) -> dict[str, Any]: + """Save the HookStartPayload instance to a dictionary. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + dict[str, Any]: The dictionary representation of this instance. + + """ + obj = self + if context is not None: + obj = context.process_object(obj) + + result: dict[str, Any] = {} + + if obj.hook_invocation_id is not None: + result["hookInvocationId"] = obj.hook_invocation_id + if obj.hook_type is not None: + result["hookType"] = obj.hook_type + if obj.input is not None: + result["input"] = obj.input + if obj.redaction is not None: + result["redaction"] = obj.redaction.save(context) + + if context is not None: + result = context.process_dict(result) + return result + + def to_yaml(self, context: SaveContext | None = None) -> str: + """Convert the HookStartPayload instance to a YAML string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + str: The YAML string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_yaml(self.save(context)) + + def to_json(self, context: SaveContext | None = None, indent: int = 2) -> str: + """Convert the HookStartPayload instance to a JSON string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + indent (int): Number of spaces for indentation. Defaults to 2. + Returns: + str: The JSON string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_json(self.save(context), indent) diff --git a/runtime/python/prompty/prompty/model/events/_HostToolRequest.py b/runtime/python/prompty/prompty/model/events/_HostToolRequest.py new file mode 100644 index 00000000..e6c9e6db --- /dev/null +++ b/runtime/python/prompty/prompty/model/events/_HostToolRequest.py @@ -0,0 +1,125 @@ +########################################## +# WARNING: This is an auto-generated file. +# DO NOT EDIT THIS FILE DIRECTLY +# ANY EDITS WILL BE LOST +########################################## + +from dataclasses import dataclass, field +from typing import Any, ClassVar + +from .._context import LoadContext, SaveContext + + +@dataclass +class HostToolRequest: + """Request passed to a host tool executor after policy and permission checks. + + Attributes + ---------- + request_id : Optional[str] + Stable host execution request identifier + tool_call_id : Optional[str] + Associated model tool call identifier, when available + tool_name : str + Name of the host tool being executed + arguments : Optional[dict[str, Any]] + Tool arguments after host-side sanitization + working_directory : Optional[str] + Working directory or execution scope for the tool + """ + + _shorthand_property: ClassVar[str | None] = None + + request_id: str | None = None + tool_call_id: str | None = None + tool_name: str = field(default="") + arguments: dict[str, Any] | None = None + working_directory: str | None = None + + @staticmethod + def load(data: Any, context: LoadContext | None = None) -> "HostToolRequest": + """Load a HostToolRequest instance. + Args: + data (Any): The data to load the instance from. + context (Optional[LoadContext]): Optional context with pre/post processing callbacks. + Returns: + HostToolRequest: The loaded HostToolRequest instance. + + """ + + if context is not None: + data = context.process_input(data) + + if not isinstance(data, dict): + raise ValueError(f"Invalid data for HostToolRequest: {data}") + + # create new instance + instance = HostToolRequest() + + if data is not None and "requestId" in data: + instance.request_id = data["requestId"] + if data is not None and "toolCallId" in data: + instance.tool_call_id = data["toolCallId"] + if data is not None and "toolName" in data: + instance.tool_name = data["toolName"] + if data is not None and "arguments" in data: + instance.arguments = data["arguments"] + if data is not None and "workingDirectory" in data: + instance.working_directory = data["workingDirectory"] + if context is not None: + instance = context.process_output(instance) + return instance + + def save(self, context: SaveContext | None = None) -> dict[str, Any]: + """Save the HostToolRequest instance to a dictionary. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + dict[str, Any]: The dictionary representation of this instance. + + """ + obj = self + if context is not None: + obj = context.process_object(obj) + + result: dict[str, Any] = {} + + if obj.request_id is not None: + result["requestId"] = obj.request_id + if obj.tool_call_id is not None: + result["toolCallId"] = obj.tool_call_id + if obj.tool_name is not None: + result["toolName"] = obj.tool_name + if obj.arguments is not None: + result["arguments"] = obj.arguments + if obj.working_directory is not None: + result["workingDirectory"] = obj.working_directory + + if context is not None: + result = context.process_dict(result) + return result + + def to_yaml(self, context: SaveContext | None = None) -> str: + """Convert the HostToolRequest instance to a YAML string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + str: The YAML string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_yaml(self.save(context)) + + def to_json(self, context: SaveContext | None = None, indent: int = 2) -> str: + """Convert the HostToolRequest instance to a JSON string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + indent (int): Number of spaces for indentation. Defaults to 2. + Returns: + str: The JSON string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_json(self.save(context), indent) diff --git a/runtime/python/prompty/prompty/model/events/_HostToolResult.py b/runtime/python/prompty/prompty/model/events/_HostToolResult.py new file mode 100644 index 00000000..82e8c064 --- /dev/null +++ b/runtime/python/prompty/prompty/model/events/_HostToolResult.py @@ -0,0 +1,153 @@ +########################################## +# WARNING: This is an auto-generated file. +# DO NOT EDIT THIS FILE DIRECTLY +# ANY EDITS WILL BE LOST +########################################## + +from dataclasses import dataclass, field +from typing import Any, ClassVar + +from .._context import LoadContext, SaveContext + + +@dataclass +class HostToolResult: + """Result returned by a host tool executor. + + Attributes + ---------- + request_id : Optional[str] + Stable host execution request identifier + tool_call_id : Optional[str] + Associated model tool call identifier, when available + tool_name : str + Name of the host tool that executed + success : bool + Whether the host execution completed successfully + result : Optional[Any] + Host-normalized execution result + exit_code : Optional[int] + Process or host exit code, when applicable + duration_ms : Optional[float] + Tool execution duration in milliseconds + error_kind : Optional[str] + Machine-readable error category when success is false + telemetry : Optional[dict[str, Any]] + Host-specific telemetry for the execution + """ + + _shorthand_property: ClassVar[str | None] = None + + request_id: str | None = None + tool_call_id: str | None = None + tool_name: str = field(default="") + success: bool = field(default=False) + result: Any | None = None + exit_code: int | None = None + duration_ms: float | None = None + error_kind: str | None = None + telemetry: dict[str, Any] | None = None + + @staticmethod + def load(data: Any, context: LoadContext | None = None) -> "HostToolResult": + """Load a HostToolResult instance. + Args: + data (Any): The data to load the instance from. + context (Optional[LoadContext]): Optional context with pre/post processing callbacks. + Returns: + HostToolResult: The loaded HostToolResult instance. + + """ + + if context is not None: + data = context.process_input(data) + + if not isinstance(data, dict): + raise ValueError(f"Invalid data for HostToolResult: {data}") + + # create new instance + instance = HostToolResult() + + if data is not None and "requestId" in data: + instance.request_id = data["requestId"] + if data is not None and "toolCallId" in data: + instance.tool_call_id = data["toolCallId"] + if data is not None and "toolName" in data: + instance.tool_name = data["toolName"] + if data is not None and "success" in data: + instance.success = data["success"] + if data is not None and "result" in data: + instance.result = data["result"] + if data is not None and "exitCode" in data: + instance.exit_code = data["exitCode"] + if data is not None and "durationMs" in data: + instance.duration_ms = data["durationMs"] + if data is not None and "errorKind" in data: + instance.error_kind = data["errorKind"] + if data is not None and "telemetry" in data: + instance.telemetry = data["telemetry"] + if context is not None: + instance = context.process_output(instance) + return instance + + def save(self, context: SaveContext | None = None) -> dict[str, Any]: + """Save the HostToolResult instance to a dictionary. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + dict[str, Any]: The dictionary representation of this instance. + + """ + obj = self + if context is not None: + obj = context.process_object(obj) + + result: dict[str, Any] = {} + + if obj.request_id is not None: + result["requestId"] = obj.request_id + if obj.tool_call_id is not None: + result["toolCallId"] = obj.tool_call_id + if obj.tool_name is not None: + result["toolName"] = obj.tool_name + if obj.success is not None: + result["success"] = obj.success + if obj.result is not None: + result["result"] = obj.result + if obj.exit_code is not None: + result["exitCode"] = obj.exit_code + if obj.duration_ms is not None: + result["durationMs"] = obj.duration_ms + if obj.error_kind is not None: + result["errorKind"] = obj.error_kind + if obj.telemetry is not None: + result["telemetry"] = obj.telemetry + + if context is not None: + result = context.process_dict(result) + return result + + def to_yaml(self, context: SaveContext | None = None) -> str: + """Convert the HostToolResult instance to a YAML string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + str: The YAML string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_yaml(self.save(context)) + + def to_json(self, context: SaveContext | None = None, indent: int = 2) -> str: + """Convert the HostToolResult instance to a JSON string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + indent (int): Number of spaces for indentation. Defaults to 2. + Returns: + str: The JSON string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_json(self.save(context), indent) diff --git a/runtime/python/prompty/prompty/model/events/_PermissionCompletedPayload.py b/runtime/python/prompty/prompty/model/events/_PermissionCompletedPayload.py index eedf9a93..913ea1d2 100644 --- a/runtime/python/prompty/prompty/model/events/_PermissionCompletedPayload.py +++ b/runtime/python/prompty/prompty/model/events/_PermissionCompletedPayload.py @@ -16,19 +16,28 @@ class PermissionCompletedPayload: Attributes ---------- + request_id : Optional[str] + Stable permission request identifier + tool_call_id : Optional[str] + Associated tool call identifier, when the permission gated a tool call permission : str Permission/action name that was decided approved : bool Whether the requested permission was approved reason : Optional[str] Decision reason, if available + result : Optional[dict[str, Any]] + Host-specific decision result, such as a durable approval token or denial details """ _shorthand_property: ClassVar[str | None] = None + request_id: str | None = None + tool_call_id: str | None = None permission: str = field(default="") approved: bool = field(default=False) reason: str | None = None + result: dict[str, Any] | None = None @staticmethod def load(data: Any, context: LoadContext | None = None) -> "PermissionCompletedPayload": @@ -50,12 +59,18 @@ def load(data: Any, context: LoadContext | None = None) -> "PermissionCompletedP # create new instance instance = PermissionCompletedPayload() + if data is not None and "requestId" in data: + instance.request_id = data["requestId"] + if data is not None and "toolCallId" in data: + instance.tool_call_id = data["toolCallId"] if data is not None and "permission" in data: instance.permission = data["permission"] if data is not None and "approved" in data: instance.approved = data["approved"] if data is not None and "reason" in data: instance.reason = data["reason"] + if data is not None and "result" in data: + instance.result = data["result"] if context is not None: instance = context.process_output(instance) return instance @@ -74,12 +89,18 @@ def save(self, context: SaveContext | None = None) -> dict[str, Any]: result: dict[str, Any] = {} + if obj.request_id is not None: + result["requestId"] = obj.request_id + if obj.tool_call_id is not None: + result["toolCallId"] = obj.tool_call_id if obj.permission is not None: result["permission"] = obj.permission if obj.approved is not None: result["approved"] = obj.approved if obj.reason is not None: result["reason"] = obj.reason + if obj.result is not None: + result["result"] = obj.result if context is not None: result = context.process_dict(result) diff --git a/runtime/python/prompty/prompty/model/events/_PermissionDecision.py b/runtime/python/prompty/prompty/model/events/_PermissionDecision.py new file mode 100644 index 00000000..61a50ba5 --- /dev/null +++ b/runtime/python/prompty/prompty/model/events/_PermissionDecision.py @@ -0,0 +1,132 @@ +########################################## +# WARNING: This is an auto-generated file. +# DO NOT EDIT THIS FILE DIRECTLY +# ANY EDITS WILL BE LOST +########################################## + +from dataclasses import dataclass, field +from typing import Any, ClassVar + +from .._context import LoadContext, SaveContext + + +@dataclass +class PermissionDecision: + """Decision returned by a permission resolver. + + Attributes + ---------- + request_id : Optional[str] + Stable permission request identifier + tool_call_id : Optional[str] + Associated tool call identifier, when the permission gated a tool call + permission : str + Permission/action name that was decided + approved : bool + Whether the requested permission was approved + reason : Optional[str] + Decision reason, if available + result : Optional[dict[str, Any]] + Host-specific decision result, such as a durable approval token or denial details + """ + + _shorthand_property: ClassVar[str | None] = None + + request_id: str | None = None + tool_call_id: str | None = None + permission: str = field(default="") + approved: bool = field(default=False) + reason: str | None = None + result: dict[str, Any] | None = None + + @staticmethod + def load(data: Any, context: LoadContext | None = None) -> "PermissionDecision": + """Load a PermissionDecision instance. + Args: + data (Any): The data to load the instance from. + context (Optional[LoadContext]): Optional context with pre/post processing callbacks. + Returns: + PermissionDecision: The loaded PermissionDecision instance. + + """ + + if context is not None: + data = context.process_input(data) + + if not isinstance(data, dict): + raise ValueError(f"Invalid data for PermissionDecision: {data}") + + # create new instance + instance = PermissionDecision() + + if data is not None and "requestId" in data: + instance.request_id = data["requestId"] + if data is not None and "toolCallId" in data: + instance.tool_call_id = data["toolCallId"] + if data is not None and "permission" in data: + instance.permission = data["permission"] + if data is not None and "approved" in data: + instance.approved = data["approved"] + if data is not None and "reason" in data: + instance.reason = data["reason"] + if data is not None and "result" in data: + instance.result = data["result"] + if context is not None: + instance = context.process_output(instance) + return instance + + def save(self, context: SaveContext | None = None) -> dict[str, Any]: + """Save the PermissionDecision instance to a dictionary. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + dict[str, Any]: The dictionary representation of this instance. + + """ + obj = self + if context is not None: + obj = context.process_object(obj) + + result: dict[str, Any] = {} + + if obj.request_id is not None: + result["requestId"] = obj.request_id + if obj.tool_call_id is not None: + result["toolCallId"] = obj.tool_call_id + if obj.permission is not None: + result["permission"] = obj.permission + if obj.approved is not None: + result["approved"] = obj.approved + if obj.reason is not None: + result["reason"] = obj.reason + if obj.result is not None: + result["result"] = obj.result + + if context is not None: + result = context.process_dict(result) + return result + + def to_yaml(self, context: SaveContext | None = None) -> str: + """Convert the PermissionDecision instance to a YAML string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + str: The YAML string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_yaml(self.save(context)) + + def to_json(self, context: SaveContext | None = None, indent: int = 2) -> str: + """Convert the PermissionDecision instance to a JSON string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + indent (int): Number of spaces for indentation. Defaults to 2. + Returns: + str: The JSON string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_json(self.save(context), indent) diff --git a/runtime/python/prompty/prompty/model/events/_PermissionRequest.py b/runtime/python/prompty/prompty/model/events/_PermissionRequest.py new file mode 100644 index 00000000..b12bf6b7 --- /dev/null +++ b/runtime/python/prompty/prompty/model/events/_PermissionRequest.py @@ -0,0 +1,140 @@ +########################################## +# WARNING: This is an auto-generated file. +# DO NOT EDIT THIS FILE DIRECTLY +# ANY EDITS WILL BE LOST +########################################## + +from dataclasses import dataclass, field +from typing import Any, ClassVar + +from .._context import LoadContext, SaveContext + + +@dataclass +class PermissionRequest: + """Request passed to a permission resolver. This is the live protocol shape; the + event payloads above can include trace-only metadata such as redaction state. + + Attributes + ---------- + request_id : Optional[str] + Stable permission request identifier + tool_call_id : Optional[str] + Associated tool call identifier, when the permission gates a tool call + permission : str + Permission/action name being requested + target : Optional[str] + Resource or tool the permission applies to + details : Optional[dict[str, Any]] + Additional host-specific permission details + prompt_request : Optional[str] + Human-readable prompt or rationale that can be shown to an approval UI + policy : Optional[dict[str, Any]] + Policy metadata used to evaluate or explain the permission request + """ + + _shorthand_property: ClassVar[str | None] = None + + request_id: str | None = None + tool_call_id: str | None = None + permission: str = field(default="") + target: str | None = None + details: dict[str, Any] | None = None + prompt_request: str | None = None + policy: dict[str, Any] | None = None + + @staticmethod + def load(data: Any, context: LoadContext | None = None) -> "PermissionRequest": + """Load a PermissionRequest instance. + Args: + data (Any): The data to load the instance from. + context (Optional[LoadContext]): Optional context with pre/post processing callbacks. + Returns: + PermissionRequest: The loaded PermissionRequest instance. + + """ + + if context is not None: + data = context.process_input(data) + + if not isinstance(data, dict): + raise ValueError(f"Invalid data for PermissionRequest: {data}") + + # create new instance + instance = PermissionRequest() + + if data is not None and "requestId" in data: + instance.request_id = data["requestId"] + if data is not None and "toolCallId" in data: + instance.tool_call_id = data["toolCallId"] + if data is not None and "permission" in data: + instance.permission = data["permission"] + if data is not None and "target" in data: + instance.target = data["target"] + if data is not None and "details" in data: + instance.details = data["details"] + if data is not None and "promptRequest" in data: + instance.prompt_request = data["promptRequest"] + if data is not None and "policy" in data: + instance.policy = data["policy"] + if context is not None: + instance = context.process_output(instance) + return instance + + def save(self, context: SaveContext | None = None) -> dict[str, Any]: + """Save the PermissionRequest instance to a dictionary. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + dict[str, Any]: The dictionary representation of this instance. + + """ + obj = self + if context is not None: + obj = context.process_object(obj) + + result: dict[str, Any] = {} + + if obj.request_id is not None: + result["requestId"] = obj.request_id + if obj.tool_call_id is not None: + result["toolCallId"] = obj.tool_call_id + if obj.permission is not None: + result["permission"] = obj.permission + if obj.target is not None: + result["target"] = obj.target + if obj.details is not None: + result["details"] = obj.details + if obj.prompt_request is not None: + result["promptRequest"] = obj.prompt_request + if obj.policy is not None: + result["policy"] = obj.policy + + if context is not None: + result = context.process_dict(result) + return result + + def to_yaml(self, context: SaveContext | None = None) -> str: + """Convert the PermissionRequest instance to a YAML string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + str: The YAML string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_yaml(self.save(context)) + + def to_json(self, context: SaveContext | None = None, indent: int = 2) -> str: + """Convert the PermissionRequest instance to a JSON string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + indent (int): Number of spaces for indentation. Defaults to 2. + Returns: + str: The JSON string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_json(self.save(context), indent) diff --git a/runtime/python/prompty/prompty/model/events/_PermissionRequestedPayload.py b/runtime/python/prompty/prompty/model/events/_PermissionRequestedPayload.py index eb2fc9b2..2a4a2ebf 100644 --- a/runtime/python/prompty/prompty/model/events/_PermissionRequestedPayload.py +++ b/runtime/python/prompty/prompty/model/events/_PermissionRequestedPayload.py @@ -8,6 +8,7 @@ from typing import Any, ClassVar from .._context import LoadContext, SaveContext +from ._RedactionMetadata import RedactionMetadata @dataclass @@ -16,19 +17,34 @@ class PermissionRequestedPayload: Attributes ---------- + request_id : Optional[str] + Stable permission request identifier + tool_call_id : Optional[str] + Associated tool call identifier, when the permission gates a tool call permission : str Permission/action name being requested target : Optional[str] Resource or tool the permission applies to details : Optional[dict[str, Any]] Additional host-specific permission details + prompt_request : Optional[str] + Human-readable prompt or rationale that can be shown to an approval UI + policy : Optional[dict[str, Any]] + Policy metadata used to evaluate or explain the permission request + redaction : Optional[RedactionMetadata] + Redaction state for sensitive request fields """ _shorthand_property: ClassVar[str | None] = None + request_id: str | None = None + tool_call_id: str | None = None permission: str = field(default="") target: str | None = None details: dict[str, Any] | None = None + prompt_request: str | None = None + policy: dict[str, Any] | None = None + redaction: RedactionMetadata | None = None @staticmethod def load(data: Any, context: LoadContext | None = None) -> "PermissionRequestedPayload": @@ -50,12 +66,22 @@ def load(data: Any, context: LoadContext | None = None) -> "PermissionRequestedP # create new instance instance = PermissionRequestedPayload() + if data is not None and "requestId" in data: + instance.request_id = data["requestId"] + if data is not None and "toolCallId" in data: + instance.tool_call_id = data["toolCallId"] if data is not None and "permission" in data: instance.permission = data["permission"] if data is not None and "target" in data: instance.target = data["target"] if data is not None and "details" in data: instance.details = data["details"] + if data is not None and "promptRequest" in data: + instance.prompt_request = data["promptRequest"] + if data is not None and "policy" in data: + instance.policy = data["policy"] + if data is not None and "redaction" in data: + instance.redaction = RedactionMetadata.load(data["redaction"], context) if context is not None: instance = context.process_output(instance) return instance @@ -74,12 +100,22 @@ def save(self, context: SaveContext | None = None) -> dict[str, Any]: result: dict[str, Any] = {} + if obj.request_id is not None: + result["requestId"] = obj.request_id + if obj.tool_call_id is not None: + result["toolCallId"] = obj.tool_call_id if obj.permission is not None: result["permission"] = obj.permission if obj.target is not None: result["target"] = obj.target if obj.details is not None: result["details"] = obj.details + if obj.prompt_request is not None: + result["promptRequest"] = obj.prompt_request + if obj.policy is not None: + result["policy"] = obj.policy + if obj.redaction is not None: + result["redaction"] = obj.redaction.save(context) if context is not None: result = context.process_dict(result) diff --git a/runtime/python/prompty/prompty/model/events/_RedactedField.py b/runtime/python/prompty/prompty/model/events/_RedactedField.py new file mode 100644 index 00000000..4ec2a2b2 --- /dev/null +++ b/runtime/python/prompty/prompty/model/events/_RedactedField.py @@ -0,0 +1,113 @@ +########################################## +# WARNING: This is an auto-generated file. +# DO NOT EDIT THIS FILE DIRECTLY +# ANY EDITS WILL BE LOST +########################################## + +from dataclasses import dataclass, field +from typing import Any, ClassVar, Literal + +from .._context import LoadContext, SaveContext + +RedactionMode = Literal["none", "redacted", "hashed", "summary", "reference"] + + +@dataclass +class RedactedField: + """Redaction handling for one JSON-shaped field path. + + Attributes + ---------- + path : str + JSONPath-like field path, relative to the containing payload + mode : str + How the field was represented + reason : Optional[str] + Human-readable reason or policy that caused this handling + """ + + _shorthand_property: ClassVar[str | None] = None + + path: str = field(default="") + mode: RedactionMode = field(default="none") + reason: str | None = None + + @staticmethod + def load(data: Any, context: LoadContext | None = None) -> "RedactedField": + """Load a RedactedField instance. + Args: + data (Any): The data to load the instance from. + context (Optional[LoadContext]): Optional context with pre/post processing callbacks. + Returns: + RedactedField: The loaded RedactedField instance. + + """ + + if context is not None: + data = context.process_input(data) + + if not isinstance(data, dict): + raise ValueError(f"Invalid data for RedactedField: {data}") + + # create new instance + instance = RedactedField() + + if data is not None and "path" in data: + instance.path = data["path"] + if data is not None and "mode" in data: + instance.mode = data["mode"] + if data is not None and "reason" in data: + instance.reason = data["reason"] + if context is not None: + instance = context.process_output(instance) + return instance + + def save(self, context: SaveContext | None = None) -> dict[str, Any]: + """Save the RedactedField instance to a dictionary. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + dict[str, Any]: The dictionary representation of this instance. + + """ + obj = self + if context is not None: + obj = context.process_object(obj) + + result: dict[str, Any] = {} + + if obj.path is not None: + result["path"] = obj.path + if obj.mode is not None: + result["mode"] = obj.mode + if obj.reason is not None: + result["reason"] = obj.reason + + if context is not None: + result = context.process_dict(result) + return result + + def to_yaml(self, context: SaveContext | None = None) -> str: + """Convert the RedactedField instance to a YAML string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + str: The YAML string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_yaml(self.save(context)) + + def to_json(self, context: SaveContext | None = None, indent: int = 2) -> str: + """Convert the RedactedField instance to a JSON string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + indent (int): Number of spaces for indentation. Defaults to 2. + Returns: + str: The JSON string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_json(self.save(context), indent) diff --git a/runtime/python/prompty/prompty/model/events/_RedactionMetadata.py b/runtime/python/prompty/prompty/model/events/_RedactionMetadata.py new file mode 100644 index 00000000..1c16dbfc --- /dev/null +++ b/runtime/python/prompty/prompty/model/events/_RedactionMetadata.py @@ -0,0 +1,135 @@ +########################################## +# WARNING: This is an auto-generated file. +# DO NOT EDIT THIS FILE DIRECTLY +# ANY EDITS WILL BE LOST +########################################## + +from dataclasses import dataclass, field +from typing import Any, ClassVar + +from .._context import LoadContext, SaveContext +from ._RedactedField import RedactedField + + +@dataclass +class RedactionMetadata: + """Metadata describing whether and how a payload was sanitized. + + Attributes + ---------- + sanitized : Optional[bool] + Whether the payload has been sanitized for persistence or external display + fields : Optional[list[RedactedField]] + Field-level redaction details + policy : Optional[str] + Host policy or sanitizer version that produced this metadata + """ + + _shorthand_property: ClassVar[str | None] = None + + sanitized: bool | None = None + fields: list[RedactedField] = field(default_factory=list) + policy: str | None = None + + @staticmethod + def load(data: Any, context: LoadContext | None = None) -> "RedactionMetadata": + """Load a RedactionMetadata instance. + Args: + data (Any): The data to load the instance from. + context (Optional[LoadContext]): Optional context with pre/post processing callbacks. + Returns: + RedactionMetadata: The loaded RedactionMetadata instance. + + """ + + if context is not None: + data = context.process_input(data) + + if not isinstance(data, dict): + raise ValueError(f"Invalid data for RedactionMetadata: {data}") + + # create new instance + instance = RedactionMetadata() + + if data is not None and "sanitized" in data: + instance.sanitized = data["sanitized"] + if data is not None and "fields" in data: + instance.fields = RedactionMetadata.load_fields(data["fields"], context) + if data is not None and "policy" in data: + instance.policy = data["policy"] + if context is not None: + instance = context.process_output(instance) + return instance + + @staticmethod + def load_fields(data: dict | list, context: LoadContext | None) -> list[RedactedField]: + if isinstance(data, dict): + # convert simple named fields to list of RedactedField + result = [] + for k, v in data.items(): + if isinstance(v, dict): + # value is an object, spread its properties + result.append({"name": k, **v}) + else: + # value is a scalar, use it as the primary property + result.append({"name": k, "path": v}) + data = result + return [RedactedField.load(item, context) for item in data] + + @staticmethod + def save_fields(items: list[RedactedField], context: SaveContext | None) -> dict[str, Any] | list[dict[str, Any]]: + if context is None: + context = SaveContext() + + # This type doesn't have a 'name' property, so always use array format + return [item.save(context) for item in items] + + def save(self, context: SaveContext | None = None) -> dict[str, Any]: + """Save the RedactionMetadata instance to a dictionary. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + dict[str, Any]: The dictionary representation of this instance. + + """ + obj = self + if context is not None: + obj = context.process_object(obj) + + result: dict[str, Any] = {} + + if obj.sanitized is not None: + result["sanitized"] = obj.sanitized + if obj.fields is not None: + result["fields"] = RedactionMetadata.save_fields(obj.fields, context) + if obj.policy is not None: + result["policy"] = obj.policy + + if context is not None: + result = context.process_dict(result) + return result + + def to_yaml(self, context: SaveContext | None = None) -> str: + """Convert the RedactionMetadata instance to a YAML string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + str: The YAML string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_yaml(self.save(context)) + + def to_json(self, context: SaveContext | None = None, indent: int = 2) -> str: + """Convert the RedactionMetadata instance to a JSON string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + indent (int): Number of spaces for indentation. Defaults to 2. + Returns: + str: The JSON string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_json(self.save(context), indent) diff --git a/runtime/python/prompty/prompty/model/events/_SessionEndPayload.py b/runtime/python/prompty/prompty/model/events/_SessionEndPayload.py new file mode 100644 index 00000000..9a87cfbf --- /dev/null +++ b/runtime/python/prompty/prompty/model/events/_SessionEndPayload.py @@ -0,0 +1,120 @@ +########################################## +# WARNING: This is an auto-generated file. +# DO NOT EDIT THIS FILE DIRECTLY +# ANY EDITS WILL BE LOST +########################################## + +from dataclasses import dataclass +from typing import Any, ClassVar, Literal + +from .._context import LoadContext, SaveContext + +SessionEndStatus = Literal["success", "error", "cancelled", "interrupted"] + + +@dataclass +class SessionEndPayload: + """Payload for "session_end" events. + + Attributes + ---------- + session_id : Optional[str] + Stable session identifier + status : Optional[str] + Final session status + reason : Optional[str] + Host-specific reason the session ended + duration_ms : Optional[float] + Total elapsed session duration in milliseconds + """ + + _shorthand_property: ClassVar[str | None] = None + + session_id: str | None = None + status: SessionEndStatus | None = None + reason: str | None = None + duration_ms: float | None = None + + @staticmethod + def load(data: Any, context: LoadContext | None = None) -> "SessionEndPayload": + """Load a SessionEndPayload instance. + Args: + data (Any): The data to load the instance from. + context (Optional[LoadContext]): Optional context with pre/post processing callbacks. + Returns: + SessionEndPayload: The loaded SessionEndPayload instance. + + """ + + if context is not None: + data = context.process_input(data) + + if not isinstance(data, dict): + raise ValueError(f"Invalid data for SessionEndPayload: {data}") + + # create new instance + instance = SessionEndPayload() + + if data is not None and "sessionId" in data: + instance.session_id = data["sessionId"] + if data is not None and "status" in data: + instance.status = data["status"] + if data is not None and "reason" in data: + instance.reason = data["reason"] + if data is not None and "durationMs" in data: + instance.duration_ms = data["durationMs"] + if context is not None: + instance = context.process_output(instance) + return instance + + def save(self, context: SaveContext | None = None) -> dict[str, Any]: + """Save the SessionEndPayload instance to a dictionary. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + dict[str, Any]: The dictionary representation of this instance. + + """ + obj = self + if context is not None: + obj = context.process_object(obj) + + result: dict[str, Any] = {} + + if obj.session_id is not None: + result["sessionId"] = obj.session_id + if obj.status is not None: + result["status"] = obj.status + if obj.reason is not None: + result["reason"] = obj.reason + if obj.duration_ms is not None: + result["durationMs"] = obj.duration_ms + + if context is not None: + result = context.process_dict(result) + return result + + def to_yaml(self, context: SaveContext | None = None) -> str: + """Convert the SessionEndPayload instance to a YAML string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + str: The YAML string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_yaml(self.save(context)) + + def to_json(self, context: SaveContext | None = None, indent: int = 2) -> str: + """Convert the SessionEndPayload instance to a JSON string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + indent (int): Number of spaces for indentation. Defaults to 2. + Returns: + str: The JSON string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_json(self.save(context), indent) diff --git a/runtime/python/prompty/prompty/model/events/_SessionEvent.py b/runtime/python/prompty/prompty/model/events/_SessionEvent.py new file mode 100644 index 00000000..242fbd79 --- /dev/null +++ b/runtime/python/prompty/prompty/model/events/_SessionEvent.py @@ -0,0 +1,164 @@ +########################################## +# WARNING: This is an auto-generated file. +# DO NOT EDIT THIS FILE DIRECTLY +# ANY EDITS WILL BE LOST +########################################## + +from dataclasses import dataclass, field +from typing import Any, ClassVar, Literal + +from .._context import LoadContext, SaveContext +from ._RedactionMetadata import RedactionMetadata + +SessionEventType = Literal[ + "session_start", + "session_end", + "session_warning", + "session_hook_start", + "session_hook_end", + "checkpoint_created", + "trajectory_event", +] + + +@dataclass +class SessionEvent: + """A canonical event envelope emitted by an outer harness session. + + Attributes + ---------- + id : str + Unique identifier for this event + type : str + Event type discriminator + timestamp : str + ISO 8601 UTC timestamp when the event was emitted + session_id : Optional[str] + Stable identifier for the outer session + turn_id : Optional[str] + Associated turn identifier, when this session event is linked to a turn + parent_id : Optional[str] + Parent event or span identifier for reconstructing event hierarchy + span_id : Optional[str] + Trace span identifier associated with this event + payload : dict[str, Any] + Event-specific payload. Use the typed payload model matching 'type'. + redaction : Optional[RedactionMetadata] + Redaction state for sensitive payload fields + """ + + _shorthand_property: ClassVar[str | None] = None + + id: str = field(default="") + type: SessionEventType = field(default="session_start") + timestamp: str = field(default="") + session_id: str | None = None + turn_id: str | None = None + parent_id: str | None = None + span_id: str | None = None + payload: dict[str, Any] = field(default_factory=dict) + redaction: RedactionMetadata | None = None + + @staticmethod + def load(data: Any, context: LoadContext | None = None) -> "SessionEvent": + """Load a SessionEvent instance. + Args: + data (Any): The data to load the instance from. + context (Optional[LoadContext]): Optional context with pre/post processing callbacks. + Returns: + SessionEvent: The loaded SessionEvent instance. + + """ + + if context is not None: + data = context.process_input(data) + + if not isinstance(data, dict): + raise ValueError(f"Invalid data for SessionEvent: {data}") + + # create new instance + instance = SessionEvent() + + if data is not None and "id" in data: + instance.id = data["id"] + if data is not None and "type" in data: + instance.type = data["type"] + if data is not None and "timestamp" in data: + instance.timestamp = data["timestamp"] + if data is not None and "sessionId" in data: + instance.session_id = data["sessionId"] + if data is not None and "turnId" in data: + instance.turn_id = data["turnId"] + if data is not None and "parentId" in data: + instance.parent_id = data["parentId"] + if data is not None and "spanId" in data: + instance.span_id = data["spanId"] + if data is not None and "payload" in data: + instance.payload = data["payload"] + if data is not None and "redaction" in data: + instance.redaction = RedactionMetadata.load(data["redaction"], context) + if context is not None: + instance = context.process_output(instance) + return instance + + def save(self, context: SaveContext | None = None) -> dict[str, Any]: + """Save the SessionEvent instance to a dictionary. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + dict[str, Any]: The dictionary representation of this instance. + + """ + obj = self + if context is not None: + obj = context.process_object(obj) + + result: dict[str, Any] = {} + + if obj.id is not None: + result["id"] = obj.id + if obj.type is not None: + result["type"] = obj.type + if obj.timestamp is not None: + result["timestamp"] = obj.timestamp + if obj.session_id is not None: + result["sessionId"] = obj.session_id + if obj.turn_id is not None: + result["turnId"] = obj.turn_id + if obj.parent_id is not None: + result["parentId"] = obj.parent_id + if obj.span_id is not None: + result["spanId"] = obj.span_id + if obj.payload is not None: + result["payload"] = obj.payload + if obj.redaction is not None: + result["redaction"] = obj.redaction.save(context) + + if context is not None: + result = context.process_dict(result) + return result + + def to_yaml(self, context: SaveContext | None = None) -> str: + """Convert the SessionEvent instance to a YAML string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + str: The YAML string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_yaml(self.save(context)) + + def to_json(self, context: SaveContext | None = None, indent: int = 2) -> str: + """Convert the SessionEvent instance to a JSON string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + indent (int): Number of spaces for indentation. Defaults to 2. + Returns: + str: The JSON string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_json(self.save(context), indent) diff --git a/runtime/python/prompty/prompty/model/events/_SessionFileRef.py b/runtime/python/prompty/prompty/model/events/_SessionFileRef.py new file mode 100644 index 00000000..46013203 --- /dev/null +++ b/runtime/python/prompty/prompty/model/events/_SessionFileRef.py @@ -0,0 +1,125 @@ +########################################## +# WARNING: This is an auto-generated file. +# DO NOT EDIT THIS FILE DIRECTLY +# ANY EDITS WILL BE LOST +########################################## + +from dataclasses import dataclass, field +from typing import Any, ClassVar + +from .._context import LoadContext, SaveContext + + +@dataclass +class SessionFileRef: + """A file observed or touched by a harness session. + + Attributes + ---------- + session_id : Optional[str] + Stable session identifier + path : str + File path, relative to the harness workspace when possible + tool_name : Optional[str] + Tool that first observed the file, when known + turn_index : Optional[int] + Zero-based turn index where the file was first observed + first_seen_at : Optional[str] + ISO 8601 UTC timestamp when the file was first observed + """ + + _shorthand_property: ClassVar[str | None] = None + + session_id: str | None = None + path: str = field(default="") + tool_name: str | None = None + turn_index: int | None = None + first_seen_at: str | None = None + + @staticmethod + def load(data: Any, context: LoadContext | None = None) -> "SessionFileRef": + """Load a SessionFileRef instance. + Args: + data (Any): The data to load the instance from. + context (Optional[LoadContext]): Optional context with pre/post processing callbacks. + Returns: + SessionFileRef: The loaded SessionFileRef instance. + + """ + + if context is not None: + data = context.process_input(data) + + if not isinstance(data, dict): + raise ValueError(f"Invalid data for SessionFileRef: {data}") + + # create new instance + instance = SessionFileRef() + + if data is not None and "sessionId" in data: + instance.session_id = data["sessionId"] + if data is not None and "path" in data: + instance.path = data["path"] + if data is not None and "toolName" in data: + instance.tool_name = data["toolName"] + if data is not None and "turnIndex" in data: + instance.turn_index = data["turnIndex"] + if data is not None and "firstSeenAt" in data: + instance.first_seen_at = data["firstSeenAt"] + if context is not None: + instance = context.process_output(instance) + return instance + + def save(self, context: SaveContext | None = None) -> dict[str, Any]: + """Save the SessionFileRef instance to a dictionary. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + dict[str, Any]: The dictionary representation of this instance. + + """ + obj = self + if context is not None: + obj = context.process_object(obj) + + result: dict[str, Any] = {} + + if obj.session_id is not None: + result["sessionId"] = obj.session_id + if obj.path is not None: + result["path"] = obj.path + if obj.tool_name is not None: + result["toolName"] = obj.tool_name + if obj.turn_index is not None: + result["turnIndex"] = obj.turn_index + if obj.first_seen_at is not None: + result["firstSeenAt"] = obj.first_seen_at + + if context is not None: + result = context.process_dict(result) + return result + + def to_yaml(self, context: SaveContext | None = None) -> str: + """Convert the SessionFileRef instance to a YAML string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + str: The YAML string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_yaml(self.save(context)) + + def to_json(self, context: SaveContext | None = None, indent: int = 2) -> str: + """Convert the SessionFileRef instance to a JSON string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + indent (int): Number of spaces for indentation. Defaults to 2. + Returns: + str: The JSON string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_json(self.save(context), indent) diff --git a/runtime/python/prompty/prompty/model/events/_SessionRef.py b/runtime/python/prompty/prompty/model/events/_SessionRef.py new file mode 100644 index 00000000..720a3167 --- /dev/null +++ b/runtime/python/prompty/prompty/model/events/_SessionRef.py @@ -0,0 +1,125 @@ +########################################## +# WARNING: This is an auto-generated file. +# DO NOT EDIT THIS FILE DIRECTLY +# ANY EDITS WILL BE LOST +########################################## + +from dataclasses import dataclass, field +from typing import Any, ClassVar + +from .._context import LoadContext, SaveContext + + +@dataclass +class SessionRef: + """A non-file reference observed by a harness session. + + Attributes + ---------- + session_id : Optional[str] + Stable session identifier + ref_type : str + Reference category + ref_value : str + Reference value + turn_index : Optional[int] + Zero-based turn index where the reference was first observed + created_at : Optional[str] + ISO 8601 UTC timestamp when the reference was recorded + """ + + _shorthand_property: ClassVar[str | None] = None + + session_id: str | None = None + ref_type: str = field(default="") + ref_value: str = field(default="") + turn_index: int | None = None + created_at: str | None = None + + @staticmethod + def load(data: Any, context: LoadContext | None = None) -> "SessionRef": + """Load a SessionRef instance. + Args: + data (Any): The data to load the instance from. + context (Optional[LoadContext]): Optional context with pre/post processing callbacks. + Returns: + SessionRef: The loaded SessionRef instance. + + """ + + if context is not None: + data = context.process_input(data) + + if not isinstance(data, dict): + raise ValueError(f"Invalid data for SessionRef: {data}") + + # create new instance + instance = SessionRef() + + if data is not None and "sessionId" in data: + instance.session_id = data["sessionId"] + if data is not None and "refType" in data: + instance.ref_type = data["refType"] + if data is not None and "refValue" in data: + instance.ref_value = data["refValue"] + if data is not None and "turnIndex" in data: + instance.turn_index = data["turnIndex"] + if data is not None and "createdAt" in data: + instance.created_at = data["createdAt"] + if context is not None: + instance = context.process_output(instance) + return instance + + def save(self, context: SaveContext | None = None) -> dict[str, Any]: + """Save the SessionRef instance to a dictionary. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + dict[str, Any]: The dictionary representation of this instance. + + """ + obj = self + if context is not None: + obj = context.process_object(obj) + + result: dict[str, Any] = {} + + if obj.session_id is not None: + result["sessionId"] = obj.session_id + if obj.ref_type is not None: + result["refType"] = obj.ref_type + if obj.ref_value is not None: + result["refValue"] = obj.ref_value + if obj.turn_index is not None: + result["turnIndex"] = obj.turn_index + if obj.created_at is not None: + result["createdAt"] = obj.created_at + + if context is not None: + result = context.process_dict(result) + return result + + def to_yaml(self, context: SaveContext | None = None) -> str: + """Convert the SessionRef instance to a YAML string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + str: The YAML string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_yaml(self.save(context)) + + def to_json(self, context: SaveContext | None = None, indent: int = 2) -> str: + """Convert the SessionRef instance to a JSON string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + indent (int): Number of spaces for indentation. Defaults to 2. + Returns: + str: The JSON string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_json(self.save(context), indent) diff --git a/runtime/python/prompty/prompty/model/events/_SessionStartPayload.py b/runtime/python/prompty/prompty/model/events/_SessionStartPayload.py new file mode 100644 index 00000000..0a22e953 --- /dev/null +++ b/runtime/python/prompty/prompty/model/events/_SessionStartPayload.py @@ -0,0 +1,154 @@ +########################################## +# WARNING: This is an auto-generated file. +# DO NOT EDIT THIS FILE DIRECTLY +# ANY EDITS WILL BE LOST +########################################## + +from dataclasses import dataclass, field +from typing import Any, ClassVar + +from .._context import LoadContext, SaveContext +from ._HarnessContext import HarnessContext + + +@dataclass +class SessionStartPayload: + """Payload for "session_start" events. + + Attributes + ---------- + session_id : str + Stable session identifier + version : Optional[int] + Session event schema version + producer : Optional[str] + Producer that started the session + runtime : Optional[str] + Runtime that produced the session + prompty_version : Optional[str] + Prompty library version + start_time : Optional[str] + ISO 8601 UTC timestamp when the session started + selected_model : Optional[str] + Selected model identifier, when known + reasoning_effort : Optional[str] + Selected reasoning effort or equivalent model setting, when known + context : Optional[HarnessContext] + Repository and execution context + """ + + _shorthand_property: ClassVar[str | None] = None + + session_id: str = field(default="") + version: int | None = None + producer: str | None = None + runtime: str | None = None + prompty_version: str | None = None + start_time: str | None = None + selected_model: str | None = None + reasoning_effort: str | None = None + context: HarnessContext | None = None + + @staticmethod + def load(data: Any, context: LoadContext | None = None) -> "SessionStartPayload": + """Load a SessionStartPayload instance. + Args: + data (Any): The data to load the instance from. + context (Optional[LoadContext]): Optional context with pre/post processing callbacks. + Returns: + SessionStartPayload: The loaded SessionStartPayload instance. + + """ + + if context is not None: + data = context.process_input(data) + + if not isinstance(data, dict): + raise ValueError(f"Invalid data for SessionStartPayload: {data}") + + # create new instance + instance = SessionStartPayload() + + if data is not None and "sessionId" in data: + instance.session_id = data["sessionId"] + if data is not None and "version" in data: + instance.version = data["version"] + if data is not None and "producer" in data: + instance.producer = data["producer"] + if data is not None and "runtime" in data: + instance.runtime = data["runtime"] + if data is not None and "promptyVersion" in data: + instance.prompty_version = data["promptyVersion"] + if data is not None and "startTime" in data: + instance.start_time = data["startTime"] + if data is not None and "selectedModel" in data: + instance.selected_model = data["selectedModel"] + if data is not None and "reasoningEffort" in data: + instance.reasoning_effort = data["reasoningEffort"] + if data is not None and "context" in data: + instance.context = HarnessContext.load(data["context"], context) + if context is not None: + instance = context.process_output(instance) + return instance + + def save(self, context: SaveContext | None = None) -> dict[str, Any]: + """Save the SessionStartPayload instance to a dictionary. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + dict[str, Any]: The dictionary representation of this instance. + + """ + obj = self + if context is not None: + obj = context.process_object(obj) + + result: dict[str, Any] = {} + + if obj.session_id is not None: + result["sessionId"] = obj.session_id + if obj.version is not None: + result["version"] = obj.version + if obj.producer is not None: + result["producer"] = obj.producer + if obj.runtime is not None: + result["runtime"] = obj.runtime + if obj.prompty_version is not None: + result["promptyVersion"] = obj.prompty_version + if obj.start_time is not None: + result["startTime"] = obj.start_time + if obj.selected_model is not None: + result["selectedModel"] = obj.selected_model + if obj.reasoning_effort is not None: + result["reasoningEffort"] = obj.reasoning_effort + if obj.context is not None: + result["context"] = obj.context.save(context) + + if context is not None: + result = context.process_dict(result) + return result + + def to_yaml(self, context: SaveContext | None = None) -> str: + """Convert the SessionStartPayload instance to a YAML string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + str: The YAML string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_yaml(self.save(context)) + + def to_json(self, context: SaveContext | None = None, indent: int = 2) -> str: + """Convert the SessionStartPayload instance to a JSON string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + indent (int): Number of spaces for indentation. Defaults to 2. + Returns: + str: The JSON string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_json(self.save(context), indent) diff --git a/runtime/python/prompty/prompty/model/events/_SessionSummary.py b/runtime/python/prompty/prompty/model/events/_SessionSummary.py new file mode 100644 index 00000000..c2e98c33 --- /dev/null +++ b/runtime/python/prompty/prompty/model/events/_SessionSummary.py @@ -0,0 +1,135 @@ +########################################## +# WARNING: This is an auto-generated file. +# DO NOT EDIT THIS FILE DIRECTLY +# ANY EDITS WILL BE LOST +########################################## + +from dataclasses import dataclass, field +from typing import Any, ClassVar, Literal + +from .._context import LoadContext, SaveContext +from ..model._TokenUsage import TokenUsage + +SessionSummaryStatus = Literal["success", "error", "cancelled", "interrupted"] + + +@dataclass +class SessionSummary: + """Summary statistics for a completed session trace. + + Attributes + ---------- + session_id : str + Stable session identifier + status : Optional[str] + Final session status + turns : Optional[int] + Number of user/assistant turns in the session + checkpoints : Optional[int] + Number of checkpoints created + usage : Optional[TokenUsage] + Aggregated token usage for the session + duration_ms : Optional[float] + Total elapsed session duration in milliseconds + """ + + _shorthand_property: ClassVar[str | None] = None + + session_id: str = field(default="") + status: SessionSummaryStatus | None = None + turns: int | None = None + checkpoints: int | None = None + usage: TokenUsage | None = None + duration_ms: float | None = None + + @staticmethod + def load(data: Any, context: LoadContext | None = None) -> "SessionSummary": + """Load a SessionSummary instance. + Args: + data (Any): The data to load the instance from. + context (Optional[LoadContext]): Optional context with pre/post processing callbacks. + Returns: + SessionSummary: The loaded SessionSummary instance. + + """ + + if context is not None: + data = context.process_input(data) + + if not isinstance(data, dict): + raise ValueError(f"Invalid data for SessionSummary: {data}") + + # create new instance + instance = SessionSummary() + + if data is not None and "sessionId" in data: + instance.session_id = data["sessionId"] + if data is not None and "status" in data: + instance.status = data["status"] + if data is not None and "turns" in data: + instance.turns = data["turns"] + if data is not None and "checkpoints" in data: + instance.checkpoints = data["checkpoints"] + if data is not None and "usage" in data: + instance.usage = TokenUsage.load(data["usage"], context) + if data is not None and "durationMs" in data: + instance.duration_ms = data["durationMs"] + if context is not None: + instance = context.process_output(instance) + return instance + + def save(self, context: SaveContext | None = None) -> dict[str, Any]: + """Save the SessionSummary instance to a dictionary. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + dict[str, Any]: The dictionary representation of this instance. + + """ + obj = self + if context is not None: + obj = context.process_object(obj) + + result: dict[str, Any] = {} + + if obj.session_id is not None: + result["sessionId"] = obj.session_id + if obj.status is not None: + result["status"] = obj.status + if obj.turns is not None: + result["turns"] = obj.turns + if obj.checkpoints is not None: + result["checkpoints"] = obj.checkpoints + if obj.usage is not None: + result["usage"] = obj.usage.save(context) + if obj.duration_ms is not None: + result["durationMs"] = obj.duration_ms + + if context is not None: + result = context.process_dict(result) + return result + + def to_yaml(self, context: SaveContext | None = None) -> str: + """Convert the SessionSummary instance to a YAML string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + str: The YAML string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_yaml(self.save(context)) + + def to_json(self, context: SaveContext | None = None, indent: int = 2) -> str: + """Convert the SessionSummary instance to a JSON string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + indent (int): Number of spaces for indentation. Defaults to 2. + Returns: + str: The JSON string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_json(self.save(context), indent) diff --git a/runtime/python/prompty/prompty/model/events/_SessionTrace.py b/runtime/python/prompty/prompty/model/events/_SessionTrace.py new file mode 100644 index 00000000..8457af1c --- /dev/null +++ b/runtime/python/prompty/prompty/model/events/_SessionTrace.py @@ -0,0 +1,314 @@ +########################################## +# WARNING: This is an auto-generated file. +# DO NOT EDIT THIS FILE DIRECTLY +# ANY EDITS WILL BE LOST +########################################## + +from dataclasses import dataclass, field +from typing import Any, ClassVar + +from .._context import LoadContext, SaveContext +from ._Checkpoint import Checkpoint +from ._SessionEvent import SessionEvent +from ._SessionFileRef import SessionFileRef +from ._SessionRef import SessionRef +from ._SessionSummary import SessionSummary +from ._TrajectoryEvent import TrajectoryEvent +from ._TurnTrace import TurnTrace + + +@dataclass +class SessionTrace: + """Portable replay container for an outer harness session. + + Attributes + ---------- + version : str + Trace schema version + runtime : Optional[str] + Runtime name that produced the trace + prompty_version : Optional[str] + Prompty library version that produced the trace + session_id : Optional[str] + Stable session identifier + events : list[SessionEvent] + Recorded session events in emission order + turns : Optional[list[TurnTrace]] + Recorded turn traces associated with the session + checkpoints : Optional[list[Checkpoint]] + Checkpoints created during the session + trajectory : Optional[list[TrajectoryEvent]] + Compact trajectory records associated with the session + files : Optional[list[SessionFileRef]] + Files observed or touched during the session + refs : Optional[list[SessionRef]] + Non-file references observed during the session + summary : Optional[SessionSummary] + Optional summary computed from the event stream + """ + + _shorthand_property: ClassVar[str | None] = None + + version: str = field(default="1") + runtime: str | None = None + prompty_version: str | None = None + session_id: str | None = None + events: list[SessionEvent] = field(default_factory=list) + turns: list[TurnTrace] = field(default_factory=list) + checkpoints: list[Checkpoint] = field(default_factory=list) + trajectory: list[TrajectoryEvent] = field(default_factory=list) + files: list[SessionFileRef] = field(default_factory=list) + refs: list[SessionRef] = field(default_factory=list) + summary: SessionSummary | None = None + + @staticmethod + def load(data: Any, context: LoadContext | None = None) -> "SessionTrace": + """Load a SessionTrace instance. + Args: + data (Any): The data to load the instance from. + context (Optional[LoadContext]): Optional context with pre/post processing callbacks. + Returns: + SessionTrace: The loaded SessionTrace instance. + + """ + + if context is not None: + data = context.process_input(data) + + if not isinstance(data, dict): + raise ValueError(f"Invalid data for SessionTrace: {data}") + + # create new instance + instance = SessionTrace() + + if data is not None and "version" in data: + instance.version = data["version"] + if data is not None and "runtime" in data: + instance.runtime = data["runtime"] + if data is not None and "promptyVersion" in data: + instance.prompty_version = data["promptyVersion"] + if data is not None and "sessionId" in data: + instance.session_id = data["sessionId"] + if data is not None and "events" in data: + instance.events = SessionTrace.load_events(data["events"], context) + if data is not None and "turns" in data: + instance.turns = SessionTrace.load_turns(data["turns"], context) + if data is not None and "checkpoints" in data: + instance.checkpoints = SessionTrace.load_checkpoints(data["checkpoints"], context) + if data is not None and "trajectory" in data: + instance.trajectory = SessionTrace.load_trajectory(data["trajectory"], context) + if data is not None and "files" in data: + instance.files = SessionTrace.load_files(data["files"], context) + if data is not None and "refs" in data: + instance.refs = SessionTrace.load_refs(data["refs"], context) + if data is not None and "summary" in data: + instance.summary = SessionSummary.load(data["summary"], context) + if context is not None: + instance = context.process_output(instance) + return instance + + @staticmethod + def load_events(data: dict | list, context: LoadContext | None) -> list[SessionEvent]: + if isinstance(data, dict): + # convert simple named events to list of SessionEvent + result = [] + for k, v in data.items(): + if isinstance(v, dict): + # value is an object, spread its properties + result.append({"name": k, **v}) + else: + # value is a scalar, use it as the primary property + result.append({"name": k, "id": v}) + data = result + return [SessionEvent.load(item, context) for item in data] + + @staticmethod + def save_events(items: list[SessionEvent], context: SaveContext | None) -> dict[str, Any] | list[dict[str, Any]]: + if context is None: + context = SaveContext() + + # This type doesn't have a 'name' property, so always use array format + return [item.save(context) for item in items] + + @staticmethod + def load_turns(data: dict | list, context: LoadContext | None) -> list[TurnTrace]: + if isinstance(data, dict): + # convert simple named turns to list of TurnTrace + result = [] + for k, v in data.items(): + if isinstance(v, dict): + # value is an object, spread its properties + result.append({"name": k, **v}) + else: + # value is a scalar, use it as the primary property + result.append({"name": k, "version": v}) + data = result + return [TurnTrace.load(item, context) for item in data] + + @staticmethod + def save_turns(items: list[TurnTrace], context: SaveContext | None) -> dict[str, Any] | list[dict[str, Any]]: + if context is None: + context = SaveContext() + + # This type doesn't have a 'name' property, so always use array format + return [item.save(context) for item in items] + + @staticmethod + def load_checkpoints(data: dict | list, context: LoadContext | None) -> list[Checkpoint]: + if isinstance(data, dict): + # convert simple named checkpoints to list of Checkpoint + result = [] + for k, v in data.items(): + if isinstance(v, dict): + # value is an object, spread its properties + result.append({"name": k, **v}) + else: + # value is a scalar, use it as the primary property + result.append({"name": k, "id": v}) + data = result + return [Checkpoint.load(item, context) for item in data] + + @staticmethod + def save_checkpoints(items: list[Checkpoint], context: SaveContext | None) -> dict[str, Any] | list[dict[str, Any]]: + if context is None: + context = SaveContext() + + # This type doesn't have a 'name' property, so always use array format + return [item.save(context) for item in items] + + @staticmethod + def load_trajectory(data: dict | list, context: LoadContext | None) -> list[TrajectoryEvent]: + if isinstance(data, dict): + # convert simple named trajectory to list of TrajectoryEvent + result = [] + for k, v in data.items(): + if isinstance(v, dict): + # value is an object, spread its properties + result.append({"name": k, **v}) + else: + # value is a scalar, use it as the primary property + result.append({"name": k, "id": v}) + data = result + return [TrajectoryEvent.load(item, context) for item in data] + + @staticmethod + def save_trajectory( + items: list[TrajectoryEvent], context: SaveContext | None + ) -> dict[str, Any] | list[dict[str, Any]]: + if context is None: + context = SaveContext() + + # This type doesn't have a 'name' property, so always use array format + return [item.save(context) for item in items] + + @staticmethod + def load_files(data: dict | list, context: LoadContext | None) -> list[SessionFileRef]: + if isinstance(data, dict): + # convert simple named files to list of SessionFileRef + result = [] + for k, v in data.items(): + if isinstance(v, dict): + # value is an object, spread its properties + result.append({"name": k, **v}) + else: + # value is a scalar, use it as the primary property + result.append({"name": k, "sessionId": v}) + data = result + return [SessionFileRef.load(item, context) for item in data] + + @staticmethod + def save_files(items: list[SessionFileRef], context: SaveContext | None) -> dict[str, Any] | list[dict[str, Any]]: + if context is None: + context = SaveContext() + + # This type doesn't have a 'name' property, so always use array format + return [item.save(context) for item in items] + + @staticmethod + def load_refs(data: dict | list, context: LoadContext | None) -> list[SessionRef]: + if isinstance(data, dict): + # convert simple named refs to list of SessionRef + result = [] + for k, v in data.items(): + if isinstance(v, dict): + # value is an object, spread its properties + result.append({"name": k, **v}) + else: + # value is a scalar, use it as the primary property + result.append({"name": k, "sessionId": v}) + data = result + return [SessionRef.load(item, context) for item in data] + + @staticmethod + def save_refs(items: list[SessionRef], context: SaveContext | None) -> dict[str, Any] | list[dict[str, Any]]: + if context is None: + context = SaveContext() + + # This type doesn't have a 'name' property, so always use array format + return [item.save(context) for item in items] + + def save(self, context: SaveContext | None = None) -> dict[str, Any]: + """Save the SessionTrace instance to a dictionary. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + dict[str, Any]: The dictionary representation of this instance. + + """ + obj = self + if context is not None: + obj = context.process_object(obj) + + result: dict[str, Any] = {} + + if obj.version is not None: + result["version"] = obj.version + if obj.runtime is not None: + result["runtime"] = obj.runtime + if obj.prompty_version is not None: + result["promptyVersion"] = obj.prompty_version + if obj.session_id is not None: + result["sessionId"] = obj.session_id + if obj.events is not None: + result["events"] = SessionTrace.save_events(obj.events, context) + if obj.turns is not None: + result["turns"] = SessionTrace.save_turns(obj.turns, context) + if obj.checkpoints is not None: + result["checkpoints"] = SessionTrace.save_checkpoints(obj.checkpoints, context) + if obj.trajectory is not None: + result["trajectory"] = SessionTrace.save_trajectory(obj.trajectory, context) + if obj.files is not None: + result["files"] = SessionTrace.save_files(obj.files, context) + if obj.refs is not None: + result["refs"] = SessionTrace.save_refs(obj.refs, context) + if obj.summary is not None: + result["summary"] = obj.summary.save(context) + + if context is not None: + result = context.process_dict(result) + return result + + def to_yaml(self, context: SaveContext | None = None) -> str: + """Convert the SessionTrace instance to a YAML string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + str: The YAML string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_yaml(self.save(context)) + + def to_json(self, context: SaveContext | None = None, indent: int = 2) -> str: + """Convert the SessionTrace instance to a JSON string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + indent (int): Number of spaces for indentation. Defaults to 2. + Returns: + str: The JSON string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_json(self.save(context), indent) diff --git a/runtime/python/prompty/prompty/model/events/_SessionWarningPayload.py b/runtime/python/prompty/prompty/model/events/_SessionWarningPayload.py new file mode 100644 index 00000000..e0a573e9 --- /dev/null +++ b/runtime/python/prompty/prompty/model/events/_SessionWarningPayload.py @@ -0,0 +1,111 @@ +########################################## +# WARNING: This is an auto-generated file. +# DO NOT EDIT THIS FILE DIRECTLY +# ANY EDITS WILL BE LOST +########################################## + +from dataclasses import dataclass, field +from typing import Any, ClassVar + +from .._context import LoadContext, SaveContext + + +@dataclass +class SessionWarningPayload: + """Payload for "session_warning" events. + + Attributes + ---------- + warning_type : str + Stable machine-readable warning category + message : str + Human-readable warning message + details : Optional[dict[str, Any]] + Additional host-specific warning details + """ + + _shorthand_property: ClassVar[str | None] = None + + warning_type: str = field(default="") + message: str = field(default="") + details: dict[str, Any] | None = None + + @staticmethod + def load(data: Any, context: LoadContext | None = None) -> "SessionWarningPayload": + """Load a SessionWarningPayload instance. + Args: + data (Any): The data to load the instance from. + context (Optional[LoadContext]): Optional context with pre/post processing callbacks. + Returns: + SessionWarningPayload: The loaded SessionWarningPayload instance. + + """ + + if context is not None: + data = context.process_input(data) + + if not isinstance(data, dict): + raise ValueError(f"Invalid data for SessionWarningPayload: {data}") + + # create new instance + instance = SessionWarningPayload() + + if data is not None and "warningType" in data: + instance.warning_type = data["warningType"] + if data is not None and "message" in data: + instance.message = data["message"] + if data is not None and "details" in data: + instance.details = data["details"] + if context is not None: + instance = context.process_output(instance) + return instance + + def save(self, context: SaveContext | None = None) -> dict[str, Any]: + """Save the SessionWarningPayload instance to a dictionary. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + dict[str, Any]: The dictionary representation of this instance. + + """ + obj = self + if context is not None: + obj = context.process_object(obj) + + result: dict[str, Any] = {} + + if obj.warning_type is not None: + result["warningType"] = obj.warning_type + if obj.message is not None: + result["message"] = obj.message + if obj.details is not None: + result["details"] = obj.details + + if context is not None: + result = context.process_dict(result) + return result + + def to_yaml(self, context: SaveContext | None = None) -> str: + """Convert the SessionWarningPayload instance to a YAML string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + str: The YAML string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_yaml(self.save(context)) + + def to_json(self, context: SaveContext | None = None, indent: int = 2) -> str: + """Convert the SessionWarningPayload instance to a JSON string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + indent (int): Number of spaces for indentation. Defaults to 2. + Returns: + str: The JSON string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_json(self.save(context), indent) diff --git a/runtime/python/prompty/prompty/model/events/_ToolExecutionCompletePayload.py b/runtime/python/prompty/prompty/model/events/_ToolExecutionCompletePayload.py new file mode 100644 index 00000000..bcb9211f --- /dev/null +++ b/runtime/python/prompty/prompty/model/events/_ToolExecutionCompletePayload.py @@ -0,0 +1,161 @@ +########################################## +# WARNING: This is an auto-generated file. +# DO NOT EDIT THIS FILE DIRECTLY +# ANY EDITS WILL BE LOST +########################################## + +from dataclasses import dataclass, field +from typing import Any, ClassVar + +from .._context import LoadContext, SaveContext +from ._RedactionMetadata import RedactionMetadata + + +@dataclass +class ToolExecutionCompletePayload: + """Payload for "tool_execution_complete" events — a concrete host tool execution finished. + + Attributes + ---------- + request_id : Optional[str] + Stable host execution request identifier + tool_call_id : Optional[str] + Associated model tool call identifier, when available + tool_name : str + Name of the host tool that executed + success : bool + Whether the host execution completed successfully + result : Optional[Any] + Host-normalized execution result + exit_code : Optional[int] + Process or host exit code, when applicable + duration_ms : Optional[float] + Tool execution duration in milliseconds + error_kind : Optional[str] + Machine-readable error category when success is false + telemetry : Optional[dict[str, Any]] + Host-specific telemetry for the execution + redaction : Optional[RedactionMetadata] + Redaction state for sensitive result fields + """ + + _shorthand_property: ClassVar[str | None] = None + + request_id: str | None = None + tool_call_id: str | None = None + tool_name: str = field(default="") + success: bool = field(default=False) + result: Any | None = None + exit_code: int | None = None + duration_ms: float | None = None + error_kind: str | None = None + telemetry: dict[str, Any] | None = None + redaction: RedactionMetadata | None = None + + @staticmethod + def load(data: Any, context: LoadContext | None = None) -> "ToolExecutionCompletePayload": + """Load a ToolExecutionCompletePayload instance. + Args: + data (Any): The data to load the instance from. + context (Optional[LoadContext]): Optional context with pre/post processing callbacks. + Returns: + ToolExecutionCompletePayload: The loaded ToolExecutionCompletePayload instance. + + """ + + if context is not None: + data = context.process_input(data) + + if not isinstance(data, dict): + raise ValueError(f"Invalid data for ToolExecutionCompletePayload: {data}") + + # create new instance + instance = ToolExecutionCompletePayload() + + if data is not None and "requestId" in data: + instance.request_id = data["requestId"] + if data is not None and "toolCallId" in data: + instance.tool_call_id = data["toolCallId"] + if data is not None and "toolName" in data: + instance.tool_name = data["toolName"] + if data is not None and "success" in data: + instance.success = data["success"] + if data is not None and "result" in data: + instance.result = data["result"] + if data is not None and "exitCode" in data: + instance.exit_code = data["exitCode"] + if data is not None and "durationMs" in data: + instance.duration_ms = data["durationMs"] + if data is not None and "errorKind" in data: + instance.error_kind = data["errorKind"] + if data is not None and "telemetry" in data: + instance.telemetry = data["telemetry"] + if data is not None and "redaction" in data: + instance.redaction = RedactionMetadata.load(data["redaction"], context) + if context is not None: + instance = context.process_output(instance) + return instance + + def save(self, context: SaveContext | None = None) -> dict[str, Any]: + """Save the ToolExecutionCompletePayload instance to a dictionary. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + dict[str, Any]: The dictionary representation of this instance. + + """ + obj = self + if context is not None: + obj = context.process_object(obj) + + result: dict[str, Any] = {} + + if obj.request_id is not None: + result["requestId"] = obj.request_id + if obj.tool_call_id is not None: + result["toolCallId"] = obj.tool_call_id + if obj.tool_name is not None: + result["toolName"] = obj.tool_name + if obj.success is not None: + result["success"] = obj.success + if obj.result is not None: + result["result"] = obj.result + if obj.exit_code is not None: + result["exitCode"] = obj.exit_code + if obj.duration_ms is not None: + result["durationMs"] = obj.duration_ms + if obj.error_kind is not None: + result["errorKind"] = obj.error_kind + if obj.telemetry is not None: + result["telemetry"] = obj.telemetry + if obj.redaction is not None: + result["redaction"] = obj.redaction.save(context) + + if context is not None: + result = context.process_dict(result) + return result + + def to_yaml(self, context: SaveContext | None = None) -> str: + """Convert the ToolExecutionCompletePayload instance to a YAML string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + str: The YAML string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_yaml(self.save(context)) + + def to_json(self, context: SaveContext | None = None, indent: int = 2) -> str: + """Convert the ToolExecutionCompletePayload instance to a JSON string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + indent (int): Number of spaces for indentation. Defaults to 2. + Returns: + str: The JSON string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_json(self.save(context), indent) diff --git a/runtime/python/prompty/prompty/model/events/_ToolExecutionStartPayload.py b/runtime/python/prompty/prompty/model/events/_ToolExecutionStartPayload.py new file mode 100644 index 00000000..f6517386 --- /dev/null +++ b/runtime/python/prompty/prompty/model/events/_ToolExecutionStartPayload.py @@ -0,0 +1,136 @@ +########################################## +# WARNING: This is an auto-generated file. +# DO NOT EDIT THIS FILE DIRECTLY +# ANY EDITS WILL BE LOST +########################################## + +from dataclasses import dataclass, field +from typing import Any, ClassVar + +from .._context import LoadContext, SaveContext +from ._RedactionMetadata import RedactionMetadata + + +@dataclass +class ToolExecutionStartPayload: + """Payload for "tool_execution_start" events — the host is about to execute a concrete tool request. + + This is distinct from "tool_call_start", which records the model requesting a tool. + Tool execution events capture the harness-side action after policy and permission checks. + + Attributes + ---------- + request_id : Optional[str] + Stable host execution request identifier + tool_call_id : Optional[str] + Associated model tool call identifier, when available + tool_name : str + Name of the host tool being executed + arguments : Optional[dict[str, Any]] + Tool arguments after host-side sanitization + working_directory : Optional[str] + Working directory or execution scope for the tool + redaction : Optional[RedactionMetadata] + Redaction state for sensitive argument fields + """ + + _shorthand_property: ClassVar[str | None] = None + + request_id: str | None = None + tool_call_id: str | None = None + tool_name: str = field(default="") + arguments: dict[str, Any] | None = None + working_directory: str | None = None + redaction: RedactionMetadata | None = None + + @staticmethod + def load(data: Any, context: LoadContext | None = None) -> "ToolExecutionStartPayload": + """Load a ToolExecutionStartPayload instance. + Args: + data (Any): The data to load the instance from. + context (Optional[LoadContext]): Optional context with pre/post processing callbacks. + Returns: + ToolExecutionStartPayload: The loaded ToolExecutionStartPayload instance. + + """ + + if context is not None: + data = context.process_input(data) + + if not isinstance(data, dict): + raise ValueError(f"Invalid data for ToolExecutionStartPayload: {data}") + + # create new instance + instance = ToolExecutionStartPayload() + + if data is not None and "requestId" in data: + instance.request_id = data["requestId"] + if data is not None and "toolCallId" in data: + instance.tool_call_id = data["toolCallId"] + if data is not None and "toolName" in data: + instance.tool_name = data["toolName"] + if data is not None and "arguments" in data: + instance.arguments = data["arguments"] + if data is not None and "workingDirectory" in data: + instance.working_directory = data["workingDirectory"] + if data is not None and "redaction" in data: + instance.redaction = RedactionMetadata.load(data["redaction"], context) + if context is not None: + instance = context.process_output(instance) + return instance + + def save(self, context: SaveContext | None = None) -> dict[str, Any]: + """Save the ToolExecutionStartPayload instance to a dictionary. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + dict[str, Any]: The dictionary representation of this instance. + + """ + obj = self + if context is not None: + obj = context.process_object(obj) + + result: dict[str, Any] = {} + + if obj.request_id is not None: + result["requestId"] = obj.request_id + if obj.tool_call_id is not None: + result["toolCallId"] = obj.tool_call_id + if obj.tool_name is not None: + result["toolName"] = obj.tool_name + if obj.arguments is not None: + result["arguments"] = obj.arguments + if obj.working_directory is not None: + result["workingDirectory"] = obj.working_directory + if obj.redaction is not None: + result["redaction"] = obj.redaction.save(context) + + if context is not None: + result = context.process_dict(result) + return result + + def to_yaml(self, context: SaveContext | None = None) -> str: + """Convert the ToolExecutionStartPayload instance to a YAML string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + str: The YAML string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_yaml(self.save(context)) + + def to_json(self, context: SaveContext | None = None, indent: int = 2) -> str: + """Convert the ToolExecutionStartPayload instance to a JSON string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + indent (int): Number of spaces for indentation. Defaults to 2. + Returns: + str: The JSON string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_json(self.save(context), indent) diff --git a/runtime/python/prompty/prompty/model/events/_TrajectoryEvent.py b/runtime/python/prompty/prompty/model/events/_TrajectoryEvent.py new file mode 100644 index 00000000..71a2ddc6 --- /dev/null +++ b/runtime/python/prompty/prompty/model/events/_TrajectoryEvent.py @@ -0,0 +1,154 @@ +########################################## +# WARNING: This is an auto-generated file. +# DO NOT EDIT THIS FILE DIRECTLY +# ANY EDITS WILL BE LOST +########################################## + +from dataclasses import dataclass, field +from typing import Any, ClassVar + +from .._context import LoadContext, SaveContext +from ._RedactionMetadata import RedactionMetadata + + +@dataclass +class TrajectoryEvent: + """A compact, replay-oriented record of one harness-side action or observation. + + Attributes + ---------- + id : Optional[str] + Stable trajectory event identifier + session_id : Optional[str] + Stable session identifier + turn_id : Optional[str] + Associated turn identifier, when available + tool_call_id : Optional[str] + Associated tool call identifier, when available + turn_index : Optional[int] + Zero-based turn index in the session + event_type : str + Host-defined trajectory event category + data : Optional[dict[str, Any]] + Sanitized event data + created_at : Optional[str] + ISO 8601 UTC timestamp when the trajectory event was recorded + redaction : Optional[RedactionMetadata] + Redaction state for sensitive trajectory fields + """ + + _shorthand_property: ClassVar[str | None] = None + + id: str | None = None + session_id: str | None = None + turn_id: str | None = None + tool_call_id: str | None = None + turn_index: int | None = None + event_type: str = field(default="") + data: dict[str, Any] | None = None + created_at: str | None = None + redaction: RedactionMetadata | None = None + + @staticmethod + def load(data: Any, context: LoadContext | None = None) -> "TrajectoryEvent": + """Load a TrajectoryEvent instance. + Args: + data (Any): The data to load the instance from. + context (Optional[LoadContext]): Optional context with pre/post processing callbacks. + Returns: + TrajectoryEvent: The loaded TrajectoryEvent instance. + + """ + + if context is not None: + data = context.process_input(data) + + if not isinstance(data, dict): + raise ValueError(f"Invalid data for TrajectoryEvent: {data}") + + # create new instance + instance = TrajectoryEvent() + + if data is not None and "id" in data: + instance.id = data["id"] + if data is not None and "sessionId" in data: + instance.session_id = data["sessionId"] + if data is not None and "turnId" in data: + instance.turn_id = data["turnId"] + if data is not None and "toolCallId" in data: + instance.tool_call_id = data["toolCallId"] + if data is not None and "turnIndex" in data: + instance.turn_index = data["turnIndex"] + if data is not None and "eventType" in data: + instance.event_type = data["eventType"] + if data is not None and "data" in data: + instance.data = data["data"] + if data is not None and "createdAt" in data: + instance.created_at = data["createdAt"] + if data is not None and "redaction" in data: + instance.redaction = RedactionMetadata.load(data["redaction"], context) + if context is not None: + instance = context.process_output(instance) + return instance + + def save(self, context: SaveContext | None = None) -> dict[str, Any]: + """Save the TrajectoryEvent instance to a dictionary. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + dict[str, Any]: The dictionary representation of this instance. + + """ + obj = self + if context is not None: + obj = context.process_object(obj) + + result: dict[str, Any] = {} + + if obj.id is not None: + result["id"] = obj.id + if obj.session_id is not None: + result["sessionId"] = obj.session_id + if obj.turn_id is not None: + result["turnId"] = obj.turn_id + if obj.tool_call_id is not None: + result["toolCallId"] = obj.tool_call_id + if obj.turn_index is not None: + result["turnIndex"] = obj.turn_index + if obj.event_type is not None: + result["eventType"] = obj.event_type + if obj.data is not None: + result["data"] = obj.data + if obj.created_at is not None: + result["createdAt"] = obj.created_at + if obj.redaction is not None: + result["redaction"] = obj.redaction.save(context) + + if context is not None: + result = context.process_dict(result) + return result + + def to_yaml(self, context: SaveContext | None = None) -> str: + """Convert the TrajectoryEvent instance to a YAML string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + Returns: + str: The YAML string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_yaml(self.save(context)) + + def to_json(self, context: SaveContext | None = None, indent: int = 2) -> str: + """Convert the TrajectoryEvent instance to a JSON string. + Args: + context (Optional[SaveContext]): Optional context with pre/post processing callbacks. + indent (int): Number of spaces for indentation. Defaults to 2. + Returns: + str: The JSON string representation of this instance. + + """ + if context is None: + context = SaveContext() + return context.to_json(self.save(context), indent) diff --git a/runtime/python/prompty/prompty/model/events/_TurnEvent.py b/runtime/python/prompty/prompty/model/events/_TurnEvent.py index 5aca2f34..280d5ebc 100644 --- a/runtime/python/prompty/prompty/model/events/_TurnEvent.py +++ b/runtime/python/prompty/prompty/model/events/_TurnEvent.py @@ -21,7 +21,11 @@ "thinking", "tool_call_start", "tool_call_complete", + "tool_execution_start", + "tool_execution_complete", "tool_result", + "hook_start", + "hook_end", "status", "messages_updated", "done", diff --git a/runtime/python/prompty/prompty/model/events/__init__.py b/runtime/python/prompty/prompty/model/events/__init__.py index 8eb17ce3..0c80cdb2 100644 --- a/runtime/python/prompty/prompty/model/events/__init__.py +++ b/runtime/python/prompty/prompty/model/events/__init__.py @@ -3,17 +3,35 @@ # DO NOT EDIT THIS FILE DIRECTLY # ANY EDITS WILL BE LOST ########################################## +from ._Checkpoint import Checkpoint from ._CompactionCompletePayload import CompactionCompletePayload from ._CompactionFailedPayload import CompactionFailedPayload from ._CompactionStartPayload import CompactionStartPayload from ._DoneEventPayload import DoneEventPayload from ._ErrorEventPayload import ErrorEventPayload +from ._HarnessContext import HarnessContext +from ._HookEndPayload import HookEndPayload +from ._HookStartPayload import HookStartPayload +from ._HostToolRequest import HostToolRequest +from ._HostToolResult import HostToolResult from ._LlmCompletePayload import LlmCompletePayload from ._LlmStartPayload import LlmStartPayload from ._MessagesUpdatedPayload import MessagesUpdatedPayload from ._PermissionCompletedPayload import PermissionCompletedPayload +from ._PermissionDecision import PermissionDecision +from ._PermissionRequest import PermissionRequest from ._PermissionRequestedPayload import PermissionRequestedPayload +from ._RedactedField import RedactedField +from ._RedactionMetadata import RedactionMetadata from ._RetryPayload import RetryPayload +from ._SessionEndPayload import SessionEndPayload +from ._SessionEvent import SessionEvent +from ._SessionFileRef import SessionFileRef +from ._SessionRef import SessionRef +from ._SessionStartPayload import SessionStartPayload +from ._SessionSummary import SessionSummary +from ._SessionTrace import SessionTrace +from ._SessionWarningPayload import SessionWarningPayload from ._StatusEventPayload import StatusEventPayload from ._StreamChunk import ( ErrorChunk, @@ -26,7 +44,10 @@ from ._TokenEventPayload import TokenEventPayload from ._ToolCallCompletePayload import ToolCallCompletePayload from ._ToolCallStartPayload import ToolCallStartPayload +from ._ToolExecutionCompletePayload import ToolExecutionCompletePayload +from ._ToolExecutionStartPayload import ToolExecutionStartPayload from ._ToolResultPayload import ToolResultPayload +from ._TrajectoryEvent import TrajectoryEvent from ._TurnEndPayload import TurnEndPayload from ._TurnEvent import TurnEvent from ._TurnStartPayload import TurnStartPayload @@ -40,12 +61,22 @@ "LlmStartPayload", "LlmCompletePayload", "RetryPayload", + "RedactedField", + "RedactionMetadata", "PermissionRequestedPayload", "PermissionCompletedPayload", + "PermissionRequest", + "PermissionDecision", "TokenEventPayload", "ThinkingEventPayload", "ToolCallStartPayload", "ToolCallCompletePayload", + "ToolExecutionStartPayload", + "ToolExecutionCompletePayload", + "HostToolRequest", + "HostToolResult", + "HookStartPayload", + "HookEndPayload", "ToolResultPayload", "StatusEventPayload", "MessagesUpdatedPayload", @@ -56,6 +87,17 @@ "CompactionFailedPayload", "TurnSummary", "TurnTrace", + "HarnessContext", + "SessionStartPayload", + "SessionEndPayload", + "SessionWarningPayload", + "SessionEvent", + "Checkpoint", + "TrajectoryEvent", + "SessionFileRef", + "SessionRef", + "SessionSummary", + "SessionTrace", "StreamChunk", "TextChunk", "ThinkingChunk", diff --git a/runtime/python/prompty/prompty/model/pipeline/_CheckpointStore.py b/runtime/python/prompty/prompty/model/pipeline/_CheckpointStore.py new file mode 100644 index 00000000..b19cbbaa --- /dev/null +++ b/runtime/python/prompty/prompty/model/pipeline/_CheckpointStore.py @@ -0,0 +1,38 @@ +########################################## +# WARNING: This is an auto-generated file. +# DO NOT EDIT THIS FILE DIRECTLY +# ANY EDITS WILL BE LOST +########################################## + +from typing import Protocol, runtime_checkable + +from ..events._Checkpoint import Checkpoint + + +@runtime_checkable +class CheckpointStore(Protocol): + """Stores and retrieves resumable session checkpoints.""" + + def save(self, checkpoint: Checkpoint) -> Checkpoint: + """Persist a session checkpoint and return the stored checkpoint""" + ... + + async def save_async(self, checkpoint: Checkpoint) -> Checkpoint: + """Persist a session checkpoint and return the stored checkpoint (async variant)""" + ... + + def load(self, session_id: str, checkpoint_id: str) -> Checkpoint | None: + """Load a checkpoint by session and checkpoint identifier""" + ... + + async def load_async(self, session_id: str, checkpoint_id: str) -> Checkpoint | None: + """Load a checkpoint by session and checkpoint identifier (async variant)""" + ... + + def list_checkpoints(self, session_id: str) -> list[Checkpoint]: + """List checkpoints for a session""" + ... + + async def list_checkpoints_async(self, session_id: str) -> list[Checkpoint]: + """List checkpoints for a session (async variant)""" + ... diff --git a/runtime/python/prompty/prompty/model/pipeline/_EventSink.py b/runtime/python/prompty/prompty/model/pipeline/_EventSink.py new file mode 100644 index 00000000..5446f786 --- /dev/null +++ b/runtime/python/prompty/prompty/model/pipeline/_EventSink.py @@ -0,0 +1,23 @@ +########################################## +# WARNING: This is an auto-generated file. +# DO NOT EDIT THIS FILE DIRECTLY +# ANY EDITS WILL BE LOST +########################################## + +from typing import Protocol, runtime_checkable + +from ..events._SessionEvent import SessionEvent +from ..events._TurnEvent import TurnEvent + + +@runtime_checkable +class EventSink(Protocol): + """Receives typed turn and session events from a harness.""" + + def emit_turn(self, turn_event: TurnEvent) -> bool: + """Emit a typed turn event to a host sink""" + ... + + def emit_session(self, session_event: SessionEvent) -> bool: + """Emit a typed session event to a host sink""" + ... diff --git a/runtime/python/prompty/prompty/model/pipeline/_HostToolExecutor.py b/runtime/python/prompty/prompty/model/pipeline/_HostToolExecutor.py new file mode 100644 index 00000000..5edb3425 --- /dev/null +++ b/runtime/python/prompty/prompty/model/pipeline/_HostToolExecutor.py @@ -0,0 +1,23 @@ +########################################## +# WARNING: This is an auto-generated file. +# DO NOT EDIT THIS FILE DIRECTLY +# ANY EDITS WILL BE LOST +########################################## + +from typing import Protocol, runtime_checkable + +from ..events._HostToolRequest import HostToolRequest +from ..events._HostToolResult import HostToolResult + + +@runtime_checkable +class HostToolExecutor(Protocol): + """Executes host tools after policy and permission checks.""" + + def execute(self, request: HostToolRequest) -> HostToolResult: + """Execute a concrete host tool request and return its completion payload""" + ... + + async def execute_async(self, request: HostToolRequest) -> HostToolResult: + """Execute a concrete host tool request and return its completion payload (async variant)""" + ... diff --git a/runtime/python/prompty/prompty/model/pipeline/_PermissionResolver.py b/runtime/python/prompty/prompty/model/pipeline/_PermissionResolver.py new file mode 100644 index 00000000..2c6d90ef --- /dev/null +++ b/runtime/python/prompty/prompty/model/pipeline/_PermissionResolver.py @@ -0,0 +1,23 @@ +########################################## +# WARNING: This is an auto-generated file. +# DO NOT EDIT THIS FILE DIRECTLY +# ANY EDITS WILL BE LOST +########################################## + +from typing import Protocol, runtime_checkable + +from ..events._PermissionDecision import PermissionDecision +from ..events._PermissionRequest import PermissionRequest + + +@runtime_checkable +class PermissionResolver(Protocol): + """Resolves host permission requests for potentially sensitive actions.""" + + def request(self, request: PermissionRequest) -> PermissionDecision: + """Resolve a host permission request""" + ... + + async def request_async(self, request: PermissionRequest) -> PermissionDecision: + """Resolve a host permission request (async variant)""" + ... diff --git a/runtime/python/prompty/prompty/model/pipeline/_TraceWriter.py b/runtime/python/prompty/prompty/model/pipeline/_TraceWriter.py new file mode 100644 index 00000000..4b06c151 --- /dev/null +++ b/runtime/python/prompty/prompty/model/pipeline/_TraceWriter.py @@ -0,0 +1,28 @@ +########################################## +# WARNING: This is an auto-generated file. +# DO NOT EDIT THIS FILE DIRECTLY +# ANY EDITS WILL BE LOST +########################################## + +from typing import Protocol, runtime_checkable + +from ..events._SessionEvent import SessionEvent +from ..events._SessionSummary import SessionSummary +from ..events._TurnEvent import TurnEvent + + +@runtime_checkable +class TraceWriter(Protocol): + """Persists typed events to a replayable trace.""" + + def append_turn(self, turn_event: TurnEvent) -> bool: + """Append a turn event to a replayable trace""" + ... + + def append_session(self, session_event: SessionEvent) -> bool: + """Append a session event to a replayable trace""" + ... + + def close(self, summary: SessionSummary | None) -> bool: + """Finalize the trace with an optional session summary""" + ... diff --git a/runtime/python/prompty/prompty/model/pipeline/__init__.py b/runtime/python/prompty/prompty/model/pipeline/__init__.py index 8080ed2a..7f39f65a 100644 --- a/runtime/python/prompty/prompty/model/pipeline/__init__.py +++ b/runtime/python/prompty/prompty/model/pipeline/__init__.py @@ -3,11 +3,16 @@ # DO NOT EDIT THIS FILE DIRECTLY # ANY EDITS WILL BE LOST ########################################## +from ._CheckpointStore import CheckpointStore from ._CompactionConfig import CompactionConfig +from ._EventSink import EventSink from ._Executor import Executor +from ._HostToolExecutor import HostToolExecutor from ._Parser import Parser +from ._PermissionResolver import PermissionResolver from ._Processor import Processor from ._Renderer import Renderer +from ._TraceWriter import TraceWriter from ._TurnOptions import TurnOptions __all__ = [ @@ -17,4 +22,9 @@ "Parser", "Executor", "Processor", + "EventSink", + "TraceWriter", + "PermissionResolver", + "CheckpointStore", + "HostToolExecutor", ] diff --git a/runtime/python/prompty/tests/model/events/test_checkpoint.py b/runtime/python/prompty/tests/model/events/test_checkpoint.py new file mode 100644 index 00000000..b0a946b6 --- /dev/null +++ b/runtime/python/prompty/tests/model/events/test_checkpoint.py @@ -0,0 +1,113 @@ +import json + +import yaml + +from prompty.model import Checkpoint + + +def test_load_json_checkpoint(): + json_data = r""" + { + "id": "chk_abc123", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "checkpointNumber": 3, + "title": "Added harness contracts", + "createdAt": "2026-06-09T20:00:00Z" + } + """ + data = json.loads(json_data, strict=False) + instance = Checkpoint.load(data) + assert instance is not None + assert instance.id == "chk_abc123" + assert instance.session_id == "sess_abc123" + assert instance.turn_id == "turn_001" + assert instance.checkpoint_number == 3 + assert instance.title == "Added harness contracts" + assert instance.created_at == "2026-06-09T20:00:00Z" + + +def test_load_yaml_checkpoint(): + yaml_data = r""" + id: chk_abc123 + sessionId: sess_abc123 + turnId: turn_001 + checkpointNumber: 3 + title: Added harness contracts + createdAt: "2026-06-09T20:00:00Z" + + """ + data = yaml.load(yaml_data, Loader=yaml.FullLoader) + instance = Checkpoint.load(data) + assert instance is not None + assert instance.id == "chk_abc123" + assert instance.session_id == "sess_abc123" + assert instance.turn_id == "turn_001" + assert instance.checkpoint_number == 3 + assert instance.title == "Added harness contracts" + assert instance.created_at == "2026-06-09T20:00:00Z" + + +def test_roundtrip_json_checkpoint(): + """Test that load -> save -> load produces equivalent data.""" + json_data = r""" + { + "id": "chk_abc123", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "checkpointNumber": 3, + "title": "Added harness contracts", + "createdAt": "2026-06-09T20:00:00Z" + } + """ + original_data = json.loads(json_data, strict=False) + instance = Checkpoint.load(original_data) + saved_data = instance.save() + reloaded = Checkpoint.load(saved_data) + assert reloaded is not None + assert reloaded.id == "chk_abc123" + assert reloaded.session_id == "sess_abc123" + assert reloaded.turn_id == "turn_001" + assert reloaded.checkpoint_number == 3 + assert reloaded.title == "Added harness contracts" + assert reloaded.created_at == "2026-06-09T20:00:00Z" + + +def test_to_json_checkpoint(): + """Test that to_json produces valid JSON.""" + json_data = r""" + { + "id": "chk_abc123", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "checkpointNumber": 3, + "title": "Added harness contracts", + "createdAt": "2026-06-09T20:00:00Z" + } + """ + data = json.loads(json_data, strict=False) + instance = Checkpoint.load(data) + json_output = instance.to_json() + assert json_output is not None + parsed = json.loads(json_output) + assert isinstance(parsed, dict) + + +def test_to_yaml_checkpoint(): + """Test that to_yaml produces valid YAML.""" + json_data = r""" + { + "id": "chk_abc123", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "checkpointNumber": 3, + "title": "Added harness contracts", + "createdAt": "2026-06-09T20:00:00Z" + } + """ + data = json.loads(json_data, strict=False) + instance = Checkpoint.load(data) + yaml_output = instance.to_yaml() + assert yaml_output is not None + parsed = yaml.safe_load(yaml_output) + assert isinstance(parsed, dict) diff --git a/runtime/python/prompty/tests/model/events/test_harness_context.py b/runtime/python/prompty/tests/model/events/test_harness_context.py new file mode 100644 index 00000000..2aa085c7 --- /dev/null +++ b/runtime/python/prompty/tests/model/events/test_harness_context.py @@ -0,0 +1,81 @@ +import json + +import yaml + +from prompty.model import HarnessContext + + +def test_load_json_harnesscontext(): + json_data = r""" + { + "cwd": "/workspace/project", + "gitRoot": "/workspace/project" + } + """ + data = json.loads(json_data, strict=False) + instance = HarnessContext.load(data) + assert instance is not None + assert instance.cwd == "/workspace/project" + assert instance.git_root == "/workspace/project" + + +def test_load_yaml_harnesscontext(): + yaml_data = r""" + cwd: /workspace/project + gitRoot: /workspace/project + + """ + data = yaml.load(yaml_data, Loader=yaml.FullLoader) + instance = HarnessContext.load(data) + assert instance is not None + assert instance.cwd == "/workspace/project" + assert instance.git_root == "/workspace/project" + + +def test_roundtrip_json_harnesscontext(): + """Test that load -> save -> load produces equivalent data.""" + json_data = r""" + { + "cwd": "/workspace/project", + "gitRoot": "/workspace/project" + } + """ + original_data = json.loads(json_data, strict=False) + instance = HarnessContext.load(original_data) + saved_data = instance.save() + reloaded = HarnessContext.load(saved_data) + assert reloaded is not None + assert reloaded.cwd == "/workspace/project" + assert reloaded.git_root == "/workspace/project" + + +def test_to_json_harnesscontext(): + """Test that to_json produces valid JSON.""" + json_data = r""" + { + "cwd": "/workspace/project", + "gitRoot": "/workspace/project" + } + """ + data = json.loads(json_data, strict=False) + instance = HarnessContext.load(data) + json_output = instance.to_json() + assert json_output is not None + parsed = json.loads(json_output) + assert isinstance(parsed, dict) + + +def test_to_yaml_harnesscontext(): + """Test that to_yaml produces valid YAML.""" + json_data = r""" + { + "cwd": "/workspace/project", + "gitRoot": "/workspace/project" + } + """ + data = json.loads(json_data, strict=False) + instance = HarnessContext.load(data) + yaml_output = instance.to_yaml() + assert yaml_output is not None + parsed = yaml.safe_load(yaml_output) + assert isinstance(parsed, dict) diff --git a/runtime/python/prompty/tests/model/events/test_hook_end_payload.py b/runtime/python/prompty/tests/model/events/test_hook_end_payload.py new file mode 100644 index 00000000..c7c44fb1 --- /dev/null +++ b/runtime/python/prompty/tests/model/events/test_hook_end_payload.py @@ -0,0 +1,105 @@ +import json + +import yaml + +from prompty.model import HookEndPayload + + +def test_load_json_hookendpayload(): + json_data = r""" + { + "hookInvocationId": "hook_abc123", + "hookType": "preToolUse", + "success": true, + "durationMs": 12, + "error": "hook failed" + } + """ + data = json.loads(json_data, strict=False) + instance = HookEndPayload.load(data) + assert instance is not None + assert instance.hook_invocation_id == "hook_abc123" + assert instance.hook_type == "preToolUse" + assert instance.success + assert instance.duration_ms == 12 + assert instance.error == "hook failed" + + +def test_load_yaml_hookendpayload(): + yaml_data = r""" + hookInvocationId: hook_abc123 + hookType: preToolUse + success: true + durationMs: 12 + error: hook failed + + """ + data = yaml.load(yaml_data, Loader=yaml.FullLoader) + instance = HookEndPayload.load(data) + assert instance is not None + assert instance.hook_invocation_id == "hook_abc123" + assert instance.hook_type == "preToolUse" + assert instance.success + assert instance.duration_ms == 12 + assert instance.error == "hook failed" + + +def test_roundtrip_json_hookendpayload(): + """Test that load -> save -> load produces equivalent data.""" + json_data = r""" + { + "hookInvocationId": "hook_abc123", + "hookType": "preToolUse", + "success": true, + "durationMs": 12, + "error": "hook failed" + } + """ + original_data = json.loads(json_data, strict=False) + instance = HookEndPayload.load(original_data) + saved_data = instance.save() + reloaded = HookEndPayload.load(saved_data) + assert reloaded is not None + assert reloaded.hook_invocation_id == "hook_abc123" + assert reloaded.hook_type == "preToolUse" + assert reloaded.success + assert reloaded.duration_ms == 12 + assert reloaded.error == "hook failed" + + +def test_to_json_hookendpayload(): + """Test that to_json produces valid JSON.""" + json_data = r""" + { + "hookInvocationId": "hook_abc123", + "hookType": "preToolUse", + "success": true, + "durationMs": 12, + "error": "hook failed" + } + """ + data = json.loads(json_data, strict=False) + instance = HookEndPayload.load(data) + json_output = instance.to_json() + assert json_output is not None + parsed = json.loads(json_output) + assert isinstance(parsed, dict) + + +def test_to_yaml_hookendpayload(): + """Test that to_yaml produces valid YAML.""" + json_data = r""" + { + "hookInvocationId": "hook_abc123", + "hookType": "preToolUse", + "success": true, + "durationMs": 12, + "error": "hook failed" + } + """ + data = json.loads(json_data, strict=False) + instance = HookEndPayload.load(data) + yaml_output = instance.to_yaml() + assert yaml_output is not None + parsed = yaml.safe_load(yaml_output) + assert isinstance(parsed, dict) diff --git a/runtime/python/prompty/tests/model/events/test_hook_start_payload.py b/runtime/python/prompty/tests/model/events/test_hook_start_payload.py new file mode 100644 index 00000000..71042da9 --- /dev/null +++ b/runtime/python/prompty/tests/model/events/test_hook_start_payload.py @@ -0,0 +1,81 @@ +import json + +import yaml + +from prompty.model import HookStartPayload + + +def test_load_json_hookstartpayload(): + json_data = r""" + { + "hookInvocationId": "hook_abc123", + "hookType": "preToolUse" + } + """ + data = json.loads(json_data, strict=False) + instance = HookStartPayload.load(data) + assert instance is not None + assert instance.hook_invocation_id == "hook_abc123" + assert instance.hook_type == "preToolUse" + + +def test_load_yaml_hookstartpayload(): + yaml_data = r""" + hookInvocationId: hook_abc123 + hookType: preToolUse + + """ + data = yaml.load(yaml_data, Loader=yaml.FullLoader) + instance = HookStartPayload.load(data) + assert instance is not None + assert instance.hook_invocation_id == "hook_abc123" + assert instance.hook_type == "preToolUse" + + +def test_roundtrip_json_hookstartpayload(): + """Test that load -> save -> load produces equivalent data.""" + json_data = r""" + { + "hookInvocationId": "hook_abc123", + "hookType": "preToolUse" + } + """ + original_data = json.loads(json_data, strict=False) + instance = HookStartPayload.load(original_data) + saved_data = instance.save() + reloaded = HookStartPayload.load(saved_data) + assert reloaded is not None + assert reloaded.hook_invocation_id == "hook_abc123" + assert reloaded.hook_type == "preToolUse" + + +def test_to_json_hookstartpayload(): + """Test that to_json produces valid JSON.""" + json_data = r""" + { + "hookInvocationId": "hook_abc123", + "hookType": "preToolUse" + } + """ + data = json.loads(json_data, strict=False) + instance = HookStartPayload.load(data) + json_output = instance.to_json() + assert json_output is not None + parsed = json.loads(json_output) + assert isinstance(parsed, dict) + + +def test_to_yaml_hookstartpayload(): + """Test that to_yaml produces valid YAML.""" + json_data = r""" + { + "hookInvocationId": "hook_abc123", + "hookType": "preToolUse" + } + """ + data = json.loads(json_data, strict=False) + instance = HookStartPayload.load(data) + yaml_output = instance.to_yaml() + assert yaml_output is not None + parsed = yaml.safe_load(yaml_output) + assert isinstance(parsed, dict) diff --git a/runtime/python/prompty/tests/model/events/test_host_tool_request.py b/runtime/python/prompty/tests/model/events/test_host_tool_request.py new file mode 100644 index 00000000..26dcadf3 --- /dev/null +++ b/runtime/python/prompty/tests/model/events/test_host_tool_request.py @@ -0,0 +1,97 @@ +import json + +import yaml + +from prompty.model import HostToolRequest + + +def test_load_json_hosttoolrequest(): + json_data = r""" + { + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "workingDirectory": "/workspace/project" + } + """ + data = json.loads(json_data, strict=False) + instance = HostToolRequest.load(data) + assert instance is not None + assert instance.request_id == "exec_abc123" + assert instance.tool_call_id == "call_abc123" + assert instance.tool_name == "powershell" + assert instance.working_directory == "/workspace/project" + + +def test_load_yaml_hosttoolrequest(): + yaml_data = r""" + requestId: exec_abc123 + toolCallId: call_abc123 + toolName: powershell + workingDirectory: /workspace/project + + """ + data = yaml.load(yaml_data, Loader=yaml.FullLoader) + instance = HostToolRequest.load(data) + assert instance is not None + assert instance.request_id == "exec_abc123" + assert instance.tool_call_id == "call_abc123" + assert instance.tool_name == "powershell" + assert instance.working_directory == "/workspace/project" + + +def test_roundtrip_json_hosttoolrequest(): + """Test that load -> save -> load produces equivalent data.""" + json_data = r""" + { + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "workingDirectory": "/workspace/project" + } + """ + original_data = json.loads(json_data, strict=False) + instance = HostToolRequest.load(original_data) + saved_data = instance.save() + reloaded = HostToolRequest.load(saved_data) + assert reloaded is not None + assert reloaded.request_id == "exec_abc123" + assert reloaded.tool_call_id == "call_abc123" + assert reloaded.tool_name == "powershell" + assert reloaded.working_directory == "/workspace/project" + + +def test_to_json_hosttoolrequest(): + """Test that to_json produces valid JSON.""" + json_data = r""" + { + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "workingDirectory": "/workspace/project" + } + """ + data = json.loads(json_data, strict=False) + instance = HostToolRequest.load(data) + json_output = instance.to_json() + assert json_output is not None + parsed = json.loads(json_output) + assert isinstance(parsed, dict) + + +def test_to_yaml_hosttoolrequest(): + """Test that to_yaml produces valid YAML.""" + json_data = r""" + { + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "workingDirectory": "/workspace/project" + } + """ + data = json.loads(json_data, strict=False) + instance = HostToolRequest.load(data) + yaml_output = instance.to_yaml() + assert yaml_output is not None + parsed = yaml.safe_load(yaml_output) + assert isinstance(parsed, dict) diff --git a/runtime/python/prompty/tests/model/events/test_host_tool_result.py b/runtime/python/prompty/tests/model/events/test_host_tool_result.py new file mode 100644 index 00000000..800efc17 --- /dev/null +++ b/runtime/python/prompty/tests/model/events/test_host_tool_result.py @@ -0,0 +1,121 @@ +import json + +import yaml + +from prompty.model import HostToolResult + + +def test_load_json_hosttoolresult(): + json_data = r""" + { + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "success": true, + "exitCode": 0, + "durationMs": 250, + "errorKind": "timeout" + } + """ + data = json.loads(json_data, strict=False) + instance = HostToolResult.load(data) + assert instance is not None + assert instance.request_id == "exec_abc123" + assert instance.tool_call_id == "call_abc123" + assert instance.tool_name == "powershell" + assert instance.success + assert instance.exit_code == 0 + assert instance.duration_ms == 250 + assert instance.error_kind == "timeout" + + +def test_load_yaml_hosttoolresult(): + yaml_data = r""" + requestId: exec_abc123 + toolCallId: call_abc123 + toolName: powershell + success: true + exitCode: 0 + durationMs: 250 + errorKind: timeout + + """ + data = yaml.load(yaml_data, Loader=yaml.FullLoader) + instance = HostToolResult.load(data) + assert instance is not None + assert instance.request_id == "exec_abc123" + assert instance.tool_call_id == "call_abc123" + assert instance.tool_name == "powershell" + assert instance.success + assert instance.exit_code == 0 + assert instance.duration_ms == 250 + assert instance.error_kind == "timeout" + + +def test_roundtrip_json_hosttoolresult(): + """Test that load -> save -> load produces equivalent data.""" + json_data = r""" + { + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "success": true, + "exitCode": 0, + "durationMs": 250, + "errorKind": "timeout" + } + """ + original_data = json.loads(json_data, strict=False) + instance = HostToolResult.load(original_data) + saved_data = instance.save() + reloaded = HostToolResult.load(saved_data) + assert reloaded is not None + assert reloaded.request_id == "exec_abc123" + assert reloaded.tool_call_id == "call_abc123" + assert reloaded.tool_name == "powershell" + assert reloaded.success + assert reloaded.exit_code == 0 + assert reloaded.duration_ms == 250 + assert reloaded.error_kind == "timeout" + + +def test_to_json_hosttoolresult(): + """Test that to_json produces valid JSON.""" + json_data = r""" + { + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "success": true, + "exitCode": 0, + "durationMs": 250, + "errorKind": "timeout" + } + """ + data = json.loads(json_data, strict=False) + instance = HostToolResult.load(data) + json_output = instance.to_json() + assert json_output is not None + parsed = json.loads(json_output) + assert isinstance(parsed, dict) + + +def test_to_yaml_hosttoolresult(): + """Test that to_yaml produces valid YAML.""" + json_data = r""" + { + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "success": true, + "exitCode": 0, + "durationMs": 250, + "errorKind": "timeout" + } + """ + data = json.loads(json_data, strict=False) + instance = HostToolResult.load(data) + yaml_output = instance.to_yaml() + assert yaml_output is not None + parsed = yaml.safe_load(yaml_output) + assert isinstance(parsed, dict) diff --git a/runtime/python/prompty/tests/model/events/test_permission_completed_payload.py b/runtime/python/prompty/tests/model/events/test_permission_completed_payload.py index 7fbf6d29..620570e8 100644 --- a/runtime/python/prompty/tests/model/events/test_permission_completed_payload.py +++ b/runtime/python/prompty/tests/model/events/test_permission_completed_payload.py @@ -8,6 +8,8 @@ def test_load_json_permissioncompletedpayload(): json_data = r""" { + "requestId": "perm_abc123", + "toolCallId": "call_abc123", "permission": "tool.execute", "approved": true, "reason": "user_approved" @@ -16,6 +18,8 @@ def test_load_json_permissioncompletedpayload(): data = json.loads(json_data, strict=False) instance = PermissionCompletedPayload.load(data) assert instance is not None + assert instance.request_id == "perm_abc123" + assert instance.tool_call_id == "call_abc123" assert instance.permission == "tool.execute" assert instance.approved assert instance.reason == "user_approved" @@ -23,6 +27,8 @@ def test_load_json_permissioncompletedpayload(): def test_load_yaml_permissioncompletedpayload(): yaml_data = r""" + requestId: perm_abc123 + toolCallId: call_abc123 permission: tool.execute approved: true reason: user_approved @@ -31,6 +37,8 @@ def test_load_yaml_permissioncompletedpayload(): data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = PermissionCompletedPayload.load(data) assert instance is not None + assert instance.request_id == "perm_abc123" + assert instance.tool_call_id == "call_abc123" assert instance.permission == "tool.execute" assert instance.approved assert instance.reason == "user_approved" @@ -40,6 +48,8 @@ def test_roundtrip_json_permissioncompletedpayload(): """Test that load -> save -> load produces equivalent data.""" json_data = r""" { + "requestId": "perm_abc123", + "toolCallId": "call_abc123", "permission": "tool.execute", "approved": true, "reason": "user_approved" @@ -50,6 +60,8 @@ def test_roundtrip_json_permissioncompletedpayload(): saved_data = instance.save() reloaded = PermissionCompletedPayload.load(saved_data) assert reloaded is not None + assert reloaded.request_id == "perm_abc123" + assert reloaded.tool_call_id == "call_abc123" assert reloaded.permission == "tool.execute" assert reloaded.approved assert reloaded.reason == "user_approved" @@ -59,6 +71,8 @@ def test_to_json_permissioncompletedpayload(): """Test that to_json produces valid JSON.""" json_data = r""" { + "requestId": "perm_abc123", + "toolCallId": "call_abc123", "permission": "tool.execute", "approved": true, "reason": "user_approved" @@ -76,6 +90,8 @@ def test_to_yaml_permissioncompletedpayload(): """Test that to_yaml produces valid YAML.""" json_data = r""" { + "requestId": "perm_abc123", + "toolCallId": "call_abc123", "permission": "tool.execute", "approved": true, "reason": "user_approved" diff --git a/runtime/python/prompty/tests/model/events/test_permission_decision.py b/runtime/python/prompty/tests/model/events/test_permission_decision.py new file mode 100644 index 00000000..e53a98e3 --- /dev/null +++ b/runtime/python/prompty/tests/model/events/test_permission_decision.py @@ -0,0 +1,105 @@ +import json + +import yaml + +from prompty.model import PermissionDecision + + +def test_load_json_permissiondecision(): + json_data = r""" + { + "requestId": "perm_abc123", + "toolCallId": "call_abc123", + "permission": "tool.execute", + "approved": true, + "reason": "user_approved" + } + """ + data = json.loads(json_data, strict=False) + instance = PermissionDecision.load(data) + assert instance is not None + assert instance.request_id == "perm_abc123" + assert instance.tool_call_id == "call_abc123" + assert instance.permission == "tool.execute" + assert instance.approved + assert instance.reason == "user_approved" + + +def test_load_yaml_permissiondecision(): + yaml_data = r""" + requestId: perm_abc123 + toolCallId: call_abc123 + permission: tool.execute + approved: true + reason: user_approved + + """ + data = yaml.load(yaml_data, Loader=yaml.FullLoader) + instance = PermissionDecision.load(data) + assert instance is not None + assert instance.request_id == "perm_abc123" + assert instance.tool_call_id == "call_abc123" + assert instance.permission == "tool.execute" + assert instance.approved + assert instance.reason == "user_approved" + + +def test_roundtrip_json_permissiondecision(): + """Test that load -> save -> load produces equivalent data.""" + json_data = r""" + { + "requestId": "perm_abc123", + "toolCallId": "call_abc123", + "permission": "tool.execute", + "approved": true, + "reason": "user_approved" + } + """ + original_data = json.loads(json_data, strict=False) + instance = PermissionDecision.load(original_data) + saved_data = instance.save() + reloaded = PermissionDecision.load(saved_data) + assert reloaded is not None + assert reloaded.request_id == "perm_abc123" + assert reloaded.tool_call_id == "call_abc123" + assert reloaded.permission == "tool.execute" + assert reloaded.approved + assert reloaded.reason == "user_approved" + + +def test_to_json_permissiondecision(): + """Test that to_json produces valid JSON.""" + json_data = r""" + { + "requestId": "perm_abc123", + "toolCallId": "call_abc123", + "permission": "tool.execute", + "approved": true, + "reason": "user_approved" + } + """ + data = json.loads(json_data, strict=False) + instance = PermissionDecision.load(data) + json_output = instance.to_json() + assert json_output is not None + parsed = json.loads(json_output) + assert isinstance(parsed, dict) + + +def test_to_yaml_permissiondecision(): + """Test that to_yaml produces valid YAML.""" + json_data = r""" + { + "requestId": "perm_abc123", + "toolCallId": "call_abc123", + "permission": "tool.execute", + "approved": true, + "reason": "user_approved" + } + """ + data = json.loads(json_data, strict=False) + instance = PermissionDecision.load(data) + yaml_output = instance.to_yaml() + assert yaml_output is not None + parsed = yaml.safe_load(yaml_output) + assert isinstance(parsed, dict) diff --git a/runtime/python/prompty/tests/model/events/test_permission_request.py b/runtime/python/prompty/tests/model/events/test_permission_request.py new file mode 100644 index 00000000..a0d58ec6 --- /dev/null +++ b/runtime/python/prompty/tests/model/events/test_permission_request.py @@ -0,0 +1,105 @@ +import json + +import yaml + +from prompty.model import PermissionRequest + + +def test_load_json_permissionrequest(): + json_data = r""" + { + "requestId": "perm_abc123", + "toolCallId": "call_abc123", + "permission": "tool.execute", + "target": "shell", + "promptRequest": "Allow shell to run tests?" + } + """ + data = json.loads(json_data, strict=False) + instance = PermissionRequest.load(data) + assert instance is not None + assert instance.request_id == "perm_abc123" + assert instance.tool_call_id == "call_abc123" + assert instance.permission == "tool.execute" + assert instance.target == "shell" + assert instance.prompt_request == "Allow shell to run tests?" + + +def test_load_yaml_permissionrequest(): + yaml_data = r""" + requestId: perm_abc123 + toolCallId: call_abc123 + permission: tool.execute + target: shell + promptRequest: Allow shell to run tests? + + """ + data = yaml.load(yaml_data, Loader=yaml.FullLoader) + instance = PermissionRequest.load(data) + assert instance is not None + assert instance.request_id == "perm_abc123" + assert instance.tool_call_id == "call_abc123" + assert instance.permission == "tool.execute" + assert instance.target == "shell" + assert instance.prompt_request == "Allow shell to run tests?" + + +def test_roundtrip_json_permissionrequest(): + """Test that load -> save -> load produces equivalent data.""" + json_data = r""" + { + "requestId": "perm_abc123", + "toolCallId": "call_abc123", + "permission": "tool.execute", + "target": "shell", + "promptRequest": "Allow shell to run tests?" + } + """ + original_data = json.loads(json_data, strict=False) + instance = PermissionRequest.load(original_data) + saved_data = instance.save() + reloaded = PermissionRequest.load(saved_data) + assert reloaded is not None + assert reloaded.request_id == "perm_abc123" + assert reloaded.tool_call_id == "call_abc123" + assert reloaded.permission == "tool.execute" + assert reloaded.target == "shell" + assert reloaded.prompt_request == "Allow shell to run tests?" + + +def test_to_json_permissionrequest(): + """Test that to_json produces valid JSON.""" + json_data = r""" + { + "requestId": "perm_abc123", + "toolCallId": "call_abc123", + "permission": "tool.execute", + "target": "shell", + "promptRequest": "Allow shell to run tests?" + } + """ + data = json.loads(json_data, strict=False) + instance = PermissionRequest.load(data) + json_output = instance.to_json() + assert json_output is not None + parsed = json.loads(json_output) + assert isinstance(parsed, dict) + + +def test_to_yaml_permissionrequest(): + """Test that to_yaml produces valid YAML.""" + json_data = r""" + { + "requestId": "perm_abc123", + "toolCallId": "call_abc123", + "permission": "tool.execute", + "target": "shell", + "promptRequest": "Allow shell to run tests?" + } + """ + data = json.loads(json_data, strict=False) + instance = PermissionRequest.load(data) + yaml_output = instance.to_yaml() + assert yaml_output is not None + parsed = yaml.safe_load(yaml_output) + assert isinstance(parsed, dict) diff --git a/runtime/python/prompty/tests/model/events/test_permission_requested_payload.py b/runtime/python/prompty/tests/model/events/test_permission_requested_payload.py index 27a040f0..14fcc80b 100644 --- a/runtime/python/prompty/tests/model/events/test_permission_requested_payload.py +++ b/runtime/python/prompty/tests/model/events/test_permission_requested_payload.py @@ -8,36 +8,51 @@ def test_load_json_permissionrequestedpayload(): json_data = r""" { + "requestId": "perm_abc123", + "toolCallId": "call_abc123", "permission": "tool.execute", - "target": "shell" + "target": "shell", + "promptRequest": "Allow shell to run tests?" } """ data = json.loads(json_data, strict=False) instance = PermissionRequestedPayload.load(data) assert instance is not None + assert instance.request_id == "perm_abc123" + assert instance.tool_call_id == "call_abc123" assert instance.permission == "tool.execute" assert instance.target == "shell" + assert instance.prompt_request == "Allow shell to run tests?" def test_load_yaml_permissionrequestedpayload(): yaml_data = r""" + requestId: perm_abc123 + toolCallId: call_abc123 permission: tool.execute target: shell + promptRequest: Allow shell to run tests? """ data = yaml.load(yaml_data, Loader=yaml.FullLoader) instance = PermissionRequestedPayload.load(data) assert instance is not None + assert instance.request_id == "perm_abc123" + assert instance.tool_call_id == "call_abc123" assert instance.permission == "tool.execute" assert instance.target == "shell" + assert instance.prompt_request == "Allow shell to run tests?" def test_roundtrip_json_permissionrequestedpayload(): """Test that load -> save -> load produces equivalent data.""" json_data = r""" { + "requestId": "perm_abc123", + "toolCallId": "call_abc123", "permission": "tool.execute", - "target": "shell" + "target": "shell", + "promptRequest": "Allow shell to run tests?" } """ original_data = json.loads(json_data, strict=False) @@ -45,16 +60,22 @@ def test_roundtrip_json_permissionrequestedpayload(): saved_data = instance.save() reloaded = PermissionRequestedPayload.load(saved_data) assert reloaded is not None + assert reloaded.request_id == "perm_abc123" + assert reloaded.tool_call_id == "call_abc123" assert reloaded.permission == "tool.execute" assert reloaded.target == "shell" + assert reloaded.prompt_request == "Allow shell to run tests?" def test_to_json_permissionrequestedpayload(): """Test that to_json produces valid JSON.""" json_data = r""" { + "requestId": "perm_abc123", + "toolCallId": "call_abc123", "permission": "tool.execute", - "target": "shell" + "target": "shell", + "promptRequest": "Allow shell to run tests?" } """ data = json.loads(json_data, strict=False) @@ -69,8 +90,11 @@ def test_to_yaml_permissionrequestedpayload(): """Test that to_yaml produces valid YAML.""" json_data = r""" { + "requestId": "perm_abc123", + "toolCallId": "call_abc123", "permission": "tool.execute", - "target": "shell" + "target": "shell", + "promptRequest": "Allow shell to run tests?" } """ data = json.loads(json_data, strict=False) diff --git a/runtime/python/prompty/tests/model/events/test_redacted_field.py b/runtime/python/prompty/tests/model/events/test_redacted_field.py new file mode 100644 index 00000000..cf006de8 --- /dev/null +++ b/runtime/python/prompty/tests/model/events/test_redacted_field.py @@ -0,0 +1,89 @@ +import json + +import yaml + +from prompty.model import RedactedField + + +def test_load_json_redactedfield(): + json_data = r""" + { + "path": "$.arguments.apiKey", + "mode": "redacted", + "reason": "secret" + } + """ + data = json.loads(json_data, strict=False) + instance = RedactedField.load(data) + assert instance is not None + assert instance.path == "$.arguments.apiKey" + assert instance.mode == "redacted" + assert instance.reason == "secret" + + +def test_load_yaml_redactedfield(): + yaml_data = r""" + path: $.arguments.apiKey + mode: redacted + reason: secret + + """ + data = yaml.load(yaml_data, Loader=yaml.FullLoader) + instance = RedactedField.load(data) + assert instance is not None + assert instance.path == "$.arguments.apiKey" + assert instance.mode == "redacted" + assert instance.reason == "secret" + + +def test_roundtrip_json_redactedfield(): + """Test that load -> save -> load produces equivalent data.""" + json_data = r""" + { + "path": "$.arguments.apiKey", + "mode": "redacted", + "reason": "secret" + } + """ + original_data = json.loads(json_data, strict=False) + instance = RedactedField.load(original_data) + saved_data = instance.save() + reloaded = RedactedField.load(saved_data) + assert reloaded is not None + assert reloaded.path == "$.arguments.apiKey" + assert reloaded.mode == "redacted" + assert reloaded.reason == "secret" + + +def test_to_json_redactedfield(): + """Test that to_json produces valid JSON.""" + json_data = r""" + { + "path": "$.arguments.apiKey", + "mode": "redacted", + "reason": "secret" + } + """ + data = json.loads(json_data, strict=False) + instance = RedactedField.load(data) + json_output = instance.to_json() + assert json_output is not None + parsed = json.loads(json_output) + assert isinstance(parsed, dict) + + +def test_to_yaml_redactedfield(): + """Test that to_yaml produces valid YAML.""" + json_data = r""" + { + "path": "$.arguments.apiKey", + "mode": "redacted", + "reason": "secret" + } + """ + data = json.loads(json_data, strict=False) + instance = RedactedField.load(data) + yaml_output = instance.to_yaml() + assert yaml_output is not None + parsed = yaml.safe_load(yaml_output) + assert isinstance(parsed, dict) diff --git a/runtime/python/prompty/tests/model/events/test_redaction_metadata.py b/runtime/python/prompty/tests/model/events/test_redaction_metadata.py new file mode 100644 index 00000000..ed11ded6 --- /dev/null +++ b/runtime/python/prompty/tests/model/events/test_redaction_metadata.py @@ -0,0 +1,81 @@ +import json + +import yaml + +from prompty.model import RedactionMetadata + + +def test_load_json_redactionmetadata(): + json_data = r""" + { + "sanitized": true, + "policy": "default-v1" + } + """ + data = json.loads(json_data, strict=False) + instance = RedactionMetadata.load(data) + assert instance is not None + assert instance.sanitized + assert instance.policy == "default-v1" + + +def test_load_yaml_redactionmetadata(): + yaml_data = r""" + sanitized: true + policy: default-v1 + + """ + data = yaml.load(yaml_data, Loader=yaml.FullLoader) + instance = RedactionMetadata.load(data) + assert instance is not None + assert instance.sanitized + assert instance.policy == "default-v1" + + +def test_roundtrip_json_redactionmetadata(): + """Test that load -> save -> load produces equivalent data.""" + json_data = r""" + { + "sanitized": true, + "policy": "default-v1" + } + """ + original_data = json.loads(json_data, strict=False) + instance = RedactionMetadata.load(original_data) + saved_data = instance.save() + reloaded = RedactionMetadata.load(saved_data) + assert reloaded is not None + assert reloaded.sanitized + assert reloaded.policy == "default-v1" + + +def test_to_json_redactionmetadata(): + """Test that to_json produces valid JSON.""" + json_data = r""" + { + "sanitized": true, + "policy": "default-v1" + } + """ + data = json.loads(json_data, strict=False) + instance = RedactionMetadata.load(data) + json_output = instance.to_json() + assert json_output is not None + parsed = json.loads(json_output) + assert isinstance(parsed, dict) + + +def test_to_yaml_redactionmetadata(): + """Test that to_yaml produces valid YAML.""" + json_data = r""" + { + "sanitized": true, + "policy": "default-v1" + } + """ + data = json.loads(json_data, strict=False) + instance = RedactionMetadata.load(data) + yaml_output = instance.to_yaml() + assert yaml_output is not None + parsed = yaml.safe_load(yaml_output) + assert isinstance(parsed, dict) diff --git a/runtime/python/prompty/tests/model/events/test_session_end_payload.py b/runtime/python/prompty/tests/model/events/test_session_end_payload.py new file mode 100644 index 00000000..63d34e7c --- /dev/null +++ b/runtime/python/prompty/tests/model/events/test_session_end_payload.py @@ -0,0 +1,97 @@ +import json + +import yaml + +from prompty.model import SessionEndPayload + + +def test_load_json_sessionendpayload(): + json_data = r""" + { + "sessionId": "sess_abc123", + "status": "success", + "reason": "complete", + "durationMs": 12500 + } + """ + data = json.loads(json_data, strict=False) + instance = SessionEndPayload.load(data) + assert instance is not None + assert instance.session_id == "sess_abc123" + assert instance.status == "success" + assert instance.reason == "complete" + assert instance.duration_ms == 12500 + + +def test_load_yaml_sessionendpayload(): + yaml_data = r""" + sessionId: sess_abc123 + status: success + reason: complete + durationMs: 12500 + + """ + data = yaml.load(yaml_data, Loader=yaml.FullLoader) + instance = SessionEndPayload.load(data) + assert instance is not None + assert instance.session_id == "sess_abc123" + assert instance.status == "success" + assert instance.reason == "complete" + assert instance.duration_ms == 12500 + + +def test_roundtrip_json_sessionendpayload(): + """Test that load -> save -> load produces equivalent data.""" + json_data = r""" + { + "sessionId": "sess_abc123", + "status": "success", + "reason": "complete", + "durationMs": 12500 + } + """ + original_data = json.loads(json_data, strict=False) + instance = SessionEndPayload.load(original_data) + saved_data = instance.save() + reloaded = SessionEndPayload.load(saved_data) + assert reloaded is not None + assert reloaded.session_id == "sess_abc123" + assert reloaded.status == "success" + assert reloaded.reason == "complete" + assert reloaded.duration_ms == 12500 + + +def test_to_json_sessionendpayload(): + """Test that to_json produces valid JSON.""" + json_data = r""" + { + "sessionId": "sess_abc123", + "status": "success", + "reason": "complete", + "durationMs": 12500 + } + """ + data = json.loads(json_data, strict=False) + instance = SessionEndPayload.load(data) + json_output = instance.to_json() + assert json_output is not None + parsed = json.loads(json_output) + assert isinstance(parsed, dict) + + +def test_to_yaml_sessionendpayload(): + """Test that to_yaml produces valid YAML.""" + json_data = r""" + { + "sessionId": "sess_abc123", + "status": "success", + "reason": "complete", + "durationMs": 12500 + } + """ + data = json.loads(json_data, strict=False) + instance = SessionEndPayload.load(data) + yaml_output = instance.to_yaml() + assert yaml_output is not None + parsed = yaml.safe_load(yaml_output) + assert isinstance(parsed, dict) diff --git a/runtime/python/prompty/tests/model/events/test_session_event.py b/runtime/python/prompty/tests/model/events/test_session_event.py new file mode 100644 index 00000000..19160b13 --- /dev/null +++ b/runtime/python/prompty/tests/model/events/test_session_event.py @@ -0,0 +1,113 @@ +import json + +import yaml + +from prompty.model import SessionEvent + + +def test_load_json_sessionevent(): + json_data = r""" + { + "id": "evt_abc123", + "timestamp": "2026-06-09T20:00:00Z", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "parentId": "evt_parent", + "spanId": "span_hook_001" + } + """ + data = json.loads(json_data, strict=False) + instance = SessionEvent.load(data) + assert instance is not None + assert instance.id == "evt_abc123" + assert instance.timestamp == "2026-06-09T20:00:00Z" + assert instance.session_id == "sess_abc123" + assert instance.turn_id == "turn_001" + assert instance.parent_id == "evt_parent" + assert instance.span_id == "span_hook_001" + + +def test_load_yaml_sessionevent(): + yaml_data = r""" + id: evt_abc123 + timestamp: "2026-06-09T20:00:00Z" + sessionId: sess_abc123 + turnId: turn_001 + parentId: evt_parent + spanId: span_hook_001 + + """ + data = yaml.load(yaml_data, Loader=yaml.FullLoader) + instance = SessionEvent.load(data) + assert instance is not None + assert instance.id == "evt_abc123" + assert instance.timestamp == "2026-06-09T20:00:00Z" + assert instance.session_id == "sess_abc123" + assert instance.turn_id == "turn_001" + assert instance.parent_id == "evt_parent" + assert instance.span_id == "span_hook_001" + + +def test_roundtrip_json_sessionevent(): + """Test that load -> save -> load produces equivalent data.""" + json_data = r""" + { + "id": "evt_abc123", + "timestamp": "2026-06-09T20:00:00Z", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "parentId": "evt_parent", + "spanId": "span_hook_001" + } + """ + original_data = json.loads(json_data, strict=False) + instance = SessionEvent.load(original_data) + saved_data = instance.save() + reloaded = SessionEvent.load(saved_data) + assert reloaded is not None + assert reloaded.id == "evt_abc123" + assert reloaded.timestamp == "2026-06-09T20:00:00Z" + assert reloaded.session_id == "sess_abc123" + assert reloaded.turn_id == "turn_001" + assert reloaded.parent_id == "evt_parent" + assert reloaded.span_id == "span_hook_001" + + +def test_to_json_sessionevent(): + """Test that to_json produces valid JSON.""" + json_data = r""" + { + "id": "evt_abc123", + "timestamp": "2026-06-09T20:00:00Z", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "parentId": "evt_parent", + "spanId": "span_hook_001" + } + """ + data = json.loads(json_data, strict=False) + instance = SessionEvent.load(data) + json_output = instance.to_json() + assert json_output is not None + parsed = json.loads(json_output) + assert isinstance(parsed, dict) + + +def test_to_yaml_sessionevent(): + """Test that to_yaml produces valid YAML.""" + json_data = r""" + { + "id": "evt_abc123", + "timestamp": "2026-06-09T20:00:00Z", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "parentId": "evt_parent", + "spanId": "span_hook_001" + } + """ + data = json.loads(json_data, strict=False) + instance = SessionEvent.load(data) + yaml_output = instance.to_yaml() + assert yaml_output is not None + parsed = yaml.safe_load(yaml_output) + assert isinstance(parsed, dict) diff --git a/runtime/python/prompty/tests/model/events/test_session_file_ref.py b/runtime/python/prompty/tests/model/events/test_session_file_ref.py new file mode 100644 index 00000000..91d92aa5 --- /dev/null +++ b/runtime/python/prompty/tests/model/events/test_session_file_ref.py @@ -0,0 +1,105 @@ +import json + +import yaml + +from prompty.model import SessionFileRef + + +def test_load_json_sessionfileref(): + json_data = r""" + { + "sessionId": "sess_abc123", + "path": "src/index.ts", + "toolName": "view", + "turnIndex": 2, + "firstSeenAt": "2026-06-09T20:00:00Z" + } + """ + data = json.loads(json_data, strict=False) + instance = SessionFileRef.load(data) + assert instance is not None + assert instance.session_id == "sess_abc123" + assert instance.path == "src/index.ts" + assert instance.tool_name == "view" + assert instance.turn_index == 2 + assert instance.first_seen_at == "2026-06-09T20:00:00Z" + + +def test_load_yaml_sessionfileref(): + yaml_data = r""" + sessionId: sess_abc123 + path: src/index.ts + toolName: view + turnIndex: 2 + firstSeenAt: "2026-06-09T20:00:00Z" + + """ + data = yaml.load(yaml_data, Loader=yaml.FullLoader) + instance = SessionFileRef.load(data) + assert instance is not None + assert instance.session_id == "sess_abc123" + assert instance.path == "src/index.ts" + assert instance.tool_name == "view" + assert instance.turn_index == 2 + assert instance.first_seen_at == "2026-06-09T20:00:00Z" + + +def test_roundtrip_json_sessionfileref(): + """Test that load -> save -> load produces equivalent data.""" + json_data = r""" + { + "sessionId": "sess_abc123", + "path": "src/index.ts", + "toolName": "view", + "turnIndex": 2, + "firstSeenAt": "2026-06-09T20:00:00Z" + } + """ + original_data = json.loads(json_data, strict=False) + instance = SessionFileRef.load(original_data) + saved_data = instance.save() + reloaded = SessionFileRef.load(saved_data) + assert reloaded is not None + assert reloaded.session_id == "sess_abc123" + assert reloaded.path == "src/index.ts" + assert reloaded.tool_name == "view" + assert reloaded.turn_index == 2 + assert reloaded.first_seen_at == "2026-06-09T20:00:00Z" + + +def test_to_json_sessionfileref(): + """Test that to_json produces valid JSON.""" + json_data = r""" + { + "sessionId": "sess_abc123", + "path": "src/index.ts", + "toolName": "view", + "turnIndex": 2, + "firstSeenAt": "2026-06-09T20:00:00Z" + } + """ + data = json.loads(json_data, strict=False) + instance = SessionFileRef.load(data) + json_output = instance.to_json() + assert json_output is not None + parsed = json.loads(json_output) + assert isinstance(parsed, dict) + + +def test_to_yaml_sessionfileref(): + """Test that to_yaml produces valid YAML.""" + json_data = r""" + { + "sessionId": "sess_abc123", + "path": "src/index.ts", + "toolName": "view", + "turnIndex": 2, + "firstSeenAt": "2026-06-09T20:00:00Z" + } + """ + data = json.loads(json_data, strict=False) + instance = SessionFileRef.load(data) + yaml_output = instance.to_yaml() + assert yaml_output is not None + parsed = yaml.safe_load(yaml_output) + assert isinstance(parsed, dict) diff --git a/runtime/python/prompty/tests/model/events/test_session_ref.py b/runtime/python/prompty/tests/model/events/test_session_ref.py new file mode 100644 index 00000000..167ac961 --- /dev/null +++ b/runtime/python/prompty/tests/model/events/test_session_ref.py @@ -0,0 +1,105 @@ +import json + +import yaml + +from prompty.model import SessionRef + + +def test_load_json_sessionref(): + json_data = r""" + { + "sessionId": "sess_abc123", + "refType": "issue", + "refValue": "owner/repo#123", + "turnIndex": 2, + "createdAt": "2026-06-09T20:00:00Z" + } + """ + data = json.loads(json_data, strict=False) + instance = SessionRef.load(data) + assert instance is not None + assert instance.session_id == "sess_abc123" + assert instance.ref_type == "issue" + assert instance.ref_value == "owner/repo#123" + assert instance.turn_index == 2 + assert instance.created_at == "2026-06-09T20:00:00Z" + + +def test_load_yaml_sessionref(): + yaml_data = r""" + sessionId: sess_abc123 + refType: issue + refValue: "owner/repo#123" + turnIndex: 2 + createdAt: "2026-06-09T20:00:00Z" + + """ + data = yaml.load(yaml_data, Loader=yaml.FullLoader) + instance = SessionRef.load(data) + assert instance is not None + assert instance.session_id == "sess_abc123" + assert instance.ref_type == "issue" + assert instance.ref_value == "owner/repo#123" + assert instance.turn_index == 2 + assert instance.created_at == "2026-06-09T20:00:00Z" + + +def test_roundtrip_json_sessionref(): + """Test that load -> save -> load produces equivalent data.""" + json_data = r""" + { + "sessionId": "sess_abc123", + "refType": "issue", + "refValue": "owner/repo#123", + "turnIndex": 2, + "createdAt": "2026-06-09T20:00:00Z" + } + """ + original_data = json.loads(json_data, strict=False) + instance = SessionRef.load(original_data) + saved_data = instance.save() + reloaded = SessionRef.load(saved_data) + assert reloaded is not None + assert reloaded.session_id == "sess_abc123" + assert reloaded.ref_type == "issue" + assert reloaded.ref_value == "owner/repo#123" + assert reloaded.turn_index == 2 + assert reloaded.created_at == "2026-06-09T20:00:00Z" + + +def test_to_json_sessionref(): + """Test that to_json produces valid JSON.""" + json_data = r""" + { + "sessionId": "sess_abc123", + "refType": "issue", + "refValue": "owner/repo#123", + "turnIndex": 2, + "createdAt": "2026-06-09T20:00:00Z" + } + """ + data = json.loads(json_data, strict=False) + instance = SessionRef.load(data) + json_output = instance.to_json() + assert json_output is not None + parsed = json.loads(json_output) + assert isinstance(parsed, dict) + + +def test_to_yaml_sessionref(): + """Test that to_yaml produces valid YAML.""" + json_data = r""" + { + "sessionId": "sess_abc123", + "refType": "issue", + "refValue": "owner/repo#123", + "turnIndex": 2, + "createdAt": "2026-06-09T20:00:00Z" + } + """ + data = json.loads(json_data, strict=False) + instance = SessionRef.load(data) + yaml_output = instance.to_yaml() + assert yaml_output is not None + parsed = yaml.safe_load(yaml_output) + assert isinstance(parsed, dict) diff --git a/runtime/python/prompty/tests/model/events/test_session_start_payload.py b/runtime/python/prompty/tests/model/events/test_session_start_payload.py new file mode 100644 index 00000000..bd989baf --- /dev/null +++ b/runtime/python/prompty/tests/model/events/test_session_start_payload.py @@ -0,0 +1,129 @@ +import json + +import yaml + +from prompty.model import SessionStartPayload + + +def test_load_json_sessionstartpayload(): + json_data = r""" + { + "sessionId": "sess_abc123", + "version": 1, + "producer": "prompty-agent", + "runtime": "typescript", + "promptyVersion": "2.0.0", + "startTime": "2026-06-09T20:00:00Z", + "selectedModel": "gpt-4o-mini", + "reasoningEffort": "medium" + } + """ + data = json.loads(json_data, strict=False) + instance = SessionStartPayload.load(data) + assert instance is not None + assert instance.session_id == "sess_abc123" + assert instance.version == 1 + assert instance.producer == "prompty-agent" + assert instance.runtime == "typescript" + assert instance.prompty_version == "2.0.0" + assert instance.start_time == "2026-06-09T20:00:00Z" + assert instance.selected_model == "gpt-4o-mini" + assert instance.reasoning_effort == "medium" + + +def test_load_yaml_sessionstartpayload(): + yaml_data = r""" + sessionId: sess_abc123 + version: 1 + producer: prompty-agent + runtime: typescript + promptyVersion: 2.0.0 + startTime: "2026-06-09T20:00:00Z" + selectedModel: gpt-4o-mini + reasoningEffort: medium + + """ + data = yaml.load(yaml_data, Loader=yaml.FullLoader) + instance = SessionStartPayload.load(data) + assert instance is not None + assert instance.session_id == "sess_abc123" + assert instance.version == 1 + assert instance.producer == "prompty-agent" + assert instance.runtime == "typescript" + assert instance.prompty_version == "2.0.0" + assert instance.start_time == "2026-06-09T20:00:00Z" + assert instance.selected_model == "gpt-4o-mini" + assert instance.reasoning_effort == "medium" + + +def test_roundtrip_json_sessionstartpayload(): + """Test that load -> save -> load produces equivalent data.""" + json_data = r""" + { + "sessionId": "sess_abc123", + "version": 1, + "producer": "prompty-agent", + "runtime": "typescript", + "promptyVersion": "2.0.0", + "startTime": "2026-06-09T20:00:00Z", + "selectedModel": "gpt-4o-mini", + "reasoningEffort": "medium" + } + """ + original_data = json.loads(json_data, strict=False) + instance = SessionStartPayload.load(original_data) + saved_data = instance.save() + reloaded = SessionStartPayload.load(saved_data) + assert reloaded is not None + assert reloaded.session_id == "sess_abc123" + assert reloaded.version == 1 + assert reloaded.producer == "prompty-agent" + assert reloaded.runtime == "typescript" + assert reloaded.prompty_version == "2.0.0" + assert reloaded.start_time == "2026-06-09T20:00:00Z" + assert reloaded.selected_model == "gpt-4o-mini" + assert reloaded.reasoning_effort == "medium" + + +def test_to_json_sessionstartpayload(): + """Test that to_json produces valid JSON.""" + json_data = r""" + { + "sessionId": "sess_abc123", + "version": 1, + "producer": "prompty-agent", + "runtime": "typescript", + "promptyVersion": "2.0.0", + "startTime": "2026-06-09T20:00:00Z", + "selectedModel": "gpt-4o-mini", + "reasoningEffort": "medium" + } + """ + data = json.loads(json_data, strict=False) + instance = SessionStartPayload.load(data) + json_output = instance.to_json() + assert json_output is not None + parsed = json.loads(json_output) + assert isinstance(parsed, dict) + + +def test_to_yaml_sessionstartpayload(): + """Test that to_yaml produces valid YAML.""" + json_data = r""" + { + "sessionId": "sess_abc123", + "version": 1, + "producer": "prompty-agent", + "runtime": "typescript", + "promptyVersion": "2.0.0", + "startTime": "2026-06-09T20:00:00Z", + "selectedModel": "gpt-4o-mini", + "reasoningEffort": "medium" + } + """ + data = json.loads(json_data, strict=False) + instance = SessionStartPayload.load(data) + yaml_output = instance.to_yaml() + assert yaml_output is not None + parsed = yaml.safe_load(yaml_output) + assert isinstance(parsed, dict) diff --git a/runtime/python/prompty/tests/model/events/test_session_summary.py b/runtime/python/prompty/tests/model/events/test_session_summary.py new file mode 100644 index 00000000..f1cbf05a --- /dev/null +++ b/runtime/python/prompty/tests/model/events/test_session_summary.py @@ -0,0 +1,105 @@ +import json + +import yaml + +from prompty.model import SessionSummary + + +def test_load_json_sessionsummary(): + json_data = r""" + { + "sessionId": "sess_abc123", + "status": "success", + "turns": 5, + "checkpoints": 2, + "durationMs": 12500 + } + """ + data = json.loads(json_data, strict=False) + instance = SessionSummary.load(data) + assert instance is not None + assert instance.session_id == "sess_abc123" + assert instance.status == "success" + assert instance.turns == 5 + assert instance.checkpoints == 2 + assert instance.duration_ms == 12500 + + +def test_load_yaml_sessionsummary(): + yaml_data = r""" + sessionId: sess_abc123 + status: success + turns: 5 + checkpoints: 2 + durationMs: 12500 + + """ + data = yaml.load(yaml_data, Loader=yaml.FullLoader) + instance = SessionSummary.load(data) + assert instance is not None + assert instance.session_id == "sess_abc123" + assert instance.status == "success" + assert instance.turns == 5 + assert instance.checkpoints == 2 + assert instance.duration_ms == 12500 + + +def test_roundtrip_json_sessionsummary(): + """Test that load -> save -> load produces equivalent data.""" + json_data = r""" + { + "sessionId": "sess_abc123", + "status": "success", + "turns": 5, + "checkpoints": 2, + "durationMs": 12500 + } + """ + original_data = json.loads(json_data, strict=False) + instance = SessionSummary.load(original_data) + saved_data = instance.save() + reloaded = SessionSummary.load(saved_data) + assert reloaded is not None + assert reloaded.session_id == "sess_abc123" + assert reloaded.status == "success" + assert reloaded.turns == 5 + assert reloaded.checkpoints == 2 + assert reloaded.duration_ms == 12500 + + +def test_to_json_sessionsummary(): + """Test that to_json produces valid JSON.""" + json_data = r""" + { + "sessionId": "sess_abc123", + "status": "success", + "turns": 5, + "checkpoints": 2, + "durationMs": 12500 + } + """ + data = json.loads(json_data, strict=False) + instance = SessionSummary.load(data) + json_output = instance.to_json() + assert json_output is not None + parsed = json.loads(json_output) + assert isinstance(parsed, dict) + + +def test_to_yaml_sessionsummary(): + """Test that to_yaml produces valid YAML.""" + json_data = r""" + { + "sessionId": "sess_abc123", + "status": "success", + "turns": 5, + "checkpoints": 2, + "durationMs": 12500 + } + """ + data = json.loads(json_data, strict=False) + instance = SessionSummary.load(data) + yaml_output = instance.to_yaml() + assert yaml_output is not None + parsed = yaml.safe_load(yaml_output) + assert isinstance(parsed, dict) diff --git a/runtime/python/prompty/tests/model/events/test_session_trace.py b/runtime/python/prompty/tests/model/events/test_session_trace.py new file mode 100644 index 00000000..095784dc --- /dev/null +++ b/runtime/python/prompty/tests/model/events/test_session_trace.py @@ -0,0 +1,97 @@ +import json + +import yaml + +from prompty.model import SessionTrace + + +def test_load_json_sessiontrace(): + json_data = r""" + { + "version": "1", + "runtime": "typescript", + "promptyVersion": "2.0.0", + "sessionId": "sess_abc123" + } + """ + data = json.loads(json_data, strict=False) + instance = SessionTrace.load(data) + assert instance is not None + assert instance.version == "1" + assert instance.runtime == "typescript" + assert instance.prompty_version == "2.0.0" + assert instance.session_id == "sess_abc123" + + +def test_load_yaml_sessiontrace(): + yaml_data = r""" + version: "1" + runtime: typescript + promptyVersion: 2.0.0 + sessionId: sess_abc123 + + """ + data = yaml.load(yaml_data, Loader=yaml.FullLoader) + instance = SessionTrace.load(data) + assert instance is not None + assert instance.version == "1" + assert instance.runtime == "typescript" + assert instance.prompty_version == "2.0.0" + assert instance.session_id == "sess_abc123" + + +def test_roundtrip_json_sessiontrace(): + """Test that load -> save -> load produces equivalent data.""" + json_data = r""" + { + "version": "1", + "runtime": "typescript", + "promptyVersion": "2.0.0", + "sessionId": "sess_abc123" + } + """ + original_data = json.loads(json_data, strict=False) + instance = SessionTrace.load(original_data) + saved_data = instance.save() + reloaded = SessionTrace.load(saved_data) + assert reloaded is not None + assert reloaded.version == "1" + assert reloaded.runtime == "typescript" + assert reloaded.prompty_version == "2.0.0" + assert reloaded.session_id == "sess_abc123" + + +def test_to_json_sessiontrace(): + """Test that to_json produces valid JSON.""" + json_data = r""" + { + "version": "1", + "runtime": "typescript", + "promptyVersion": "2.0.0", + "sessionId": "sess_abc123" + } + """ + data = json.loads(json_data, strict=False) + instance = SessionTrace.load(data) + json_output = instance.to_json() + assert json_output is not None + parsed = json.loads(json_output) + assert isinstance(parsed, dict) + + +def test_to_yaml_sessiontrace(): + """Test that to_yaml produces valid YAML.""" + json_data = r""" + { + "version": "1", + "runtime": "typescript", + "promptyVersion": "2.0.0", + "sessionId": "sess_abc123" + } + """ + data = json.loads(json_data, strict=False) + instance = SessionTrace.load(data) + yaml_output = instance.to_yaml() + assert yaml_output is not None + parsed = yaml.safe_load(yaml_output) + assert isinstance(parsed, dict) diff --git a/runtime/python/prompty/tests/model/events/test_session_warning_payload.py b/runtime/python/prompty/tests/model/events/test_session_warning_payload.py new file mode 100644 index 00000000..75a58b67 --- /dev/null +++ b/runtime/python/prompty/tests/model/events/test_session_warning_payload.py @@ -0,0 +1,81 @@ +import json + +import yaml + +from prompty.model import SessionWarningPayload + + +def test_load_json_sessionwarningpayload(): + json_data = r""" + { + "warningType": "remote", + "message": "Remote session disabled" + } + """ + data = json.loads(json_data, strict=False) + instance = SessionWarningPayload.load(data) + assert instance is not None + assert instance.warning_type == "remote" + assert instance.message == "Remote session disabled" + + +def test_load_yaml_sessionwarningpayload(): + yaml_data = r""" + warningType: remote + message: Remote session disabled + + """ + data = yaml.load(yaml_data, Loader=yaml.FullLoader) + instance = SessionWarningPayload.load(data) + assert instance is not None + assert instance.warning_type == "remote" + assert instance.message == "Remote session disabled" + + +def test_roundtrip_json_sessionwarningpayload(): + """Test that load -> save -> load produces equivalent data.""" + json_data = r""" + { + "warningType": "remote", + "message": "Remote session disabled" + } + """ + original_data = json.loads(json_data, strict=False) + instance = SessionWarningPayload.load(original_data) + saved_data = instance.save() + reloaded = SessionWarningPayload.load(saved_data) + assert reloaded is not None + assert reloaded.warning_type == "remote" + assert reloaded.message == "Remote session disabled" + + +def test_to_json_sessionwarningpayload(): + """Test that to_json produces valid JSON.""" + json_data = r""" + { + "warningType": "remote", + "message": "Remote session disabled" + } + """ + data = json.loads(json_data, strict=False) + instance = SessionWarningPayload.load(data) + json_output = instance.to_json() + assert json_output is not None + parsed = json.loads(json_output) + assert isinstance(parsed, dict) + + +def test_to_yaml_sessionwarningpayload(): + """Test that to_yaml produces valid YAML.""" + json_data = r""" + { + "warningType": "remote", + "message": "Remote session disabled" + } + """ + data = json.loads(json_data, strict=False) + instance = SessionWarningPayload.load(data) + yaml_output = instance.to_yaml() + assert yaml_output is not None + parsed = yaml.safe_load(yaml_output) + assert isinstance(parsed, dict) diff --git a/runtime/python/prompty/tests/model/events/test_tool_execution_complete_payload.py b/runtime/python/prompty/tests/model/events/test_tool_execution_complete_payload.py new file mode 100644 index 00000000..3a83bba7 --- /dev/null +++ b/runtime/python/prompty/tests/model/events/test_tool_execution_complete_payload.py @@ -0,0 +1,121 @@ +import json + +import yaml + +from prompty.model import ToolExecutionCompletePayload + + +def test_load_json_toolexecutioncompletepayload(): + json_data = r""" + { + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "success": true, + "exitCode": 0, + "durationMs": 250, + "errorKind": "timeout" + } + """ + data = json.loads(json_data, strict=False) + instance = ToolExecutionCompletePayload.load(data) + assert instance is not None + assert instance.request_id == "exec_abc123" + assert instance.tool_call_id == "call_abc123" + assert instance.tool_name == "powershell" + assert instance.success + assert instance.exit_code == 0 + assert instance.duration_ms == 250 + assert instance.error_kind == "timeout" + + +def test_load_yaml_toolexecutioncompletepayload(): + yaml_data = r""" + requestId: exec_abc123 + toolCallId: call_abc123 + toolName: powershell + success: true + exitCode: 0 + durationMs: 250 + errorKind: timeout + + """ + data = yaml.load(yaml_data, Loader=yaml.FullLoader) + instance = ToolExecutionCompletePayload.load(data) + assert instance is not None + assert instance.request_id == "exec_abc123" + assert instance.tool_call_id == "call_abc123" + assert instance.tool_name == "powershell" + assert instance.success + assert instance.exit_code == 0 + assert instance.duration_ms == 250 + assert instance.error_kind == "timeout" + + +def test_roundtrip_json_toolexecutioncompletepayload(): + """Test that load -> save -> load produces equivalent data.""" + json_data = r""" + { + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "success": true, + "exitCode": 0, + "durationMs": 250, + "errorKind": "timeout" + } + """ + original_data = json.loads(json_data, strict=False) + instance = ToolExecutionCompletePayload.load(original_data) + saved_data = instance.save() + reloaded = ToolExecutionCompletePayload.load(saved_data) + assert reloaded is not None + assert reloaded.request_id == "exec_abc123" + assert reloaded.tool_call_id == "call_abc123" + assert reloaded.tool_name == "powershell" + assert reloaded.success + assert reloaded.exit_code == 0 + assert reloaded.duration_ms == 250 + assert reloaded.error_kind == "timeout" + + +def test_to_json_toolexecutioncompletepayload(): + """Test that to_json produces valid JSON.""" + json_data = r""" + { + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "success": true, + "exitCode": 0, + "durationMs": 250, + "errorKind": "timeout" + } + """ + data = json.loads(json_data, strict=False) + instance = ToolExecutionCompletePayload.load(data) + json_output = instance.to_json() + assert json_output is not None + parsed = json.loads(json_output) + assert isinstance(parsed, dict) + + +def test_to_yaml_toolexecutioncompletepayload(): + """Test that to_yaml produces valid YAML.""" + json_data = r""" + { + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "success": true, + "exitCode": 0, + "durationMs": 250, + "errorKind": "timeout" + } + """ + data = json.loads(json_data, strict=False) + instance = ToolExecutionCompletePayload.load(data) + yaml_output = instance.to_yaml() + assert yaml_output is not None + parsed = yaml.safe_load(yaml_output) + assert isinstance(parsed, dict) diff --git a/runtime/python/prompty/tests/model/events/test_tool_execution_start_payload.py b/runtime/python/prompty/tests/model/events/test_tool_execution_start_payload.py new file mode 100644 index 00000000..be931ff4 --- /dev/null +++ b/runtime/python/prompty/tests/model/events/test_tool_execution_start_payload.py @@ -0,0 +1,97 @@ +import json + +import yaml + +from prompty.model import ToolExecutionStartPayload + + +def test_load_json_toolexecutionstartpayload(): + json_data = r""" + { + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "workingDirectory": "/workspace/project" + } + """ + data = json.loads(json_data, strict=False) + instance = ToolExecutionStartPayload.load(data) + assert instance is not None + assert instance.request_id == "exec_abc123" + assert instance.tool_call_id == "call_abc123" + assert instance.tool_name == "powershell" + assert instance.working_directory == "/workspace/project" + + +def test_load_yaml_toolexecutionstartpayload(): + yaml_data = r""" + requestId: exec_abc123 + toolCallId: call_abc123 + toolName: powershell + workingDirectory: /workspace/project + + """ + data = yaml.load(yaml_data, Loader=yaml.FullLoader) + instance = ToolExecutionStartPayload.load(data) + assert instance is not None + assert instance.request_id == "exec_abc123" + assert instance.tool_call_id == "call_abc123" + assert instance.tool_name == "powershell" + assert instance.working_directory == "/workspace/project" + + +def test_roundtrip_json_toolexecutionstartpayload(): + """Test that load -> save -> load produces equivalent data.""" + json_data = r""" + { + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "workingDirectory": "/workspace/project" + } + """ + original_data = json.loads(json_data, strict=False) + instance = ToolExecutionStartPayload.load(original_data) + saved_data = instance.save() + reloaded = ToolExecutionStartPayload.load(saved_data) + assert reloaded is not None + assert reloaded.request_id == "exec_abc123" + assert reloaded.tool_call_id == "call_abc123" + assert reloaded.tool_name == "powershell" + assert reloaded.working_directory == "/workspace/project" + + +def test_to_json_toolexecutionstartpayload(): + """Test that to_json produces valid JSON.""" + json_data = r""" + { + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "workingDirectory": "/workspace/project" + } + """ + data = json.loads(json_data, strict=False) + instance = ToolExecutionStartPayload.load(data) + json_output = instance.to_json() + assert json_output is not None + parsed = json.loads(json_output) + assert isinstance(parsed, dict) + + +def test_to_yaml_toolexecutionstartpayload(): + """Test that to_yaml produces valid YAML.""" + json_data = r""" + { + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "workingDirectory": "/workspace/project" + } + """ + data = json.loads(json_data, strict=False) + instance = ToolExecutionStartPayload.load(data) + yaml_output = instance.to_yaml() + assert yaml_output is not None + parsed = yaml.safe_load(yaml_output) + assert isinstance(parsed, dict) diff --git a/runtime/python/prompty/tests/model/events/test_trajectory_event.py b/runtime/python/prompty/tests/model/events/test_trajectory_event.py new file mode 100644 index 00000000..8cce6486 --- /dev/null +++ b/runtime/python/prompty/tests/model/events/test_trajectory_event.py @@ -0,0 +1,121 @@ +import json + +import yaml + +from prompty.model import TrajectoryEvent + + +def test_load_json_trajectoryevent(): + json_data = r""" + { + "id": "traj_abc123", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "toolCallId": "call_abc123", + "turnIndex": 4, + "eventType": "command", + "createdAt": "2026-06-09T20:00:00Z" + } + """ + data = json.loads(json_data, strict=False) + instance = TrajectoryEvent.load(data) + assert instance is not None + assert instance.id == "traj_abc123" + assert instance.session_id == "sess_abc123" + assert instance.turn_id == "turn_001" + assert instance.tool_call_id == "call_abc123" + assert instance.turn_index == 4 + assert instance.event_type == "command" + assert instance.created_at == "2026-06-09T20:00:00Z" + + +def test_load_yaml_trajectoryevent(): + yaml_data = r""" + id: traj_abc123 + sessionId: sess_abc123 + turnId: turn_001 + toolCallId: call_abc123 + turnIndex: 4 + eventType: command + createdAt: "2026-06-09T20:00:00Z" + + """ + data = yaml.load(yaml_data, Loader=yaml.FullLoader) + instance = TrajectoryEvent.load(data) + assert instance is not None + assert instance.id == "traj_abc123" + assert instance.session_id == "sess_abc123" + assert instance.turn_id == "turn_001" + assert instance.tool_call_id == "call_abc123" + assert instance.turn_index == 4 + assert instance.event_type == "command" + assert instance.created_at == "2026-06-09T20:00:00Z" + + +def test_roundtrip_json_trajectoryevent(): + """Test that load -> save -> load produces equivalent data.""" + json_data = r""" + { + "id": "traj_abc123", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "toolCallId": "call_abc123", + "turnIndex": 4, + "eventType": "command", + "createdAt": "2026-06-09T20:00:00Z" + } + """ + original_data = json.loads(json_data, strict=False) + instance = TrajectoryEvent.load(original_data) + saved_data = instance.save() + reloaded = TrajectoryEvent.load(saved_data) + assert reloaded is not None + assert reloaded.id == "traj_abc123" + assert reloaded.session_id == "sess_abc123" + assert reloaded.turn_id == "turn_001" + assert reloaded.tool_call_id == "call_abc123" + assert reloaded.turn_index == 4 + assert reloaded.event_type == "command" + assert reloaded.created_at == "2026-06-09T20:00:00Z" + + +def test_to_json_trajectoryevent(): + """Test that to_json produces valid JSON.""" + json_data = r""" + { + "id": "traj_abc123", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "toolCallId": "call_abc123", + "turnIndex": 4, + "eventType": "command", + "createdAt": "2026-06-09T20:00:00Z" + } + """ + data = json.loads(json_data, strict=False) + instance = TrajectoryEvent.load(data) + json_output = instance.to_json() + assert json_output is not None + parsed = json.loads(json_output) + assert isinstance(parsed, dict) + + +def test_to_yaml_trajectoryevent(): + """Test that to_yaml produces valid YAML.""" + json_data = r""" + { + "id": "traj_abc123", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "toolCallId": "call_abc123", + "turnIndex": 4, + "eventType": "command", + "createdAt": "2026-06-09T20:00:00Z" + } + """ + data = json.loads(json_data, strict=False) + instance = TrajectoryEvent.load(data) + yaml_output = instance.to_yaml() + assert yaml_output is not None + parsed = yaml.safe_load(yaml_output) + assert isinstance(parsed, dict) diff --git a/runtime/rust/prompty/src/model/events/checkpoint.rs b/runtime/rust/prompty/src/model/events/checkpoint.rs new file mode 100644 index 00000000..0fda30d5 --- /dev/null +++ b/runtime/rust/prompty/src/model/events/checkpoint.rs @@ -0,0 +1,140 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use super::super::context::{LoadContext, SaveContext}; + +use super::redaction_metadata::RedactionMetadata; + +/// A persisted handoff point for a harness session. +#[derive(Debug, Clone, Default)] +pub struct Checkpoint { + /// Stable checkpoint identifier + pub id: Option, + /// Stable session identifier + pub session_id: Option, + /// Associated turn identifier, when the checkpoint was created inside a turn + pub turn_id: Option, + /// Monotonic checkpoint number within the session + pub checkpoint_number: Option, + /// Short checkpoint title + pub title: String, + /// Short human-readable overview + pub overview: Option, + /// Portable checkpoint state needed to resume or hand off the session + pub state: serde_json::Value, + /// Optional host-authored summary or handoff note + pub summary: Option, + /// Host-defined checkpoint metadata + pub metadata: serde_json::Value, + /// ISO 8601 UTC timestamp when the checkpoint was created + pub created_at: Option, + /// Redaction state for sensitive checkpoint fields + pub redaction: Option, +} + +impl Checkpoint { + /// Create a new Checkpoint with default values. + pub fn new() -> Self { + Self::default() + } + + /// Load Checkpoint from a JSON string. + pub fn from_json(json: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_json::from_str(json)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load Checkpoint from a YAML string. + pub fn from_yaml(yaml: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_yaml::from_str(yaml)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load Checkpoint from a `serde_json::Value`. + /// + /// Calls `ctx.process_input` before field extraction. + pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { + let value = ctx.process_input(value.clone()); + Self { + id: value.get("id").and_then(|v| v.as_str()).map(|s| s.to_string()), + session_id: value.get("sessionId").and_then(|v| v.as_str()).map(|s| s.to_string()), + turn_id: value.get("turnId").and_then(|v| v.as_str()).map(|s| s.to_string()), + checkpoint_number: value.get("checkpointNumber").and_then(|v| v.as_i64()).map(|v| v as i32), + title: value.get("title").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + overview: value.get("overview").and_then(|v| v.as_str()).map(|s| s.to_string()), + state: value.get("state").cloned().unwrap_or(serde_json::Value::Null), + summary: value.get("summary").and_then(|v| v.as_str()).map(|s| s.to_string()), + metadata: value.get("metadata").cloned().unwrap_or(serde_json::Value::Null), + created_at: value.get("createdAt").and_then(|v| v.as_str()).map(|s| s.to_string()), + redaction: value.get("redaction").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| RedactionMetadata::load_from_value(v, ctx)), + } + } + + /// Serialize Checkpoint to a `serde_json::Value`. + /// + /// Calls `ctx.process_dict` after serialization. + pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { + let mut result = serde_json::Map::new(); + // Write base fields + if let Some(ref val) = self.id { + result.insert("id".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(ref val) = self.session_id { + result.insert("sessionId".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(ref val) = self.turn_id { + result.insert("turnId".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(val) = self.checkpoint_number { + result.insert("checkpointNumber".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + } + if !self.title.is_empty() { + result.insert("title".to_string(), serde_json::Value::String(self.title.clone())); + } + if let Some(ref val) = self.overview { + result.insert("overview".to_string(), serde_json::Value::String(val.clone())); + } + if !self.state.is_null() { + result.insert("state".to_string(), self.state.clone()); + } + if let Some(ref val) = self.summary { + result.insert("summary".to_string(), serde_json::Value::String(val.clone())); + } + if !self.metadata.is_null() { + result.insert("metadata".to_string(), self.metadata.clone()); + } + if let Some(ref val) = self.created_at { + result.insert("createdAt".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(ref val) = self.redaction { + let nested = val.to_value(ctx); + if !nested.is_null() { + result.insert("redaction".to_string(), nested); + } + } + ctx.process_dict(serde_json::Value::Object(result)) + } + + /// Serialize Checkpoint to a JSON string. + pub fn to_json(&self, ctx: &SaveContext) -> Result { + serde_json::to_string_pretty(&self.to_value(ctx)) + } + + /// Serialize Checkpoint to a YAML string. + pub fn to_yaml(&self, ctx: &SaveContext) -> Result { + serde_yaml::to_string(&self.to_value(ctx)) + } + /// Returns typed reference to the map if the field is an object. + /// Returns `None` if the field is null or not an object. + pub fn as_state_dict(&self) -> Option<&serde_json::Map> { + self.state.as_object() + } + + /// Returns typed reference to the map if the field is an object. + /// Returns `None` if the field is null or not an object. + pub fn as_metadata_dict(&self) -> Option<&serde_json::Map> { + self.metadata.as_object() + } + +} diff --git a/runtime/rust/prompty/src/model/events/harness_context.rs b/runtime/rust/prompty/src/model/events/harness_context.rs new file mode 100644 index 00000000..1f53dc88 --- /dev/null +++ b/runtime/rust/prompty/src/model/events/harness_context.rs @@ -0,0 +1,81 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use super::super::context::{LoadContext, SaveContext}; + +/// Execution context associated with a harness session. Host-specific environments can store detailed profiles in metadata without making the core contract depend on one source-control provider or workspace shape. +#[derive(Debug, Clone, Default)] +pub struct HarnessContext { + /// Current working directory for the harness + pub cwd: Option, + /// Git repository root, when known + pub git_root: Option, + /// Host-defined context metadata, such as source-control or sandbox details + pub metadata: serde_json::Value, +} + +impl HarnessContext { + /// Create a new HarnessContext with default values. + pub fn new() -> Self { + Self::default() + } + + /// Load HarnessContext from a JSON string. + pub fn from_json(json: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_json::from_str(json)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load HarnessContext from a YAML string. + pub fn from_yaml(yaml: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_yaml::from_str(yaml)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load HarnessContext from a `serde_json::Value`. + /// + /// Calls `ctx.process_input` before field extraction. + pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { + let value = ctx.process_input(value.clone()); + Self { + cwd: value.get("cwd").and_then(|v| v.as_str()).map(|s| s.to_string()), + git_root: value.get("gitRoot").and_then(|v| v.as_str()).map(|s| s.to_string()), + metadata: value.get("metadata").cloned().unwrap_or(serde_json::Value::Null), + } + } + + /// Serialize HarnessContext to a `serde_json::Value`. + /// + /// Calls `ctx.process_dict` after serialization. + pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { + let mut result = serde_json::Map::new(); + // Write base fields + if let Some(ref val) = self.cwd { + result.insert("cwd".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(ref val) = self.git_root { + result.insert("gitRoot".to_string(), serde_json::Value::String(val.clone())); + } + if !self.metadata.is_null() { + result.insert("metadata".to_string(), self.metadata.clone()); + } + ctx.process_dict(serde_json::Value::Object(result)) + } + + /// Serialize HarnessContext to a JSON string. + pub fn to_json(&self, ctx: &SaveContext) -> Result { + serde_json::to_string_pretty(&self.to_value(ctx)) + } + + /// Serialize HarnessContext to a YAML string. + pub fn to_yaml(&self, ctx: &SaveContext) -> Result { + serde_yaml::to_string(&self.to_value(ctx)) + } + /// Returns typed reference to the map if the field is an object. + /// Returns `None` if the field is null or not an object. + pub fn as_metadata_dict(&self) -> Option<&serde_json::Map> { + self.metadata.as_object() + } + +} diff --git a/runtime/rust/prompty/src/model/events/hook_end_payload.rs b/runtime/rust/prompty/src/model/events/hook_end_payload.rs new file mode 100644 index 00000000..9fc3b2c0 --- /dev/null +++ b/runtime/rust/prompty/src/model/events/hook_end_payload.rs @@ -0,0 +1,108 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use super::super::context::{LoadContext, SaveContext}; + +use super::redaction_metadata::RedactionMetadata; + +/// Payload for "hook_end" events — a host lifecycle hook finished. +#[derive(Debug, Clone, Default)] +pub struct HookEndPayload { + /// Stable hook invocation identifier + pub hook_invocation_id: String, + /// Host-defined hook type + pub hook_type: String, + /// Whether the hook completed successfully + pub success: bool, + /// Hook output after host-side sanitization + pub output: serde_json::Value, + /// Hook execution duration in milliseconds + pub duration_ms: Option, + /// Human-readable error when success is false + pub error: Option, + /// Redaction state for sensitive hook output fields + pub redaction: Option, +} + +impl HookEndPayload { + /// Create a new HookEndPayload with default values. + pub fn new() -> Self { + Self::default() + } + + /// Load HookEndPayload from a JSON string. + pub fn from_json(json: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_json::from_str(json)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load HookEndPayload from a YAML string. + pub fn from_yaml(yaml: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_yaml::from_str(yaml)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load HookEndPayload from a `serde_json::Value`. + /// + /// Calls `ctx.process_input` before field extraction. + pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { + let value = ctx.process_input(value.clone()); + Self { + hook_invocation_id: value.get("hookInvocationId").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + hook_type: value.get("hookType").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + success: value.get("success").and_then(|v| v.as_bool()).unwrap_or(false), + output: value.get("output").cloned().unwrap_or(serde_json::Value::Null), + duration_ms: value.get("durationMs").and_then(|v| v.as_f64()), + error: value.get("error").and_then(|v| v.as_str()).map(|s| s.to_string()), + redaction: value.get("redaction").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| RedactionMetadata::load_from_value(v, ctx)), + } + } + + /// Serialize HookEndPayload to a `serde_json::Value`. + /// + /// Calls `ctx.process_dict` after serialization. + pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { + let mut result = serde_json::Map::new(); + // Write base fields + if !self.hook_invocation_id.is_empty() { + result.insert("hookInvocationId".to_string(), serde_json::Value::String(self.hook_invocation_id.clone())); + } + if !self.hook_type.is_empty() { + result.insert("hookType".to_string(), serde_json::Value::String(self.hook_type.clone())); + } + result.insert("success".to_string(), serde_json::Value::Bool(self.success)); + if !self.output.is_null() { + result.insert("output".to_string(), self.output.clone()); + } + if let Some(val) = self.duration_ms { + result.insert("durationMs".to_string(), serde_json::Number::from_f64(val as f64).map(serde_json::Value::Number).unwrap_or(serde_json::Value::Null)); + } + if let Some(ref val) = self.error { + result.insert("error".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(ref val) = self.redaction { + let nested = val.to_value(ctx); + if !nested.is_null() { + result.insert("redaction".to_string(), nested); + } + } + ctx.process_dict(serde_json::Value::Object(result)) + } + + /// Serialize HookEndPayload to a JSON string. + pub fn to_json(&self, ctx: &SaveContext) -> Result { + serde_json::to_string_pretty(&self.to_value(ctx)) + } + + /// Serialize HookEndPayload to a YAML string. + pub fn to_yaml(&self, ctx: &SaveContext) -> Result { + serde_yaml::to_string(&self.to_value(ctx)) + } + /// Returns typed reference to the map if the field is an object. + /// Returns `None` if the field is null or not an object. + pub fn as_output_dict(&self) -> Option<&serde_json::Map> { + self.output.as_object() + } + +} diff --git a/runtime/rust/prompty/src/model/events/hook_start_payload.rs b/runtime/rust/prompty/src/model/events/hook_start_payload.rs new file mode 100644 index 00000000..8b785312 --- /dev/null +++ b/runtime/rust/prompty/src/model/events/hook_start_payload.rs @@ -0,0 +1,92 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use super::super::context::{LoadContext, SaveContext}; + +use super::redaction_metadata::RedactionMetadata; + +/// Payload for "hook_start" events — a host lifecycle hook is beginning. +#[derive(Debug, Clone, Default)] +pub struct HookStartPayload { + /// Stable hook invocation identifier + pub hook_invocation_id: String, + /// Host-defined hook type + pub hook_type: String, + /// Hook input after host-side sanitization + pub input: serde_json::Value, + /// Redaction state for sensitive hook input fields + pub redaction: Option, +} + +impl HookStartPayload { + /// Create a new HookStartPayload with default values. + pub fn new() -> Self { + Self::default() + } + + /// Load HookStartPayload from a JSON string. + pub fn from_json(json: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_json::from_str(json)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load HookStartPayload from a YAML string. + pub fn from_yaml(yaml: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_yaml::from_str(yaml)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load HookStartPayload from a `serde_json::Value`. + /// + /// Calls `ctx.process_input` before field extraction. + pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { + let value = ctx.process_input(value.clone()); + Self { + hook_invocation_id: value.get("hookInvocationId").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + hook_type: value.get("hookType").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + input: value.get("input").cloned().unwrap_or(serde_json::Value::Null), + redaction: value.get("redaction").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| RedactionMetadata::load_from_value(v, ctx)), + } + } + + /// Serialize HookStartPayload to a `serde_json::Value`. + /// + /// Calls `ctx.process_dict` after serialization. + pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { + let mut result = serde_json::Map::new(); + // Write base fields + if !self.hook_invocation_id.is_empty() { + result.insert("hookInvocationId".to_string(), serde_json::Value::String(self.hook_invocation_id.clone())); + } + if !self.hook_type.is_empty() { + result.insert("hookType".to_string(), serde_json::Value::String(self.hook_type.clone())); + } + if !self.input.is_null() { + result.insert("input".to_string(), self.input.clone()); + } + if let Some(ref val) = self.redaction { + let nested = val.to_value(ctx); + if !nested.is_null() { + result.insert("redaction".to_string(), nested); + } + } + ctx.process_dict(serde_json::Value::Object(result)) + } + + /// Serialize HookStartPayload to a JSON string. + pub fn to_json(&self, ctx: &SaveContext) -> Result { + serde_json::to_string_pretty(&self.to_value(ctx)) + } + + /// Serialize HookStartPayload to a YAML string. + pub fn to_yaml(&self, ctx: &SaveContext) -> Result { + serde_yaml::to_string(&self.to_value(ctx)) + } + /// Returns typed reference to the map if the field is an object. + /// Returns `None` if the field is null or not an object. + pub fn as_input_dict(&self) -> Option<&serde_json::Map> { + self.input.as_object() + } + +} diff --git a/runtime/rust/prompty/src/model/events/host_tool_request.rs b/runtime/rust/prompty/src/model/events/host_tool_request.rs new file mode 100644 index 00000000..851e1f13 --- /dev/null +++ b/runtime/rust/prompty/src/model/events/host_tool_request.rs @@ -0,0 +1,93 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use super::super::context::{LoadContext, SaveContext}; + +/// Request passed to a host tool executor after policy and permission checks. +#[derive(Debug, Clone, Default)] +pub struct HostToolRequest { + /// Stable host execution request identifier + pub request_id: Option, + /// Associated model tool call identifier, when available + pub tool_call_id: Option, + /// Name of the host tool being executed + pub tool_name: String, + /// Tool arguments after host-side sanitization + pub arguments: serde_json::Value, + /// Working directory or execution scope for the tool + pub working_directory: Option, +} + +impl HostToolRequest { + /// Create a new HostToolRequest with default values. + pub fn new() -> Self { + Self::default() + } + + /// Load HostToolRequest from a JSON string. + pub fn from_json(json: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_json::from_str(json)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load HostToolRequest from a YAML string. + pub fn from_yaml(yaml: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_yaml::from_str(yaml)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load HostToolRequest from a `serde_json::Value`. + /// + /// Calls `ctx.process_input` before field extraction. + pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { + let value = ctx.process_input(value.clone()); + Self { + request_id: value.get("requestId").and_then(|v| v.as_str()).map(|s| s.to_string()), + tool_call_id: value.get("toolCallId").and_then(|v| v.as_str()).map(|s| s.to_string()), + tool_name: value.get("toolName").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + arguments: value.get("arguments").cloned().unwrap_or(serde_json::Value::Null), + working_directory: value.get("workingDirectory").and_then(|v| v.as_str()).map(|s| s.to_string()), + } + } + + /// Serialize HostToolRequest to a `serde_json::Value`. + /// + /// Calls `ctx.process_dict` after serialization. + pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { + let mut result = serde_json::Map::new(); + // Write base fields + if let Some(ref val) = self.request_id { + result.insert("requestId".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(ref val) = self.tool_call_id { + result.insert("toolCallId".to_string(), serde_json::Value::String(val.clone())); + } + if !self.tool_name.is_empty() { + result.insert("toolName".to_string(), serde_json::Value::String(self.tool_name.clone())); + } + if !self.arguments.is_null() { + result.insert("arguments".to_string(), self.arguments.clone()); + } + if let Some(ref val) = self.working_directory { + result.insert("workingDirectory".to_string(), serde_json::Value::String(val.clone())); + } + ctx.process_dict(serde_json::Value::Object(result)) + } + + /// Serialize HostToolRequest to a JSON string. + pub fn to_json(&self, ctx: &SaveContext) -> Result { + serde_json::to_string_pretty(&self.to_value(ctx)) + } + + /// Serialize HostToolRequest to a YAML string. + pub fn to_yaml(&self, ctx: &SaveContext) -> Result { + serde_yaml::to_string(&self.to_value(ctx)) + } + /// Returns typed reference to the map if the field is an object. + /// Returns `None` if the field is null or not an object. + pub fn as_arguments_dict(&self) -> Option<&serde_json::Map> { + self.arguments.as_object() + } + +} diff --git a/runtime/rust/prompty/src/model/events/host_tool_result.rs b/runtime/rust/prompty/src/model/events/host_tool_result.rs new file mode 100644 index 00000000..3d7e7e1e --- /dev/null +++ b/runtime/rust/prompty/src/model/events/host_tool_result.rs @@ -0,0 +1,115 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use super::super::context::{LoadContext, SaveContext}; + +/// Result returned by a host tool executor. +#[derive(Debug, Clone, Default)] +pub struct HostToolResult { + /// Stable host execution request identifier + pub request_id: Option, + /// Associated model tool call identifier, when available + pub tool_call_id: Option, + /// Name of the host tool that executed + pub tool_name: String, + /// Whether the host execution completed successfully + pub success: bool, + /// Host-normalized execution result + pub result: Option, + /// Process or host exit code, when applicable + pub exit_code: Option, + /// Tool execution duration in milliseconds + pub duration_ms: Option, + /// Machine-readable error category when success is false + pub error_kind: Option, + /// Host-specific telemetry for the execution + pub telemetry: serde_json::Value, +} + +impl HostToolResult { + /// Create a new HostToolResult with default values. + pub fn new() -> Self { + Self::default() + } + + /// Load HostToolResult from a JSON string. + pub fn from_json(json: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_json::from_str(json)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load HostToolResult from a YAML string. + pub fn from_yaml(yaml: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_yaml::from_str(yaml)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load HostToolResult from a `serde_json::Value`. + /// + /// Calls `ctx.process_input` before field extraction. + pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { + let value = ctx.process_input(value.clone()); + Self { + request_id: value.get("requestId").and_then(|v| v.as_str()).map(|s| s.to_string()), + tool_call_id: value.get("toolCallId").and_then(|v| v.as_str()).map(|s| s.to_string()), + tool_name: value.get("toolName").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + success: value.get("success").and_then(|v| v.as_bool()).unwrap_or(false), + result: value.get("result").cloned(), + exit_code: value.get("exitCode").and_then(|v| v.as_i64()).map(|v| v as i32), + duration_ms: value.get("durationMs").and_then(|v| v.as_f64()), + error_kind: value.get("errorKind").and_then(|v| v.as_str()).map(|s| s.to_string()), + telemetry: value.get("telemetry").cloned().unwrap_or(serde_json::Value::Null), + } + } + + /// Serialize HostToolResult to a `serde_json::Value`. + /// + /// Calls `ctx.process_dict` after serialization. + pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { + let mut result = serde_json::Map::new(); + // Write base fields + if let Some(ref val) = self.request_id { + result.insert("requestId".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(ref val) = self.tool_call_id { + result.insert("toolCallId".to_string(), serde_json::Value::String(val.clone())); + } + if !self.tool_name.is_empty() { + result.insert("toolName".to_string(), serde_json::Value::String(self.tool_name.clone())); + } + result.insert("success".to_string(), serde_json::Value::Bool(self.success)); + if let Some(ref val) = self.result { + result.insert("result".to_string(), val.clone()); + } + if let Some(val) = self.exit_code { + result.insert("exitCode".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + } + if let Some(val) = self.duration_ms { + result.insert("durationMs".to_string(), serde_json::Number::from_f64(val as f64).map(serde_json::Value::Number).unwrap_or(serde_json::Value::Null)); + } + if let Some(ref val) = self.error_kind { + result.insert("errorKind".to_string(), serde_json::Value::String(val.clone())); + } + if !self.telemetry.is_null() { + result.insert("telemetry".to_string(), self.telemetry.clone()); + } + ctx.process_dict(serde_json::Value::Object(result)) + } + + /// Serialize HostToolResult to a JSON string. + pub fn to_json(&self, ctx: &SaveContext) -> Result { + serde_json::to_string_pretty(&self.to_value(ctx)) + } + + /// Serialize HostToolResult to a YAML string. + pub fn to_yaml(&self, ctx: &SaveContext) -> Result { + serde_yaml::to_string(&self.to_value(ctx)) + } + /// Returns typed reference to the map if the field is an object. + /// Returns `None` if the field is null or not an object. + pub fn as_telemetry_dict(&self) -> Option<&serde_json::Map> { + self.telemetry.as_object() + } + +} diff --git a/runtime/rust/prompty/src/model/events/mod.rs b/runtime/rust/prompty/src/model/events/mod.rs index 3c0cba60..c6bb2c10 100644 --- a/runtime/rust/prompty/src/model/events/mod.rs +++ b/runtime/rust/prompty/src/model/events/mod.rs @@ -20,12 +20,24 @@ pub use llm_complete_payload::*; pub mod retry_payload; pub use retry_payload::*; +pub mod redacted_field; +pub use redacted_field::*; + +pub mod redaction_metadata; +pub use redaction_metadata::*; + pub mod permission_requested_payload; pub use permission_requested_payload::*; pub mod permission_completed_payload; pub use permission_completed_payload::*; +pub mod permission_request; +pub use permission_request::*; + +pub mod permission_decision; +pub use permission_decision::*; + pub mod token_event_payload; pub use token_event_payload::*; @@ -38,6 +50,24 @@ pub use tool_call_start_payload::*; pub mod tool_call_complete_payload; pub use tool_call_complete_payload::*; +pub mod tool_execution_start_payload; +pub use tool_execution_start_payload::*; + +pub mod tool_execution_complete_payload; +pub use tool_execution_complete_payload::*; + +pub mod host_tool_request; +pub use host_tool_request::*; + +pub mod host_tool_result; +pub use host_tool_result::*; + +pub mod hook_start_payload; +pub use hook_start_payload::*; + +pub mod hook_end_payload; +pub use hook_end_payload::*; + pub mod tool_result_payload; pub use tool_result_payload::*; @@ -68,5 +98,38 @@ pub use turn_summary::*; pub mod turn_trace; pub use turn_trace::*; +pub mod harness_context; +pub use harness_context::*; + +pub mod session_start_payload; +pub use session_start_payload::*; + +pub mod session_end_payload; +pub use session_end_payload::*; + +pub mod session_warning_payload; +pub use session_warning_payload::*; + +pub mod session_event; +pub use session_event::*; + +pub mod checkpoint; +pub use checkpoint::*; + +pub mod trajectory_event; +pub use trajectory_event::*; + +pub mod session_file_ref; +pub use session_file_ref::*; + +pub mod session_ref; +pub use session_ref::*; + +pub mod session_summary; +pub use session_summary::*; + +pub mod session_trace; +pub use session_trace::*; + pub mod stream_chunk; pub use stream_chunk::*; diff --git a/runtime/rust/prompty/src/model/events/permission_completed_payload.rs b/runtime/rust/prompty/src/model/events/permission_completed_payload.rs index f704814e..daffe201 100644 --- a/runtime/rust/prompty/src/model/events/permission_completed_payload.rs +++ b/runtime/rust/prompty/src/model/events/permission_completed_payload.rs @@ -7,12 +7,18 @@ use super::super::context::{LoadContext, SaveContext}; /// Payload for permission completion events — an approval decision was made. #[derive(Debug, Clone, Default)] pub struct PermissionCompletedPayload { + /// Stable permission request identifier + pub request_id: Option, + /// Associated tool call identifier, when the permission gated a tool call + pub tool_call_id: Option, /// Permission/action name that was decided pub permission: String, /// Whether the requested permission was approved pub approved: bool, /// Decision reason, if available pub reason: Option, + /// Host-specific decision result, such as a durable approval token or denial details + pub result: serde_json::Value, } impl PermissionCompletedPayload { @@ -39,9 +45,12 @@ impl PermissionCompletedPayload { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { + request_id: value.get("requestId").and_then(|v| v.as_str()).map(|s| s.to_string()), + tool_call_id: value.get("toolCallId").and_then(|v| v.as_str()).map(|s| s.to_string()), permission: value.get("permission").and_then(|v| v.as_str()).unwrap_or_default().to_string(), approved: value.get("approved").and_then(|v| v.as_bool()).unwrap_or(false), reason: value.get("reason").and_then(|v| v.as_str()).map(|s| s.to_string()), + result: value.get("result").cloned().unwrap_or(serde_json::Value::Null), } } @@ -51,6 +60,12 @@ impl PermissionCompletedPayload { pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { let mut result = serde_json::Map::new(); // Write base fields + if let Some(ref val) = self.request_id { + result.insert("requestId".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(ref val) = self.tool_call_id { + result.insert("toolCallId".to_string(), serde_json::Value::String(val.clone())); + } if !self.permission.is_empty() { result.insert("permission".to_string(), serde_json::Value::String(self.permission.clone())); } @@ -58,6 +73,9 @@ impl PermissionCompletedPayload { if let Some(ref val) = self.reason { result.insert("reason".to_string(), serde_json::Value::String(val.clone())); } + if !self.result.is_null() { + result.insert("result".to_string(), self.result.clone()); + } ctx.process_dict(serde_json::Value::Object(result)) } @@ -70,4 +88,10 @@ impl PermissionCompletedPayload { pub fn to_yaml(&self, ctx: &SaveContext) -> Result { serde_yaml::to_string(&self.to_value(ctx)) } + /// Returns typed reference to the map if the field is an object. + /// Returns `None` if the field is null or not an object. + pub fn as_result_dict(&self) -> Option<&serde_json::Map> { + self.result.as_object() + } + } diff --git a/runtime/rust/prompty/src/model/events/permission_decision.rs b/runtime/rust/prompty/src/model/events/permission_decision.rs new file mode 100644 index 00000000..a9adfb52 --- /dev/null +++ b/runtime/rust/prompty/src/model/events/permission_decision.rs @@ -0,0 +1,97 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use super::super::context::{LoadContext, SaveContext}; + +/// Decision returned by a permission resolver. +#[derive(Debug, Clone, Default)] +pub struct PermissionDecision { + /// Stable permission request identifier + pub request_id: Option, + /// Associated tool call identifier, when the permission gated a tool call + pub tool_call_id: Option, + /// Permission/action name that was decided + pub permission: String, + /// Whether the requested permission was approved + pub approved: bool, + /// Decision reason, if available + pub reason: Option, + /// Host-specific decision result, such as a durable approval token or denial details + pub result: serde_json::Value, +} + +impl PermissionDecision { + /// Create a new PermissionDecision with default values. + pub fn new() -> Self { + Self::default() + } + + /// Load PermissionDecision from a JSON string. + pub fn from_json(json: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_json::from_str(json)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load PermissionDecision from a YAML string. + pub fn from_yaml(yaml: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_yaml::from_str(yaml)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load PermissionDecision from a `serde_json::Value`. + /// + /// Calls `ctx.process_input` before field extraction. + pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { + let value = ctx.process_input(value.clone()); + Self { + request_id: value.get("requestId").and_then(|v| v.as_str()).map(|s| s.to_string()), + tool_call_id: value.get("toolCallId").and_then(|v| v.as_str()).map(|s| s.to_string()), + permission: value.get("permission").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + approved: value.get("approved").and_then(|v| v.as_bool()).unwrap_or(false), + reason: value.get("reason").and_then(|v| v.as_str()).map(|s| s.to_string()), + result: value.get("result").cloned().unwrap_or(serde_json::Value::Null), + } + } + + /// Serialize PermissionDecision to a `serde_json::Value`. + /// + /// Calls `ctx.process_dict` after serialization. + pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { + let mut result = serde_json::Map::new(); + // Write base fields + if let Some(ref val) = self.request_id { + result.insert("requestId".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(ref val) = self.tool_call_id { + result.insert("toolCallId".to_string(), serde_json::Value::String(val.clone())); + } + if !self.permission.is_empty() { + result.insert("permission".to_string(), serde_json::Value::String(self.permission.clone())); + } + result.insert("approved".to_string(), serde_json::Value::Bool(self.approved)); + if let Some(ref val) = self.reason { + result.insert("reason".to_string(), serde_json::Value::String(val.clone())); + } + if !self.result.is_null() { + result.insert("result".to_string(), self.result.clone()); + } + ctx.process_dict(serde_json::Value::Object(result)) + } + + /// Serialize PermissionDecision to a JSON string. + pub fn to_json(&self, ctx: &SaveContext) -> Result { + serde_json::to_string_pretty(&self.to_value(ctx)) + } + + /// Serialize PermissionDecision to a YAML string. + pub fn to_yaml(&self, ctx: &SaveContext) -> Result { + serde_yaml::to_string(&self.to_value(ctx)) + } + /// Returns typed reference to the map if the field is an object. + /// Returns `None` if the field is null or not an object. + pub fn as_result_dict(&self) -> Option<&serde_json::Map> { + self.result.as_object() + } + +} diff --git a/runtime/rust/prompty/src/model/events/permission_request.rs b/runtime/rust/prompty/src/model/events/permission_request.rs new file mode 100644 index 00000000..7ea8788b --- /dev/null +++ b/runtime/rust/prompty/src/model/events/permission_request.rs @@ -0,0 +1,111 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use super::super::context::{LoadContext, SaveContext}; + +/// Request passed to a permission resolver. This is the live protocol shape; the event payloads above can include trace-only metadata such as redaction state. +#[derive(Debug, Clone, Default)] +pub struct PermissionRequest { + /// Stable permission request identifier + pub request_id: Option, + /// Associated tool call identifier, when the permission gates a tool call + pub tool_call_id: Option, + /// Permission/action name being requested + pub permission: String, + /// Resource or tool the permission applies to + pub target: Option, + /// Additional host-specific permission details + pub details: serde_json::Value, + /// Human-readable prompt or rationale that can be shown to an approval UI + pub prompt_request: Option, + /// Policy metadata used to evaluate or explain the permission request + pub policy: serde_json::Value, +} + +impl PermissionRequest { + /// Create a new PermissionRequest with default values. + pub fn new() -> Self { + Self::default() + } + + /// Load PermissionRequest from a JSON string. + pub fn from_json(json: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_json::from_str(json)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load PermissionRequest from a YAML string. + pub fn from_yaml(yaml: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_yaml::from_str(yaml)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load PermissionRequest from a `serde_json::Value`. + /// + /// Calls `ctx.process_input` before field extraction. + pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { + let value = ctx.process_input(value.clone()); + Self { + request_id: value.get("requestId").and_then(|v| v.as_str()).map(|s| s.to_string()), + tool_call_id: value.get("toolCallId").and_then(|v| v.as_str()).map(|s| s.to_string()), + permission: value.get("permission").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + target: value.get("target").and_then(|v| v.as_str()).map(|s| s.to_string()), + details: value.get("details").cloned().unwrap_or(serde_json::Value::Null), + prompt_request: value.get("promptRequest").and_then(|v| v.as_str()).map(|s| s.to_string()), + policy: value.get("policy").cloned().unwrap_or(serde_json::Value::Null), + } + } + + /// Serialize PermissionRequest to a `serde_json::Value`. + /// + /// Calls `ctx.process_dict` after serialization. + pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { + let mut result = serde_json::Map::new(); + // Write base fields + if let Some(ref val) = self.request_id { + result.insert("requestId".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(ref val) = self.tool_call_id { + result.insert("toolCallId".to_string(), serde_json::Value::String(val.clone())); + } + if !self.permission.is_empty() { + result.insert("permission".to_string(), serde_json::Value::String(self.permission.clone())); + } + if let Some(ref val) = self.target { + result.insert("target".to_string(), serde_json::Value::String(val.clone())); + } + if !self.details.is_null() { + result.insert("details".to_string(), self.details.clone()); + } + if let Some(ref val) = self.prompt_request { + result.insert("promptRequest".to_string(), serde_json::Value::String(val.clone())); + } + if !self.policy.is_null() { + result.insert("policy".to_string(), self.policy.clone()); + } + ctx.process_dict(serde_json::Value::Object(result)) + } + + /// Serialize PermissionRequest to a JSON string. + pub fn to_json(&self, ctx: &SaveContext) -> Result { + serde_json::to_string_pretty(&self.to_value(ctx)) + } + + /// Serialize PermissionRequest to a YAML string. + pub fn to_yaml(&self, ctx: &SaveContext) -> Result { + serde_yaml::to_string(&self.to_value(ctx)) + } + /// Returns typed reference to the map if the field is an object. + /// Returns `None` if the field is null or not an object. + pub fn as_details_dict(&self) -> Option<&serde_json::Map> { + self.details.as_object() + } + + /// Returns typed reference to the map if the field is an object. + /// Returns `None` if the field is null or not an object. + pub fn as_policy_dict(&self) -> Option<&serde_json::Map> { + self.policy.as_object() + } + +} diff --git a/runtime/rust/prompty/src/model/events/permission_requested_payload.rs b/runtime/rust/prompty/src/model/events/permission_requested_payload.rs index f370f2b3..43353537 100644 --- a/runtime/rust/prompty/src/model/events/permission_requested_payload.rs +++ b/runtime/rust/prompty/src/model/events/permission_requested_payload.rs @@ -4,15 +4,27 @@ use super::super::context::{LoadContext, SaveContext}; +use super::redaction_metadata::RedactionMetadata; + /// Payload for permission request events — a host is asked to approve an action. #[derive(Debug, Clone, Default)] pub struct PermissionRequestedPayload { + /// Stable permission request identifier + pub request_id: Option, + /// Associated tool call identifier, when the permission gates a tool call + pub tool_call_id: Option, /// Permission/action name being requested pub permission: String, /// Resource or tool the permission applies to pub target: Option, /// Additional host-specific permission details pub details: serde_json::Value, + /// Human-readable prompt or rationale that can be shown to an approval UI + pub prompt_request: Option, + /// Policy metadata used to evaluate or explain the permission request + pub policy: serde_json::Value, + /// Redaction state for sensitive request fields + pub redaction: Option, } impl PermissionRequestedPayload { @@ -39,9 +51,14 @@ impl PermissionRequestedPayload { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { + request_id: value.get("requestId").and_then(|v| v.as_str()).map(|s| s.to_string()), + tool_call_id: value.get("toolCallId").and_then(|v| v.as_str()).map(|s| s.to_string()), permission: value.get("permission").and_then(|v| v.as_str()).unwrap_or_default().to_string(), target: value.get("target").and_then(|v| v.as_str()).map(|s| s.to_string()), details: value.get("details").cloned().unwrap_or(serde_json::Value::Null), + prompt_request: value.get("promptRequest").and_then(|v| v.as_str()).map(|s| s.to_string()), + policy: value.get("policy").cloned().unwrap_or(serde_json::Value::Null), + redaction: value.get("redaction").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| RedactionMetadata::load_from_value(v, ctx)), } } @@ -51,6 +68,12 @@ impl PermissionRequestedPayload { pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { let mut result = serde_json::Map::new(); // Write base fields + if let Some(ref val) = self.request_id { + result.insert("requestId".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(ref val) = self.tool_call_id { + result.insert("toolCallId".to_string(), serde_json::Value::String(val.clone())); + } if !self.permission.is_empty() { result.insert("permission".to_string(), serde_json::Value::String(self.permission.clone())); } @@ -60,6 +83,18 @@ impl PermissionRequestedPayload { if !self.details.is_null() { result.insert("details".to_string(), self.details.clone()); } + if let Some(ref val) = self.prompt_request { + result.insert("promptRequest".to_string(), serde_json::Value::String(val.clone())); + } + if !self.policy.is_null() { + result.insert("policy".to_string(), self.policy.clone()); + } + if let Some(ref val) = self.redaction { + let nested = val.to_value(ctx); + if !nested.is_null() { + result.insert("redaction".to_string(), nested); + } + } ctx.process_dict(serde_json::Value::Object(result)) } @@ -78,4 +113,10 @@ impl PermissionRequestedPayload { self.details.as_object() } + /// Returns typed reference to the map if the field is an object. + /// Returns `None` if the field is null or not an object. + pub fn as_policy_dict(&self) -> Option<&serde_json::Map> { + self.policy.as_object() + } + } diff --git a/runtime/rust/prompty/src/model/events/redacted_field.rs b/runtime/rust/prompty/src/model/events/redacted_field.rs new file mode 100644 index 00000000..be21f755 --- /dev/null +++ b/runtime/rust/prompty/src/model/events/redacted_field.rs @@ -0,0 +1,123 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use super::super::context::{LoadContext, SaveContext}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum RedactionMode { + None, + Redacted, + Hashed, + Summary, + Reference, +} + +impl Default for RedactionMode { + fn default() -> Self { + Self::None + } +} + +impl std::fmt::Display for RedactionMode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::None => write!(f, "none"), + Self::Redacted => write!(f, "redacted"), + Self::Hashed => write!(f, "hashed"), + Self::Summary => write!(f, "summary"), + Self::Reference => write!(f, "reference"), + } + } +} + +impl RedactionMode { + pub fn from_str_opt(s: &str) -> Option { + match s { + "none" => Some(Self::None), + "redacted" => Some(Self::Redacted), + "hashed" => Some(Self::Hashed), + "summary" => Some(Self::Summary), + "reference" => Some(Self::Reference), + _ => None, + } + } + + pub fn as_str(&self) -> &str { + match self { + Self::None => "none", + Self::Redacted => "redacted", + Self::Hashed => "hashed", + Self::Summary => "summary", + Self::Reference => "reference", + } + } +} + +/// Redaction handling for one JSON-shaped field path. +#[derive(Debug, Clone, Default)] +pub struct RedactedField { + /// JSONPath-like field path, relative to the containing payload + pub path: String, + /// How the field was represented + pub mode: RedactionMode, + /// Human-readable reason or policy that caused this handling + pub reason: Option, +} + +impl RedactedField { + /// Create a new RedactedField with default values. + pub fn new() -> Self { + Self::default() + } + + /// Load RedactedField from a JSON string. + pub fn from_json(json: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_json::from_str(json)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load RedactedField from a YAML string. + pub fn from_yaml(yaml: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_yaml::from_str(yaml)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load RedactedField from a `serde_json::Value`. + /// + /// Calls `ctx.process_input` before field extraction. + pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { + let value = ctx.process_input(value.clone()); + Self { + path: value.get("path").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + mode: value.get("mode").and_then(|v| v.as_str()).and_then(|s| RedactionMode::from_str_opt(s)).unwrap_or(RedactionMode::None), + reason: value.get("reason").and_then(|v| v.as_str()).map(|s| s.to_string()), + } + } + + /// Serialize RedactedField to a `serde_json::Value`. + /// + /// Calls `ctx.process_dict` after serialization. + pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { + let mut result = serde_json::Map::new(); + // Write base fields + if !self.path.is_empty() { + result.insert("path".to_string(), serde_json::Value::String(self.path.clone())); + } + result.insert("mode".to_string(), serde_json::Value::String(self.mode.to_string())); + if let Some(ref val) = self.reason { + result.insert("reason".to_string(), serde_json::Value::String(val.clone())); + } + ctx.process_dict(serde_json::Value::Object(result)) + } + + /// Serialize RedactedField to a JSON string. + pub fn to_json(&self, ctx: &SaveContext) -> Result { + serde_json::to_string_pretty(&self.to_value(ctx)) + } + + /// Serialize RedactedField to a YAML string. + pub fn to_yaml(&self, ctx: &SaveContext) -> Result { + serde_yaml::to_string(&self.to_value(ctx)) + } +} diff --git a/runtime/rust/prompty/src/model/events/redaction_metadata.rs b/runtime/rust/prompty/src/model/events/redaction_metadata.rs new file mode 100644 index 00000000..2a5cd8eb --- /dev/null +++ b/runtime/rust/prompty/src/model/events/redaction_metadata.rs @@ -0,0 +1,97 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use super::super::context::{LoadContext, SaveContext}; + +use super::redacted_field::RedactedField; + +/// Metadata describing whether and how a payload was sanitized. +#[derive(Debug, Clone, Default)] +pub struct RedactionMetadata { + /// Whether the payload has been sanitized for persistence or external display + pub sanitized: Option, + /// Field-level redaction details + pub fields: Vec, + /// Host policy or sanitizer version that produced this metadata + pub policy: Option, +} + +impl RedactionMetadata { + /// Create a new RedactionMetadata with default values. + pub fn new() -> Self { + Self::default() + } + + /// Load RedactionMetadata from a JSON string. + pub fn from_json(json: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_json::from_str(json)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load RedactionMetadata from a YAML string. + pub fn from_yaml(yaml: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_yaml::from_str(yaml)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load RedactionMetadata from a `serde_json::Value`. + /// + /// Calls `ctx.process_input` before field extraction. + pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { + let value = ctx.process_input(value.clone()); + Self { + sanitized: value.get("sanitized").and_then(|v| v.as_bool()), + fields: value.get("fields").map(|v| Self::load_fields(v, ctx)).unwrap_or_default(), + policy: value.get("policy").and_then(|v| v.as_str()).map(|s| s.to_string()), + } + } + + /// Serialize RedactionMetadata to a `serde_json::Value`. + /// + /// Calls `ctx.process_dict` after serialization. + pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { + let mut result = serde_json::Map::new(); + // Write base fields + if let Some(val) = self.sanitized { + result.insert("sanitized".to_string(), serde_json::Value::Bool(val)); + } + if !self.fields.is_empty() { + result.insert("fields".to_string(), Self::save_fields(&self.fields, ctx)); + } + if let Some(ref val) = self.policy { + result.insert("policy".to_string(), serde_json::Value::String(val.clone())); + } + ctx.process_dict(serde_json::Value::Object(result)) + } + + /// Serialize RedactionMetadata to a JSON string. + pub fn to_json(&self, ctx: &SaveContext) -> Result { + serde_json::to_string_pretty(&self.to_value(ctx)) + } + + /// Serialize RedactionMetadata to a YAML string. + pub fn to_yaml(&self, ctx: &SaveContext) -> Result { + serde_yaml::to_string(&self.to_value(ctx)) + } + + /// Load a collection of RedactedField from a JSON value. + /// Handles both array format `[{...}]`. + fn load_fields(data: &serde_json::Value, ctx: &LoadContext) -> Vec { + match data { + serde_json::Value::Array(arr) => { + arr.iter().map(|v| RedactedField::load_from_value(v, ctx)).collect() + } + + _ => Vec::new(), + + } + } + + /// Save a collection of RedactedField to a JSON value. + fn save_fields(items: &[RedactedField], ctx: &SaveContext) -> serde_json::Value { + + serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()) + + } +} diff --git a/runtime/rust/prompty/src/model/events/session_end_payload.rs b/runtime/rust/prompty/src/model/events/session_end_payload.rs new file mode 100644 index 00000000..86e13a4c --- /dev/null +++ b/runtime/rust/prompty/src/model/events/session_end_payload.rs @@ -0,0 +1,127 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use super::super::context::{LoadContext, SaveContext}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum SessionEndStatus { + Success, + Error, + Cancelled, + Interrupted, +} + +impl Default for SessionEndStatus { + fn default() -> Self { + Self::Success + } +} + +impl std::fmt::Display for SessionEndStatus { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Success => write!(f, "success"), + Self::Error => write!(f, "error"), + Self::Cancelled => write!(f, "cancelled"), + Self::Interrupted => write!(f, "interrupted"), + } + } +} + +impl SessionEndStatus { + pub fn from_str_opt(s: &str) -> Option { + match s { + "success" => Some(Self::Success), + "error" => Some(Self::Error), + "cancelled" => Some(Self::Cancelled), + "interrupted" => Some(Self::Interrupted), + _ => None, + } + } + + pub fn as_str(&self) -> &str { + match self { + Self::Success => "success", + Self::Error => "error", + Self::Cancelled => "cancelled", + Self::Interrupted => "interrupted", + } + } +} + +/// Payload for "session_end" events. +#[derive(Debug, Clone, Default)] +pub struct SessionEndPayload { + /// Stable session identifier + pub session_id: Option, + /// Final session status + pub status: Option, + /// Host-specific reason the session ended + pub reason: Option, + /// Total elapsed session duration in milliseconds + pub duration_ms: Option, +} + +impl SessionEndPayload { + /// Create a new SessionEndPayload with default values. + pub fn new() -> Self { + Self::default() + } + + /// Load SessionEndPayload from a JSON string. + pub fn from_json(json: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_json::from_str(json)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load SessionEndPayload from a YAML string. + pub fn from_yaml(yaml: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_yaml::from_str(yaml)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load SessionEndPayload from a `serde_json::Value`. + /// + /// Calls `ctx.process_input` before field extraction. + pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { + let value = ctx.process_input(value.clone()); + Self { + session_id: value.get("sessionId").and_then(|v| v.as_str()).map(|s| s.to_string()), + status: value.get("status").and_then(|v| v.as_str()).and_then(|s| SessionEndStatus::from_str_opt(s)), + reason: value.get("reason").and_then(|v| v.as_str()).map(|s| s.to_string()), + duration_ms: value.get("durationMs").and_then(|v| v.as_f64()), + } + } + + /// Serialize SessionEndPayload to a `serde_json::Value`. + /// + /// Calls `ctx.process_dict` after serialization. + pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { + let mut result = serde_json::Map::new(); + // Write base fields + if let Some(ref val) = self.session_id { + result.insert("sessionId".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(ref val) = self.status { + result.insert("status".to_string(), serde_json::Value::String(val.to_string())); + } + if let Some(ref val) = self.reason { + result.insert("reason".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(val) = self.duration_ms { + result.insert("durationMs".to_string(), serde_json::Number::from_f64(val as f64).map(serde_json::Value::Number).unwrap_or(serde_json::Value::Null)); + } + ctx.process_dict(serde_json::Value::Object(result)) + } + + /// Serialize SessionEndPayload to a JSON string. + pub fn to_json(&self, ctx: &SaveContext) -> Result { + serde_json::to_string_pretty(&self.to_value(ctx)) + } + + /// Serialize SessionEndPayload to a YAML string. + pub fn to_yaml(&self, ctx: &SaveContext) -> Result { + serde_yaml::to_string(&self.to_value(ctx)) + } +} diff --git a/runtime/rust/prompty/src/model/events/session_event.rs b/runtime/rust/prompty/src/model/events/session_event.rs new file mode 100644 index 00000000..8ea3a7c7 --- /dev/null +++ b/runtime/rust/prompty/src/model/events/session_event.rs @@ -0,0 +1,178 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use super::super::context::{LoadContext, SaveContext}; + +use super::redaction_metadata::RedactionMetadata; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum SessionEventType { + Session_start, + Session_end, + Session_warning, + Session_hook_start, + Session_hook_end, + Checkpoint_created, + Trajectory_event, +} + +impl Default for SessionEventType { + fn default() -> Self { + Self::Session_start + } +} + +impl std::fmt::Display for SessionEventType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Session_start => write!(f, "session_start"), + Self::Session_end => write!(f, "session_end"), + Self::Session_warning => write!(f, "session_warning"), + Self::Session_hook_start => write!(f, "session_hook_start"), + Self::Session_hook_end => write!(f, "session_hook_end"), + Self::Checkpoint_created => write!(f, "checkpoint_created"), + Self::Trajectory_event => write!(f, "trajectory_event"), + } + } +} + +impl SessionEventType { + pub fn from_str_opt(s: &str) -> Option { + match s { + "session_start" => Some(Self::Session_start), + "session_end" => Some(Self::Session_end), + "session_warning" => Some(Self::Session_warning), + "session_hook_start" => Some(Self::Session_hook_start), + "session_hook_end" => Some(Self::Session_hook_end), + "checkpoint_created" => Some(Self::Checkpoint_created), + "trajectory_event" => Some(Self::Trajectory_event), + _ => None, + } + } + + pub fn as_str(&self) -> &str { + match self { + Self::Session_start => "session_start", + Self::Session_end => "session_end", + Self::Session_warning => "session_warning", + Self::Session_hook_start => "session_hook_start", + Self::Session_hook_end => "session_hook_end", + Self::Checkpoint_created => "checkpoint_created", + Self::Trajectory_event => "trajectory_event", + } + } +} + +/// A canonical event envelope emitted by an outer harness session. +#[derive(Debug, Clone, Default)] +pub struct SessionEvent { + /// Unique identifier for this event + pub id: String, + /// Event type discriminator + pub r#type: SessionEventType, + /// ISO 8601 UTC timestamp when the event was emitted + pub timestamp: String, + /// Stable identifier for the outer session + pub session_id: Option, + /// Associated turn identifier, when this session event is linked to a turn + pub turn_id: Option, + /// Parent event or span identifier for reconstructing event hierarchy + pub parent_id: Option, + /// Trace span identifier associated with this event + pub span_id: Option, + /// Event-specific payload. Use the typed payload model matching 'type'. + pub payload: serde_json::Value, + /// Redaction state for sensitive payload fields + pub redaction: Option, +} + +impl SessionEvent { + /// Create a new SessionEvent with default values. + pub fn new() -> Self { + Self::default() + } + + /// Load SessionEvent from a JSON string. + pub fn from_json(json: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_json::from_str(json)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load SessionEvent from a YAML string. + pub fn from_yaml(yaml: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_yaml::from_str(yaml)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load SessionEvent from a `serde_json::Value`. + /// + /// Calls `ctx.process_input` before field extraction. + pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { + let value = ctx.process_input(value.clone()); + Self { + id: value.get("id").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + r#type: value.get("type").and_then(|v| v.as_str()).and_then(|s| SessionEventType::from_str_opt(s)).unwrap_or(SessionEventType::Session_start), + timestamp: value.get("timestamp").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + session_id: value.get("sessionId").and_then(|v| v.as_str()).map(|s| s.to_string()), + turn_id: value.get("turnId").and_then(|v| v.as_str()).map(|s| s.to_string()), + parent_id: value.get("parentId").and_then(|v| v.as_str()).map(|s| s.to_string()), + span_id: value.get("spanId").and_then(|v| v.as_str()).map(|s| s.to_string()), + payload: value.get("payload").cloned().unwrap_or(serde_json::Value::Null), + redaction: value.get("redaction").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| RedactionMetadata::load_from_value(v, ctx)), + } + } + + /// Serialize SessionEvent to a `serde_json::Value`. + /// + /// Calls `ctx.process_dict` after serialization. + pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { + let mut result = serde_json::Map::new(); + // Write base fields + if !self.id.is_empty() { + result.insert("id".to_string(), serde_json::Value::String(self.id.clone())); + } + result.insert("type".to_string(), serde_json::Value::String(self.r#type.to_string())); + if !self.timestamp.is_empty() { + result.insert("timestamp".to_string(), serde_json::Value::String(self.timestamp.clone())); + } + if let Some(ref val) = self.session_id { + result.insert("sessionId".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(ref val) = self.turn_id { + result.insert("turnId".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(ref val) = self.parent_id { + result.insert("parentId".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(ref val) = self.span_id { + result.insert("spanId".to_string(), serde_json::Value::String(val.clone())); + } + if !self.payload.is_null() { + result.insert("payload".to_string(), self.payload.clone()); + } + if let Some(ref val) = self.redaction { + let nested = val.to_value(ctx); + if !nested.is_null() { + result.insert("redaction".to_string(), nested); + } + } + ctx.process_dict(serde_json::Value::Object(result)) + } + + /// Serialize SessionEvent to a JSON string. + pub fn to_json(&self, ctx: &SaveContext) -> Result { + serde_json::to_string_pretty(&self.to_value(ctx)) + } + + /// Serialize SessionEvent to a YAML string. + pub fn to_yaml(&self, ctx: &SaveContext) -> Result { + serde_yaml::to_string(&self.to_value(ctx)) + } + /// Returns typed reference to the map if the field is an object. + /// Returns `None` if the field is null or not an object. + pub fn as_payload_dict(&self) -> Option<&serde_json::Map> { + self.payload.as_object() + } + +} diff --git a/runtime/rust/prompty/src/model/events/session_file_ref.rs b/runtime/rust/prompty/src/model/events/session_file_ref.rs new file mode 100644 index 00000000..981b0496 --- /dev/null +++ b/runtime/rust/prompty/src/model/events/session_file_ref.rs @@ -0,0 +1,87 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use super::super::context::{LoadContext, SaveContext}; + +/// A file observed or touched by a harness session. +#[derive(Debug, Clone, Default)] +pub struct SessionFileRef { + /// Stable session identifier + pub session_id: Option, + /// File path, relative to the harness workspace when possible + pub path: String, + /// Tool that first observed the file, when known + pub tool_name: Option, + /// Zero-based turn index where the file was first observed + pub turn_index: Option, + /// ISO 8601 UTC timestamp when the file was first observed + pub first_seen_at: Option, +} + +impl SessionFileRef { + /// Create a new SessionFileRef with default values. + pub fn new() -> Self { + Self::default() + } + + /// Load SessionFileRef from a JSON string. + pub fn from_json(json: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_json::from_str(json)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load SessionFileRef from a YAML string. + pub fn from_yaml(yaml: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_yaml::from_str(yaml)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load SessionFileRef from a `serde_json::Value`. + /// + /// Calls `ctx.process_input` before field extraction. + pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { + let value = ctx.process_input(value.clone()); + Self { + session_id: value.get("sessionId").and_then(|v| v.as_str()).map(|s| s.to_string()), + path: value.get("path").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + tool_name: value.get("toolName").and_then(|v| v.as_str()).map(|s| s.to_string()), + turn_index: value.get("turnIndex").and_then(|v| v.as_i64()).map(|v| v as i32), + first_seen_at: value.get("firstSeenAt").and_then(|v| v.as_str()).map(|s| s.to_string()), + } + } + + /// Serialize SessionFileRef to a `serde_json::Value`. + /// + /// Calls `ctx.process_dict` after serialization. + pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { + let mut result = serde_json::Map::new(); + // Write base fields + if let Some(ref val) = self.session_id { + result.insert("sessionId".to_string(), serde_json::Value::String(val.clone())); + } + if !self.path.is_empty() { + result.insert("path".to_string(), serde_json::Value::String(self.path.clone())); + } + if let Some(ref val) = self.tool_name { + result.insert("toolName".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(val) = self.turn_index { + result.insert("turnIndex".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + } + if let Some(ref val) = self.first_seen_at { + result.insert("firstSeenAt".to_string(), serde_json::Value::String(val.clone())); + } + ctx.process_dict(serde_json::Value::Object(result)) + } + + /// Serialize SessionFileRef to a JSON string. + pub fn to_json(&self, ctx: &SaveContext) -> Result { + serde_json::to_string_pretty(&self.to_value(ctx)) + } + + /// Serialize SessionFileRef to a YAML string. + pub fn to_yaml(&self, ctx: &SaveContext) -> Result { + serde_yaml::to_string(&self.to_value(ctx)) + } +} diff --git a/runtime/rust/prompty/src/model/events/session_ref.rs b/runtime/rust/prompty/src/model/events/session_ref.rs new file mode 100644 index 00000000..a0018b19 --- /dev/null +++ b/runtime/rust/prompty/src/model/events/session_ref.rs @@ -0,0 +1,87 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use super::super::context::{LoadContext, SaveContext}; + +/// A non-file reference observed by a harness session. +#[derive(Debug, Clone, Default)] +pub struct SessionRef { + /// Stable session identifier + pub session_id: Option, + /// Reference category + pub ref_type: String, + /// Reference value + pub ref_value: String, + /// Zero-based turn index where the reference was first observed + pub turn_index: Option, + /// ISO 8601 UTC timestamp when the reference was recorded + pub created_at: Option, +} + +impl SessionRef { + /// Create a new SessionRef with default values. + pub fn new() -> Self { + Self::default() + } + + /// Load SessionRef from a JSON string. + pub fn from_json(json: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_json::from_str(json)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load SessionRef from a YAML string. + pub fn from_yaml(yaml: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_yaml::from_str(yaml)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load SessionRef from a `serde_json::Value`. + /// + /// Calls `ctx.process_input` before field extraction. + pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { + let value = ctx.process_input(value.clone()); + Self { + session_id: value.get("sessionId").and_then(|v| v.as_str()).map(|s| s.to_string()), + ref_type: value.get("refType").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + ref_value: value.get("refValue").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + turn_index: value.get("turnIndex").and_then(|v| v.as_i64()).map(|v| v as i32), + created_at: value.get("createdAt").and_then(|v| v.as_str()).map(|s| s.to_string()), + } + } + + /// Serialize SessionRef to a `serde_json::Value`. + /// + /// Calls `ctx.process_dict` after serialization. + pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { + let mut result = serde_json::Map::new(); + // Write base fields + if let Some(ref val) = self.session_id { + result.insert("sessionId".to_string(), serde_json::Value::String(val.clone())); + } + if !self.ref_type.is_empty() { + result.insert("refType".to_string(), serde_json::Value::String(self.ref_type.clone())); + } + if !self.ref_value.is_empty() { + result.insert("refValue".to_string(), serde_json::Value::String(self.ref_value.clone())); + } + if let Some(val) = self.turn_index { + result.insert("turnIndex".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + } + if let Some(ref val) = self.created_at { + result.insert("createdAt".to_string(), serde_json::Value::String(val.clone())); + } + ctx.process_dict(serde_json::Value::Object(result)) + } + + /// Serialize SessionRef to a JSON string. + pub fn to_json(&self, ctx: &SaveContext) -> Result { + serde_json::to_string_pretty(&self.to_value(ctx)) + } + + /// Serialize SessionRef to a YAML string. + pub fn to_yaml(&self, ctx: &SaveContext) -> Result { + serde_yaml::to_string(&self.to_value(ctx)) + } +} diff --git a/runtime/rust/prompty/src/model/events/session_start_payload.rs b/runtime/rust/prompty/src/model/events/session_start_payload.rs new file mode 100644 index 00000000..dddae728 --- /dev/null +++ b/runtime/rust/prompty/src/model/events/session_start_payload.rs @@ -0,0 +1,116 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use super::super::context::{LoadContext, SaveContext}; + +use super::harness_context::HarnessContext; + +/// Payload for "session_start" events. +#[derive(Debug, Clone, Default)] +pub struct SessionStartPayload { + /// Stable session identifier + pub session_id: String, + /// Session event schema version + pub version: Option, + /// Producer that started the session + pub producer: Option, + /// Runtime that produced the session + pub runtime: Option, + /// Prompty library version + pub prompty_version: Option, + /// ISO 8601 UTC timestamp when the session started + pub start_time: Option, + /// Selected model identifier, when known + pub selected_model: Option, + /// Selected reasoning effort or equivalent model setting, when known + pub reasoning_effort: Option, + /// Repository and execution context + pub context: Option, +} + +impl SessionStartPayload { + /// Create a new SessionStartPayload with default values. + pub fn new() -> Self { + Self::default() + } + + /// Load SessionStartPayload from a JSON string. + pub fn from_json(json: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_json::from_str(json)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load SessionStartPayload from a YAML string. + pub fn from_yaml(yaml: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_yaml::from_str(yaml)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load SessionStartPayload from a `serde_json::Value`. + /// + /// Calls `ctx.process_input` before field extraction. + pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { + let value = ctx.process_input(value.clone()); + Self { + session_id: value.get("sessionId").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + version: value.get("version").and_then(|v| v.as_i64()).map(|v| v as i32), + producer: value.get("producer").and_then(|v| v.as_str()).map(|s| s.to_string()), + runtime: value.get("runtime").and_then(|v| v.as_str()).map(|s| s.to_string()), + prompty_version: value.get("promptyVersion").and_then(|v| v.as_str()).map(|s| s.to_string()), + start_time: value.get("startTime").and_then(|v| v.as_str()).map(|s| s.to_string()), + selected_model: value.get("selectedModel").and_then(|v| v.as_str()).map(|s| s.to_string()), + reasoning_effort: value.get("reasoningEffort").and_then(|v| v.as_str()).map(|s| s.to_string()), + context: value.get("context").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| HarnessContext::load_from_value(v, ctx)), + } + } + + /// Serialize SessionStartPayload to a `serde_json::Value`. + /// + /// Calls `ctx.process_dict` after serialization. + pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { + let mut result = serde_json::Map::new(); + // Write base fields + if !self.session_id.is_empty() { + result.insert("sessionId".to_string(), serde_json::Value::String(self.session_id.clone())); + } + if let Some(val) = self.version { + result.insert("version".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + } + if let Some(ref val) = self.producer { + result.insert("producer".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(ref val) = self.runtime { + result.insert("runtime".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(ref val) = self.prompty_version { + result.insert("promptyVersion".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(ref val) = self.start_time { + result.insert("startTime".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(ref val) = self.selected_model { + result.insert("selectedModel".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(ref val) = self.reasoning_effort { + result.insert("reasoningEffort".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(ref val) = self.context { + let nested = val.to_value(ctx); + if !nested.is_null() { + result.insert("context".to_string(), nested); + } + } + ctx.process_dict(serde_json::Value::Object(result)) + } + + /// Serialize SessionStartPayload to a JSON string. + pub fn to_json(&self, ctx: &SaveContext) -> Result { + serde_json::to_string_pretty(&self.to_value(ctx)) + } + + /// Serialize SessionStartPayload to a YAML string. + pub fn to_yaml(&self, ctx: &SaveContext) -> Result { + serde_yaml::to_string(&self.to_value(ctx)) + } +} diff --git a/runtime/rust/prompty/src/model/events/session_summary.rs b/runtime/rust/prompty/src/model/events/session_summary.rs new file mode 100644 index 00000000..2aafb579 --- /dev/null +++ b/runtime/rust/prompty/src/model/events/session_summary.rs @@ -0,0 +1,144 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use super::super::context::{LoadContext, SaveContext}; + +use super::super::model::token_usage::TokenUsage; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum SessionSummaryStatus { + Success, + Error, + Cancelled, + Interrupted, +} + +impl Default for SessionSummaryStatus { + fn default() -> Self { + Self::Success + } +} + +impl std::fmt::Display for SessionSummaryStatus { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Success => write!(f, "success"), + Self::Error => write!(f, "error"), + Self::Cancelled => write!(f, "cancelled"), + Self::Interrupted => write!(f, "interrupted"), + } + } +} + +impl SessionSummaryStatus { + pub fn from_str_opt(s: &str) -> Option { + match s { + "success" => Some(Self::Success), + "error" => Some(Self::Error), + "cancelled" => Some(Self::Cancelled), + "interrupted" => Some(Self::Interrupted), + _ => None, + } + } + + pub fn as_str(&self) -> &str { + match self { + Self::Success => "success", + Self::Error => "error", + Self::Cancelled => "cancelled", + Self::Interrupted => "interrupted", + } + } +} + +/// Summary statistics for a completed session trace. +#[derive(Debug, Clone, Default)] +pub struct SessionSummary { + /// Stable session identifier + pub session_id: String, + /// Final session status + pub status: Option, + /// Number of user/assistant turns in the session + pub turns: Option, + /// Number of checkpoints created + pub checkpoints: Option, + /// Aggregated token usage for the session + pub usage: Option, + /// Total elapsed session duration in milliseconds + pub duration_ms: Option, +} + +impl SessionSummary { + /// Create a new SessionSummary with default values. + pub fn new() -> Self { + Self::default() + } + + /// Load SessionSummary from a JSON string. + pub fn from_json(json: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_json::from_str(json)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load SessionSummary from a YAML string. + pub fn from_yaml(yaml: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_yaml::from_str(yaml)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load SessionSummary from a `serde_json::Value`. + /// + /// Calls `ctx.process_input` before field extraction. + pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { + let value = ctx.process_input(value.clone()); + Self { + session_id: value.get("sessionId").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + status: value.get("status").and_then(|v| v.as_str()).and_then(|s| SessionSummaryStatus::from_str_opt(s)), + turns: value.get("turns").and_then(|v| v.as_i64()).map(|v| v as i32), + checkpoints: value.get("checkpoints").and_then(|v| v.as_i64()).map(|v| v as i32), + usage: value.get("usage").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| TokenUsage::load_from_value(v, ctx)), + duration_ms: value.get("durationMs").and_then(|v| v.as_f64()), + } + } + + /// Serialize SessionSummary to a `serde_json::Value`. + /// + /// Calls `ctx.process_dict` after serialization. + pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { + let mut result = serde_json::Map::new(); + // Write base fields + if !self.session_id.is_empty() { + result.insert("sessionId".to_string(), serde_json::Value::String(self.session_id.clone())); + } + if let Some(ref val) = self.status { + result.insert("status".to_string(), serde_json::Value::String(val.to_string())); + } + if let Some(val) = self.turns { + result.insert("turns".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + } + if let Some(val) = self.checkpoints { + result.insert("checkpoints".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + } + if let Some(ref val) = self.usage { + let nested = val.to_value(ctx); + if !nested.is_null() { + result.insert("usage".to_string(), nested); + } + } + if let Some(val) = self.duration_ms { + result.insert("durationMs".to_string(), serde_json::Number::from_f64(val as f64).map(serde_json::Value::Number).unwrap_or(serde_json::Value::Null)); + } + ctx.process_dict(serde_json::Value::Object(result)) + } + + /// Serialize SessionSummary to a JSON string. + pub fn to_json(&self, ctx: &SaveContext) -> Result { + serde_json::to_string_pretty(&self.to_value(ctx)) + } + + /// Serialize SessionSummary to a YAML string. + pub fn to_yaml(&self, ctx: &SaveContext) -> Result { + serde_yaml::to_string(&self.to_value(ctx)) + } +} diff --git a/runtime/rust/prompty/src/model/events/session_trace.rs b/runtime/rust/prompty/src/model/events/session_trace.rs new file mode 100644 index 00000000..5b9a1a8b --- /dev/null +++ b/runtime/rust/prompty/src/model/events/session_trace.rs @@ -0,0 +1,260 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use super::super::context::{LoadContext, SaveContext}; + +use super::checkpoint::Checkpoint; + +use super::session_event::SessionEvent; + +use super::session_file_ref::SessionFileRef; + +use super::session_ref::SessionRef; + +use super::session_summary::SessionSummary; + +use super::trajectory_event::TrajectoryEvent; + +use super::turn_trace::TurnTrace; + +/// Portable replay container for an outer harness session. +#[derive(Debug, Clone, Default)] +pub struct SessionTrace { + /// Trace schema version + pub version: String, + /// Runtime name that produced the trace + pub runtime: Option, + /// Prompty library version that produced the trace + pub prompty_version: Option, + /// Stable session identifier + pub session_id: Option, + /// Recorded session events in emission order + pub events: Vec, + /// Recorded turn traces associated with the session + pub turns: Vec, + /// Checkpoints created during the session + pub checkpoints: Vec, + /// Compact trajectory records associated with the session + pub trajectory: Vec, + /// Files observed or touched during the session + pub files: Vec, + /// Non-file references observed during the session + pub refs: Vec, + /// Optional summary computed from the event stream + pub summary: Option, +} + +impl SessionTrace { + /// Create a new SessionTrace with default values. + pub fn new() -> Self { + Self::default() + } + + /// Load SessionTrace from a JSON string. + pub fn from_json(json: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_json::from_str(json)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load SessionTrace from a YAML string. + pub fn from_yaml(yaml: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_yaml::from_str(yaml)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load SessionTrace from a `serde_json::Value`. + /// + /// Calls `ctx.process_input` before field extraction. + pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { + let value = ctx.process_input(value.clone()); + Self { + version: value.get("version").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + runtime: value.get("runtime").and_then(|v| v.as_str()).map(|s| s.to_string()), + prompty_version: value.get("promptyVersion").and_then(|v| v.as_str()).map(|s| s.to_string()), + session_id: value.get("sessionId").and_then(|v| v.as_str()).map(|s| s.to_string()), + events: value.get("events").map(|v| Self::load_events(v, ctx)).unwrap_or_default(), + turns: value.get("turns").map(|v| Self::load_turns(v, ctx)).unwrap_or_default(), + checkpoints: value.get("checkpoints").map(|v| Self::load_checkpoints(v, ctx)).unwrap_or_default(), + trajectory: value.get("trajectory").map(|v| Self::load_trajectory(v, ctx)).unwrap_or_default(), + files: value.get("files").map(|v| Self::load_files(v, ctx)).unwrap_or_default(), + refs: value.get("refs").map(|v| Self::load_refs(v, ctx)).unwrap_or_default(), + summary: value.get("summary").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| SessionSummary::load_from_value(v, ctx)), + } + } + + /// Serialize SessionTrace to a `serde_json::Value`. + /// + /// Calls `ctx.process_dict` after serialization. + pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { + let mut result = serde_json::Map::new(); + // Write base fields + if !self.version.is_empty() { + result.insert("version".to_string(), serde_json::Value::String(self.version.clone())); + } + if let Some(ref val) = self.runtime { + result.insert("runtime".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(ref val) = self.prompty_version { + result.insert("promptyVersion".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(ref val) = self.session_id { + result.insert("sessionId".to_string(), serde_json::Value::String(val.clone())); + } + if !self.events.is_empty() { + result.insert("events".to_string(), Self::save_events(&self.events, ctx)); + } + if !self.turns.is_empty() { + result.insert("turns".to_string(), Self::save_turns(&self.turns, ctx)); + } + if !self.checkpoints.is_empty() { + result.insert("checkpoints".to_string(), Self::save_checkpoints(&self.checkpoints, ctx)); + } + if !self.trajectory.is_empty() { + result.insert("trajectory".to_string(), Self::save_trajectory(&self.trajectory, ctx)); + } + if !self.files.is_empty() { + result.insert("files".to_string(), Self::save_files(&self.files, ctx)); + } + if !self.refs.is_empty() { + result.insert("refs".to_string(), Self::save_refs(&self.refs, ctx)); + } + if let Some(ref val) = self.summary { + let nested = val.to_value(ctx); + if !nested.is_null() { + result.insert("summary".to_string(), nested); + } + } + ctx.process_dict(serde_json::Value::Object(result)) + } + + /// Serialize SessionTrace to a JSON string. + pub fn to_json(&self, ctx: &SaveContext) -> Result { + serde_json::to_string_pretty(&self.to_value(ctx)) + } + + /// Serialize SessionTrace to a YAML string. + pub fn to_yaml(&self, ctx: &SaveContext) -> Result { + serde_yaml::to_string(&self.to_value(ctx)) + } + + /// Load a collection of SessionEvent from a JSON value. + /// Handles both array format `[{...}]`. + fn load_events(data: &serde_json::Value, ctx: &LoadContext) -> Vec { + match data { + serde_json::Value::Array(arr) => { + arr.iter().map(|v| SessionEvent::load_from_value(v, ctx)).collect() + } + + _ => Vec::new(), + + } + } + + /// Save a collection of SessionEvent to a JSON value. + fn save_events(items: &[SessionEvent], ctx: &SaveContext) -> serde_json::Value { + + serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()) + + } + + /// Load a collection of TurnTrace from a JSON value. + /// Handles both array format `[{...}]`. + fn load_turns(data: &serde_json::Value, ctx: &LoadContext) -> Vec { + match data { + serde_json::Value::Array(arr) => { + arr.iter().map(|v| TurnTrace::load_from_value(v, ctx)).collect() + } + + _ => Vec::new(), + + } + } + + /// Save a collection of TurnTrace to a JSON value. + fn save_turns(items: &[TurnTrace], ctx: &SaveContext) -> serde_json::Value { + + serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()) + + } + + /// Load a collection of Checkpoint from a JSON value. + /// Handles both array format `[{...}]`. + fn load_checkpoints(data: &serde_json::Value, ctx: &LoadContext) -> Vec { + match data { + serde_json::Value::Array(arr) => { + arr.iter().map(|v| Checkpoint::load_from_value(v, ctx)).collect() + } + + _ => Vec::new(), + + } + } + + /// Save a collection of Checkpoint to a JSON value. + fn save_checkpoints(items: &[Checkpoint], ctx: &SaveContext) -> serde_json::Value { + + serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()) + + } + + /// Load a collection of TrajectoryEvent from a JSON value. + /// Handles both array format `[{...}]`. + fn load_trajectory(data: &serde_json::Value, ctx: &LoadContext) -> Vec { + match data { + serde_json::Value::Array(arr) => { + arr.iter().map(|v| TrajectoryEvent::load_from_value(v, ctx)).collect() + } + + _ => Vec::new(), + + } + } + + /// Save a collection of TrajectoryEvent to a JSON value. + fn save_trajectory(items: &[TrajectoryEvent], ctx: &SaveContext) -> serde_json::Value { + + serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()) + + } + + /// Load a collection of SessionFileRef from a JSON value. + /// Handles both array format `[{...}]`. + fn load_files(data: &serde_json::Value, ctx: &LoadContext) -> Vec { + match data { + serde_json::Value::Array(arr) => { + arr.iter().map(|v| SessionFileRef::load_from_value(v, ctx)).collect() + } + + _ => Vec::new(), + + } + } + + /// Save a collection of SessionFileRef to a JSON value. + fn save_files(items: &[SessionFileRef], ctx: &SaveContext) -> serde_json::Value { + + serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()) + + } + + /// Load a collection of SessionRef from a JSON value. + /// Handles both array format `[{...}]`. + fn load_refs(data: &serde_json::Value, ctx: &LoadContext) -> Vec { + match data { + serde_json::Value::Array(arr) => { + arr.iter().map(|v| SessionRef::load_from_value(v, ctx)).collect() + } + + _ => Vec::new(), + + } + } + + /// Save a collection of SessionRef to a JSON value. + fn save_refs(items: &[SessionRef], ctx: &SaveContext) -> serde_json::Value { + + serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()) + + } +} diff --git a/runtime/rust/prompty/src/model/events/session_warning_payload.rs b/runtime/rust/prompty/src/model/events/session_warning_payload.rs new file mode 100644 index 00000000..27b8fd8d --- /dev/null +++ b/runtime/rust/prompty/src/model/events/session_warning_payload.rs @@ -0,0 +1,81 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use super::super::context::{LoadContext, SaveContext}; + +/// Payload for "session_warning" events. +#[derive(Debug, Clone, Default)] +pub struct SessionWarningPayload { + /// Stable machine-readable warning category + pub warning_type: String, + /// Human-readable warning message + pub message: String, + /// Additional host-specific warning details + pub details: serde_json::Value, +} + +impl SessionWarningPayload { + /// Create a new SessionWarningPayload with default values. + pub fn new() -> Self { + Self::default() + } + + /// Load SessionWarningPayload from a JSON string. + pub fn from_json(json: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_json::from_str(json)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load SessionWarningPayload from a YAML string. + pub fn from_yaml(yaml: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_yaml::from_str(yaml)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load SessionWarningPayload from a `serde_json::Value`. + /// + /// Calls `ctx.process_input` before field extraction. + pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { + let value = ctx.process_input(value.clone()); + Self { + warning_type: value.get("warningType").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + message: value.get("message").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + details: value.get("details").cloned().unwrap_or(serde_json::Value::Null), + } + } + + /// Serialize SessionWarningPayload to a `serde_json::Value`. + /// + /// Calls `ctx.process_dict` after serialization. + pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { + let mut result = serde_json::Map::new(); + // Write base fields + if !self.warning_type.is_empty() { + result.insert("warningType".to_string(), serde_json::Value::String(self.warning_type.clone())); + } + if !self.message.is_empty() { + result.insert("message".to_string(), serde_json::Value::String(self.message.clone())); + } + if !self.details.is_null() { + result.insert("details".to_string(), self.details.clone()); + } + ctx.process_dict(serde_json::Value::Object(result)) + } + + /// Serialize SessionWarningPayload to a JSON string. + pub fn to_json(&self, ctx: &SaveContext) -> Result { + serde_json::to_string_pretty(&self.to_value(ctx)) + } + + /// Serialize SessionWarningPayload to a YAML string. + pub fn to_yaml(&self, ctx: &SaveContext) -> Result { + serde_yaml::to_string(&self.to_value(ctx)) + } + /// Returns typed reference to the map if the field is an object. + /// Returns `None` if the field is null or not an object. + pub fn as_details_dict(&self) -> Option<&serde_json::Map> { + self.details.as_object() + } + +} diff --git a/runtime/rust/prompty/src/model/events/tool_execution_complete_payload.rs b/runtime/rust/prompty/src/model/events/tool_execution_complete_payload.rs new file mode 100644 index 00000000..7abb8ae8 --- /dev/null +++ b/runtime/rust/prompty/src/model/events/tool_execution_complete_payload.rs @@ -0,0 +1,126 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use super::super::context::{LoadContext, SaveContext}; + +use super::redaction_metadata::RedactionMetadata; + +/// Payload for "tool_execution_complete" events — a concrete host tool execution finished. +#[derive(Debug, Clone, Default)] +pub struct ToolExecutionCompletePayload { + /// Stable host execution request identifier + pub request_id: Option, + /// Associated model tool call identifier, when available + pub tool_call_id: Option, + /// Name of the host tool that executed + pub tool_name: String, + /// Whether the host execution completed successfully + pub success: bool, + /// Host-normalized execution result + pub result: Option, + /// Process or host exit code, when applicable + pub exit_code: Option, + /// Tool execution duration in milliseconds + pub duration_ms: Option, + /// Machine-readable error category when success is false + pub error_kind: Option, + /// Host-specific telemetry for the execution + pub telemetry: serde_json::Value, + /// Redaction state for sensitive result fields + pub redaction: Option, +} + +impl ToolExecutionCompletePayload { + /// Create a new ToolExecutionCompletePayload with default values. + pub fn new() -> Self { + Self::default() + } + + /// Load ToolExecutionCompletePayload from a JSON string. + pub fn from_json(json: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_json::from_str(json)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load ToolExecutionCompletePayload from a YAML string. + pub fn from_yaml(yaml: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_yaml::from_str(yaml)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load ToolExecutionCompletePayload from a `serde_json::Value`. + /// + /// Calls `ctx.process_input` before field extraction. + pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { + let value = ctx.process_input(value.clone()); + Self { + request_id: value.get("requestId").and_then(|v| v.as_str()).map(|s| s.to_string()), + tool_call_id: value.get("toolCallId").and_then(|v| v.as_str()).map(|s| s.to_string()), + tool_name: value.get("toolName").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + success: value.get("success").and_then(|v| v.as_bool()).unwrap_or(false), + result: value.get("result").cloned(), + exit_code: value.get("exitCode").and_then(|v| v.as_i64()).map(|v| v as i32), + duration_ms: value.get("durationMs").and_then(|v| v.as_f64()), + error_kind: value.get("errorKind").and_then(|v| v.as_str()).map(|s| s.to_string()), + telemetry: value.get("telemetry").cloned().unwrap_or(serde_json::Value::Null), + redaction: value.get("redaction").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| RedactionMetadata::load_from_value(v, ctx)), + } + } + + /// Serialize ToolExecutionCompletePayload to a `serde_json::Value`. + /// + /// Calls `ctx.process_dict` after serialization. + pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { + let mut result = serde_json::Map::new(); + // Write base fields + if let Some(ref val) = self.request_id { + result.insert("requestId".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(ref val) = self.tool_call_id { + result.insert("toolCallId".to_string(), serde_json::Value::String(val.clone())); + } + if !self.tool_name.is_empty() { + result.insert("toolName".to_string(), serde_json::Value::String(self.tool_name.clone())); + } + result.insert("success".to_string(), serde_json::Value::Bool(self.success)); + if let Some(ref val) = self.result { + result.insert("result".to_string(), val.clone()); + } + if let Some(val) = self.exit_code { + result.insert("exitCode".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + } + if let Some(val) = self.duration_ms { + result.insert("durationMs".to_string(), serde_json::Number::from_f64(val as f64).map(serde_json::Value::Number).unwrap_or(serde_json::Value::Null)); + } + if let Some(ref val) = self.error_kind { + result.insert("errorKind".to_string(), serde_json::Value::String(val.clone())); + } + if !self.telemetry.is_null() { + result.insert("telemetry".to_string(), self.telemetry.clone()); + } + if let Some(ref val) = self.redaction { + let nested = val.to_value(ctx); + if !nested.is_null() { + result.insert("redaction".to_string(), nested); + } + } + ctx.process_dict(serde_json::Value::Object(result)) + } + + /// Serialize ToolExecutionCompletePayload to a JSON string. + pub fn to_json(&self, ctx: &SaveContext) -> Result { + serde_json::to_string_pretty(&self.to_value(ctx)) + } + + /// Serialize ToolExecutionCompletePayload to a YAML string. + pub fn to_yaml(&self, ctx: &SaveContext) -> Result { + serde_yaml::to_string(&self.to_value(ctx)) + } + /// Returns typed reference to the map if the field is an object. + /// Returns `None` if the field is null or not an object. + pub fn as_telemetry_dict(&self) -> Option<&serde_json::Map> { + self.telemetry.as_object() + } + +} diff --git a/runtime/rust/prompty/src/model/events/tool_execution_start_payload.rs b/runtime/rust/prompty/src/model/events/tool_execution_start_payload.rs new file mode 100644 index 00000000..6458188a --- /dev/null +++ b/runtime/rust/prompty/src/model/events/tool_execution_start_payload.rs @@ -0,0 +1,104 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use super::super::context::{LoadContext, SaveContext}; + +use super::redaction_metadata::RedactionMetadata; + +/// Payload for "tool_execution_start" events — the host is about to execute a concrete tool request. This is distinct from "tool_call_start", which records the model requesting a tool. Tool execution events capture the harness-side action after policy and permission checks. +#[derive(Debug, Clone, Default)] +pub struct ToolExecutionStartPayload { + /// Stable host execution request identifier + pub request_id: Option, + /// Associated model tool call identifier, when available + pub tool_call_id: Option, + /// Name of the host tool being executed + pub tool_name: String, + /// Tool arguments after host-side sanitization + pub arguments: serde_json::Value, + /// Working directory or execution scope for the tool + pub working_directory: Option, + /// Redaction state for sensitive argument fields + pub redaction: Option, +} + +impl ToolExecutionStartPayload { + /// Create a new ToolExecutionStartPayload with default values. + pub fn new() -> Self { + Self::default() + } + + /// Load ToolExecutionStartPayload from a JSON string. + pub fn from_json(json: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_json::from_str(json)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load ToolExecutionStartPayload from a YAML string. + pub fn from_yaml(yaml: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_yaml::from_str(yaml)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load ToolExecutionStartPayload from a `serde_json::Value`. + /// + /// Calls `ctx.process_input` before field extraction. + pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { + let value = ctx.process_input(value.clone()); + Self { + request_id: value.get("requestId").and_then(|v| v.as_str()).map(|s| s.to_string()), + tool_call_id: value.get("toolCallId").and_then(|v| v.as_str()).map(|s| s.to_string()), + tool_name: value.get("toolName").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + arguments: value.get("arguments").cloned().unwrap_or(serde_json::Value::Null), + working_directory: value.get("workingDirectory").and_then(|v| v.as_str()).map(|s| s.to_string()), + redaction: value.get("redaction").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| RedactionMetadata::load_from_value(v, ctx)), + } + } + + /// Serialize ToolExecutionStartPayload to a `serde_json::Value`. + /// + /// Calls `ctx.process_dict` after serialization. + pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { + let mut result = serde_json::Map::new(); + // Write base fields + if let Some(ref val) = self.request_id { + result.insert("requestId".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(ref val) = self.tool_call_id { + result.insert("toolCallId".to_string(), serde_json::Value::String(val.clone())); + } + if !self.tool_name.is_empty() { + result.insert("toolName".to_string(), serde_json::Value::String(self.tool_name.clone())); + } + if !self.arguments.is_null() { + result.insert("arguments".to_string(), self.arguments.clone()); + } + if let Some(ref val) = self.working_directory { + result.insert("workingDirectory".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(ref val) = self.redaction { + let nested = val.to_value(ctx); + if !nested.is_null() { + result.insert("redaction".to_string(), nested); + } + } + ctx.process_dict(serde_json::Value::Object(result)) + } + + /// Serialize ToolExecutionStartPayload to a JSON string. + pub fn to_json(&self, ctx: &SaveContext) -> Result { + serde_json::to_string_pretty(&self.to_value(ctx)) + } + + /// Serialize ToolExecutionStartPayload to a YAML string. + pub fn to_yaml(&self, ctx: &SaveContext) -> Result { + serde_yaml::to_string(&self.to_value(ctx)) + } + /// Returns typed reference to the map if the field is an object. + /// Returns `None` if the field is null or not an object. + pub fn as_arguments_dict(&self) -> Option<&serde_json::Map> { + self.arguments.as_object() + } + +} diff --git a/runtime/rust/prompty/src/model/events/trajectory_event.rs b/runtime/rust/prompty/src/model/events/trajectory_event.rs new file mode 100644 index 00000000..0af08b52 --- /dev/null +++ b/runtime/rust/prompty/src/model/events/trajectory_event.rs @@ -0,0 +1,122 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use super::super::context::{LoadContext, SaveContext}; + +use super::redaction_metadata::RedactionMetadata; + +/// A compact, replay-oriented record of one harness-side action or observation. +#[derive(Debug, Clone, Default)] +pub struct TrajectoryEvent { + /// Stable trajectory event identifier + pub id: Option, + /// Stable session identifier + pub session_id: Option, + /// Associated turn identifier, when available + pub turn_id: Option, + /// Associated tool call identifier, when available + pub tool_call_id: Option, + /// Zero-based turn index in the session + pub turn_index: Option, + /// Host-defined trajectory event category + pub event_type: String, + /// Sanitized event data + pub data: serde_json::Value, + /// ISO 8601 UTC timestamp when the trajectory event was recorded + pub created_at: Option, + /// Redaction state for sensitive trajectory fields + pub redaction: Option, +} + +impl TrajectoryEvent { + /// Create a new TrajectoryEvent with default values. + pub fn new() -> Self { + Self::default() + } + + /// Load TrajectoryEvent from a JSON string. + pub fn from_json(json: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_json::from_str(json)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load TrajectoryEvent from a YAML string. + pub fn from_yaml(yaml: &str, ctx: &LoadContext) -> Result { + let value: serde_json::Value = serde_yaml::from_str(yaml)?; + Ok(Self::load_from_value(&value, ctx)) + } + + /// Load TrajectoryEvent from a `serde_json::Value`. + /// + /// Calls `ctx.process_input` before field extraction. + pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { + let value = ctx.process_input(value.clone()); + Self { + id: value.get("id").and_then(|v| v.as_str()).map(|s| s.to_string()), + session_id: value.get("sessionId").and_then(|v| v.as_str()).map(|s| s.to_string()), + turn_id: value.get("turnId").and_then(|v| v.as_str()).map(|s| s.to_string()), + tool_call_id: value.get("toolCallId").and_then(|v| v.as_str()).map(|s| s.to_string()), + turn_index: value.get("turnIndex").and_then(|v| v.as_i64()).map(|v| v as i32), + event_type: value.get("eventType").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + data: value.get("data").cloned().unwrap_or(serde_json::Value::Null), + created_at: value.get("createdAt").and_then(|v| v.as_str()).map(|s| s.to_string()), + redaction: value.get("redaction").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| RedactionMetadata::load_from_value(v, ctx)), + } + } + + /// Serialize TrajectoryEvent to a `serde_json::Value`. + /// + /// Calls `ctx.process_dict` after serialization. + pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { + let mut result = serde_json::Map::new(); + // Write base fields + if let Some(ref val) = self.id { + result.insert("id".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(ref val) = self.session_id { + result.insert("sessionId".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(ref val) = self.turn_id { + result.insert("turnId".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(ref val) = self.tool_call_id { + result.insert("toolCallId".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(val) = self.turn_index { + result.insert("turnIndex".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + } + if !self.event_type.is_empty() { + result.insert("eventType".to_string(), serde_json::Value::String(self.event_type.clone())); + } + if !self.data.is_null() { + result.insert("data".to_string(), self.data.clone()); + } + if let Some(ref val) = self.created_at { + result.insert("createdAt".to_string(), serde_json::Value::String(val.clone())); + } + if let Some(ref val) = self.redaction { + let nested = val.to_value(ctx); + if !nested.is_null() { + result.insert("redaction".to_string(), nested); + } + } + ctx.process_dict(serde_json::Value::Object(result)) + } + + /// Serialize TrajectoryEvent to a JSON string. + pub fn to_json(&self, ctx: &SaveContext) -> Result { + serde_json::to_string_pretty(&self.to_value(ctx)) + } + + /// Serialize TrajectoryEvent to a YAML string. + pub fn to_yaml(&self, ctx: &SaveContext) -> Result { + serde_yaml::to_string(&self.to_value(ctx)) + } + /// Returns typed reference to the map if the field is an object. + /// Returns `None` if the field is null or not an object. + pub fn as_data_dict(&self) -> Option<&serde_json::Map> { + self.data.as_object() + } + +} diff --git a/runtime/rust/prompty/src/model/events/turn_event.rs b/runtime/rust/prompty/src/model/events/turn_event.rs index ae2bd627..266d8531 100644 --- a/runtime/rust/prompty/src/model/events/turn_event.rs +++ b/runtime/rust/prompty/src/model/events/turn_event.rs @@ -17,7 +17,11 @@ pub enum TurnEventType { Thinking, Tool_call_start, Tool_call_complete, + Tool_execution_start, + Tool_execution_complete, Tool_result, + Hook_start, + Hook_end, Status, Messages_updated, Done, @@ -48,7 +52,11 @@ impl std::fmt::Display for TurnEventType { Self::Thinking => write!(f, "thinking"), Self::Tool_call_start => write!(f, "tool_call_start"), Self::Tool_call_complete => write!(f, "tool_call_complete"), + Self::Tool_execution_start => write!(f, "tool_execution_start"), + Self::Tool_execution_complete => write!(f, "tool_execution_complete"), Self::Tool_result => write!(f, "tool_result"), + Self::Hook_start => write!(f, "hook_start"), + Self::Hook_end => write!(f, "hook_end"), Self::Status => write!(f, "status"), Self::Messages_updated => write!(f, "messages_updated"), Self::Done => write!(f, "done"), @@ -75,7 +83,11 @@ impl TurnEventType { "thinking" => Some(Self::Thinking), "tool_call_start" => Some(Self::Tool_call_start), "tool_call_complete" => Some(Self::Tool_call_complete), + "tool_execution_start" => Some(Self::Tool_execution_start), + "tool_execution_complete" => Some(Self::Tool_execution_complete), "tool_result" => Some(Self::Tool_result), + "hook_start" => Some(Self::Hook_start), + "hook_end" => Some(Self::Hook_end), "status" => Some(Self::Status), "messages_updated" => Some(Self::Messages_updated), "done" => Some(Self::Done), @@ -101,7 +113,11 @@ impl TurnEventType { Self::Thinking => "thinking", Self::Tool_call_start => "tool_call_start", Self::Tool_call_complete => "tool_call_complete", + Self::Tool_execution_start => "tool_execution_start", + Self::Tool_execution_complete => "tool_execution_complete", Self::Tool_result => "tool_result", + Self::Hook_start => "hook_start", + Self::Hook_end => "hook_end", Self::Status => "status", Self::Messages_updated => "messages_updated", Self::Done => "done", diff --git a/runtime/rust/prompty/src/model/pipeline/checkpoint_store.rs b/runtime/rust/prompty/src/model/pipeline/checkpoint_store.rs new file mode 100644 index 00000000..3c494b57 --- /dev/null +++ b/runtime/rust/prompty/src/model/pipeline/checkpoint_store.rs @@ -0,0 +1,17 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + + +use super::super::events::checkpoint::Checkpoint; + +/// Stores and retrieves resumable session checkpoints. +#[async_trait::async_trait] +pub trait CheckpointStore: Send + Sync { + /// Persist a session checkpoint and return the stored checkpoint + async fn save(&self, checkpoint: &Checkpoint) -> Result>; + /// Load a checkpoint by session and checkpoint identifier + async fn load(&self, session_id: &String, checkpoint_id: &String) -> Result, Box>; + /// List checkpoints for a session + async fn list_checkpoints(&self, session_id: &String) -> Result, Box>; +} diff --git a/runtime/rust/prompty/src/model/pipeline/event_sink.rs b/runtime/rust/prompty/src/model/pipeline/event_sink.rs new file mode 100644 index 00000000..77646e7e --- /dev/null +++ b/runtime/rust/prompty/src/model/pipeline/event_sink.rs @@ -0,0 +1,17 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + + +use super::super::events::session_event::SessionEvent; + +use super::super::events::turn_event::TurnEvent; + +/// Receives typed turn and session events from a harness. +#[async_trait::async_trait] +pub trait EventSink: Send + Sync { + /// Emit a typed turn event to a host sink + fn emit_turn(&self, turn_event: &TurnEvent) -> bool; + /// Emit a typed session event to a host sink + fn emit_session(&self, session_event: &SessionEvent) -> bool; +} diff --git a/runtime/rust/prompty/src/model/pipeline/host_tool_executor.rs b/runtime/rust/prompty/src/model/pipeline/host_tool_executor.rs new file mode 100644 index 00000000..5d72087a --- /dev/null +++ b/runtime/rust/prompty/src/model/pipeline/host_tool_executor.rs @@ -0,0 +1,15 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + + +use super::super::events::host_tool_request::HostToolRequest; + +use super::super::events::host_tool_result::HostToolResult; + +/// Executes host tools after policy and permission checks. +#[async_trait::async_trait] +pub trait HostToolExecutor: Send + Sync { + /// Execute a concrete host tool request and return its completion payload + async fn execute(&self, request: &HostToolRequest) -> Result>; +} diff --git a/runtime/rust/prompty/src/model/pipeline/mod.rs b/runtime/rust/prompty/src/model/pipeline/mod.rs index ab85d056..f2cbc64d 100644 --- a/runtime/rust/prompty/src/model/pipeline/mod.rs +++ b/runtime/rust/prompty/src/model/pipeline/mod.rs @@ -19,3 +19,18 @@ pub use executor::*; pub mod processor; pub use processor::*; + +pub mod event_sink; +pub use event_sink::*; + +pub mod trace_writer; +pub use trace_writer::*; + +pub mod permission_resolver; +pub use permission_resolver::*; + +pub mod checkpoint_store; +pub use checkpoint_store::*; + +pub mod host_tool_executor; +pub use host_tool_executor::*; diff --git a/runtime/rust/prompty/src/model/pipeline/permission_resolver.rs b/runtime/rust/prompty/src/model/pipeline/permission_resolver.rs new file mode 100644 index 00000000..43aa3808 --- /dev/null +++ b/runtime/rust/prompty/src/model/pipeline/permission_resolver.rs @@ -0,0 +1,15 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + + +use super::super::events::permission_decision::PermissionDecision; + +use super::super::events::permission_request::PermissionRequest; + +/// Resolves host permission requests for potentially sensitive actions. +#[async_trait::async_trait] +pub trait PermissionResolver: Send + Sync { + /// Resolve a host permission request + async fn request(&self, request: &PermissionRequest) -> Result>; +} diff --git a/runtime/rust/prompty/src/model/pipeline/trace_writer.rs b/runtime/rust/prompty/src/model/pipeline/trace_writer.rs new file mode 100644 index 00000000..d1734168 --- /dev/null +++ b/runtime/rust/prompty/src/model/pipeline/trace_writer.rs @@ -0,0 +1,21 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + + +use super::super::events::session_event::SessionEvent; + +use super::super::events::session_summary::SessionSummary; + +use super::super::events::turn_event::TurnEvent; + +/// Persists typed events to a replayable trace. +#[async_trait::async_trait] +pub trait TraceWriter: Send + Sync { + /// Append a turn event to a replayable trace + fn append_turn(&self, turn_event: &TurnEvent) -> bool; + /// Append a session event to a replayable trace + fn append_session(&self, session_event: &SessionEvent) -> bool; + /// Finalize the trace with an optional session summary + fn close(&self, summary: &Option) -> bool; +} diff --git a/runtime/rust/prompty/tests/model/events/checkpoint_test.rs b/runtime/rust/prompty/tests/model/events/checkpoint_test.rs new file mode 100644 index 00000000..f372e2e2 --- /dev/null +++ b/runtime/rust/prompty/tests/model/events/checkpoint_test.rs @@ -0,0 +1,79 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use prompty::model::Checkpoint; +use prompty::model::context::{LoadContext, SaveContext}; + +#[test] +fn test_checkpoint_load_json() { + let json = r####" +{ + "id": "chk_abc123", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "checkpointNumber": 3, + "title": "Added harness contracts", + "createdAt": "2026-06-09T20:00:00Z" +} +"####; + let ctx = LoadContext::default(); + let result = Checkpoint::from_json(json, &ctx); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + let instance = result.unwrap(); + assert!(instance.id.is_some(), "Expected id to be Some"); + assert_eq!(instance.id.as_ref().unwrap(), &"chk_abc123"); + assert!(instance.session_id.is_some(), "Expected session_id to be Some"); + assert_eq!(instance.session_id.as_ref().unwrap(), &"sess_abc123"); + assert!(instance.turn_id.is_some(), "Expected turn_id to be Some"); + assert_eq!(instance.turn_id.as_ref().unwrap(), &"turn_001"); + assert!(instance.checkpoint_number.is_some(), "Expected checkpoint_number to be Some"); + assert_eq!(instance.checkpoint_number.as_ref().unwrap(), &3); + assert_eq!(instance.title, "Added harness contracts"); + assert!(instance.created_at.is_some(), "Expected created_at to be Some"); + assert_eq!(instance.created_at.as_ref().unwrap(), &"2026-06-09T20:00:00Z"); +} + +#[test] +fn test_checkpoint_load_yaml() { + let yaml = r####" +id: chk_abc123 +sessionId: sess_abc123 +turnId: turn_001 +checkpointNumber: 3 +title: Added harness contracts +createdAt: "2026-06-09T20:00:00Z" + +"####; + let ctx = LoadContext::default(); + let result = Checkpoint::from_yaml(yaml, &ctx); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + let instance = result.unwrap(); + assert!(instance.id.is_some(), "Expected id to be Some"); + assert!(instance.session_id.is_some(), "Expected session_id to be Some"); + assert!(instance.turn_id.is_some(), "Expected turn_id to be Some"); + assert!(instance.checkpoint_number.is_some(), "Expected checkpoint_number to be Some"); + assert_eq!(instance.title, "Added harness contracts"); + assert!(instance.created_at.is_some(), "Expected created_at to be Some"); +} + +#[test] +fn test_checkpoint_roundtrip() { + let json = r####" +{ + "id": "chk_abc123", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "checkpointNumber": 3, + "title": "Added harness contracts", + "createdAt": "2026-06-09T20:00:00Z" +} +"####; + let load_ctx = LoadContext::default(); + let result = Checkpoint::from_json(json, &load_ctx); + assert!(result.is_ok(), "Failed to load: {:?}", result.err()); + let instance = result.unwrap(); + let save_ctx = SaveContext::default(); + let json_output = instance.to_json(&save_ctx); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); +} diff --git a/runtime/rust/prompty/tests/model/events/harness_context_test.rs b/runtime/rust/prompty/tests/model/events/harness_context_test.rs new file mode 100644 index 00000000..721019e5 --- /dev/null +++ b/runtime/rust/prompty/tests/model/events/harness_context_test.rs @@ -0,0 +1,56 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use prompty::model::HarnessContext; +use prompty::model::context::{LoadContext, SaveContext}; + +#[test] +fn test_harness_context_load_json() { + let json = r####" +{ + "cwd": "/workspace/project", + "gitRoot": "/workspace/project" +} +"####; + let ctx = LoadContext::default(); + let result = HarnessContext::from_json(json, &ctx); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + let instance = result.unwrap(); + assert!(instance.cwd.is_some(), "Expected cwd to be Some"); + assert_eq!(instance.cwd.as_ref().unwrap(), &"/workspace/project"); + assert!(instance.git_root.is_some(), "Expected git_root to be Some"); + assert_eq!(instance.git_root.as_ref().unwrap(), &"/workspace/project"); +} + +#[test] +fn test_harness_context_load_yaml() { + let yaml = r####" +cwd: /workspace/project +gitRoot: /workspace/project + +"####; + let ctx = LoadContext::default(); + let result = HarnessContext::from_yaml(yaml, &ctx); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + let instance = result.unwrap(); + assert!(instance.cwd.is_some(), "Expected cwd to be Some"); + assert!(instance.git_root.is_some(), "Expected git_root to be Some"); +} + +#[test] +fn test_harness_context_roundtrip() { + let json = r####" +{ + "cwd": "/workspace/project", + "gitRoot": "/workspace/project" +} +"####; + let load_ctx = LoadContext::default(); + let result = HarnessContext::from_json(json, &load_ctx); + assert!(result.is_ok(), "Failed to load: {:?}", result.err()); + let instance = result.unwrap(); + let save_ctx = SaveContext::default(); + let json_output = instance.to_json(&save_ctx); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); +} diff --git a/runtime/rust/prompty/tests/model/events/hook_end_payload_test.rs b/runtime/rust/prompty/tests/model/events/hook_end_payload_test.rs new file mode 100644 index 00000000..d9b910c3 --- /dev/null +++ b/runtime/rust/prompty/tests/model/events/hook_end_payload_test.rs @@ -0,0 +1,71 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use prompty::model::HookEndPayload; +use prompty::model::context::{LoadContext, SaveContext}; + +#[test] +fn test_hook_end_payload_load_json() { + let json = r####" +{ + "hookInvocationId": "hook_abc123", + "hookType": "preToolUse", + "success": true, + "durationMs": 12, + "error": "hook failed" +} +"####; + let ctx = LoadContext::default(); + let result = HookEndPayload::from_json(json, &ctx); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + let instance = result.unwrap(); + assert_eq!(instance.hook_invocation_id, "hook_abc123"); + assert_eq!(instance.hook_type, "preToolUse"); + assert_eq!(instance.success, true); + assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); + assert_eq!(instance.duration_ms.as_ref().unwrap(), &12.0); + assert!(instance.error.is_some(), "Expected error to be Some"); + assert_eq!(instance.error.as_ref().unwrap(), &"hook failed"); +} + +#[test] +fn test_hook_end_payload_load_yaml() { + let yaml = r####" +hookInvocationId: hook_abc123 +hookType: preToolUse +success: true +durationMs: 12 +error: hook failed + +"####; + let ctx = LoadContext::default(); + let result = HookEndPayload::from_yaml(yaml, &ctx); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + let instance = result.unwrap(); + assert_eq!(instance.hook_invocation_id, "hook_abc123"); + assert_eq!(instance.hook_type, "preToolUse"); + assert_eq!(instance.success, true); + assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); + assert!(instance.error.is_some(), "Expected error to be Some"); +} + +#[test] +fn test_hook_end_payload_roundtrip() { + let json = r####" +{ + "hookInvocationId": "hook_abc123", + "hookType": "preToolUse", + "success": true, + "durationMs": 12, + "error": "hook failed" +} +"####; + let load_ctx = LoadContext::default(); + let result = HookEndPayload::from_json(json, &load_ctx); + assert!(result.is_ok(), "Failed to load: {:?}", result.err()); + let instance = result.unwrap(); + let save_ctx = SaveContext::default(); + let json_output = instance.to_json(&save_ctx); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); +} diff --git a/runtime/rust/prompty/tests/model/events/hook_start_payload_test.rs b/runtime/rust/prompty/tests/model/events/hook_start_payload_test.rs new file mode 100644 index 00000000..3bdb1df7 --- /dev/null +++ b/runtime/rust/prompty/tests/model/events/hook_start_payload_test.rs @@ -0,0 +1,54 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use prompty::model::HookStartPayload; +use prompty::model::context::{LoadContext, SaveContext}; + +#[test] +fn test_hook_start_payload_load_json() { + let json = r####" +{ + "hookInvocationId": "hook_abc123", + "hookType": "preToolUse" +} +"####; + let ctx = LoadContext::default(); + let result = HookStartPayload::from_json(json, &ctx); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + let instance = result.unwrap(); + assert_eq!(instance.hook_invocation_id, "hook_abc123"); + assert_eq!(instance.hook_type, "preToolUse"); +} + +#[test] +fn test_hook_start_payload_load_yaml() { + let yaml = r####" +hookInvocationId: hook_abc123 +hookType: preToolUse + +"####; + let ctx = LoadContext::default(); + let result = HookStartPayload::from_yaml(yaml, &ctx); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + let instance = result.unwrap(); + assert_eq!(instance.hook_invocation_id, "hook_abc123"); + assert_eq!(instance.hook_type, "preToolUse"); +} + +#[test] +fn test_hook_start_payload_roundtrip() { + let json = r####" +{ + "hookInvocationId": "hook_abc123", + "hookType": "preToolUse" +} +"####; + let load_ctx = LoadContext::default(); + let result = HookStartPayload::from_json(json, &load_ctx); + assert!(result.is_ok(), "Failed to load: {:?}", result.err()); + let instance = result.unwrap(); + let save_ctx = SaveContext::default(); + let json_output = instance.to_json(&save_ctx); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); +} diff --git a/runtime/rust/prompty/tests/model/events/host_tool_request_test.rs b/runtime/rust/prompty/tests/model/events/host_tool_request_test.rs new file mode 100644 index 00000000..99caee25 --- /dev/null +++ b/runtime/rust/prompty/tests/model/events/host_tool_request_test.rs @@ -0,0 +1,67 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use prompty::model::HostToolRequest; +use prompty::model::context::{LoadContext, SaveContext}; + +#[test] +fn test_host_tool_request_load_json() { + let json = r####" +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "workingDirectory": "/workspace/project" +} +"####; + let ctx = LoadContext::default(); + let result = HostToolRequest::from_json(json, &ctx); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + let instance = result.unwrap(); + assert!(instance.request_id.is_some(), "Expected request_id to be Some"); + assert_eq!(instance.request_id.as_ref().unwrap(), &"exec_abc123"); + assert!(instance.tool_call_id.is_some(), "Expected tool_call_id to be Some"); + assert_eq!(instance.tool_call_id.as_ref().unwrap(), &"call_abc123"); + assert_eq!(instance.tool_name, "powershell"); + assert!(instance.working_directory.is_some(), "Expected working_directory to be Some"); + assert_eq!(instance.working_directory.as_ref().unwrap(), &"/workspace/project"); +} + +#[test] +fn test_host_tool_request_load_yaml() { + let yaml = r####" +requestId: exec_abc123 +toolCallId: call_abc123 +toolName: powershell +workingDirectory: /workspace/project + +"####; + let ctx = LoadContext::default(); + let result = HostToolRequest::from_yaml(yaml, &ctx); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + let instance = result.unwrap(); + assert!(instance.request_id.is_some(), "Expected request_id to be Some"); + assert!(instance.tool_call_id.is_some(), "Expected tool_call_id to be Some"); + assert_eq!(instance.tool_name, "powershell"); + assert!(instance.working_directory.is_some(), "Expected working_directory to be Some"); +} + +#[test] +fn test_host_tool_request_roundtrip() { + let json = r####" +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "workingDirectory": "/workspace/project" +} +"####; + let load_ctx = LoadContext::default(); + let result = HostToolRequest::from_json(json, &load_ctx); + assert!(result.is_ok(), "Failed to load: {:?}", result.err()); + let instance = result.unwrap(); + let save_ctx = SaveContext::default(); + let json_output = instance.to_json(&save_ctx); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); +} diff --git a/runtime/rust/prompty/tests/model/events/host_tool_result_test.rs b/runtime/rust/prompty/tests/model/events/host_tool_result_test.rs new file mode 100644 index 00000000..85988f25 --- /dev/null +++ b/runtime/rust/prompty/tests/model/events/host_tool_result_test.rs @@ -0,0 +1,84 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use prompty::model::HostToolResult; +use prompty::model::context::{LoadContext, SaveContext}; + +#[test] +fn test_host_tool_result_load_json() { + let json = r####" +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "success": true, + "exitCode": 0, + "durationMs": 250, + "errorKind": "timeout" +} +"####; + let ctx = LoadContext::default(); + let result = HostToolResult::from_json(json, &ctx); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + let instance = result.unwrap(); + assert!(instance.request_id.is_some(), "Expected request_id to be Some"); + assert_eq!(instance.request_id.as_ref().unwrap(), &"exec_abc123"); + assert!(instance.tool_call_id.is_some(), "Expected tool_call_id to be Some"); + assert_eq!(instance.tool_call_id.as_ref().unwrap(), &"call_abc123"); + assert_eq!(instance.tool_name, "powershell"); + assert_eq!(instance.success, true); + assert!(instance.exit_code.is_some(), "Expected exit_code to be Some"); + assert_eq!(instance.exit_code.as_ref().unwrap(), &0); + assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); + assert_eq!(instance.duration_ms.as_ref().unwrap(), &250.0); + assert!(instance.error_kind.is_some(), "Expected error_kind to be Some"); + assert_eq!(instance.error_kind.as_ref().unwrap(), &"timeout"); +} + +#[test] +fn test_host_tool_result_load_yaml() { + let yaml = r####" +requestId: exec_abc123 +toolCallId: call_abc123 +toolName: powershell +success: true +exitCode: 0 +durationMs: 250 +errorKind: timeout + +"####; + let ctx = LoadContext::default(); + let result = HostToolResult::from_yaml(yaml, &ctx); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + let instance = result.unwrap(); + assert!(instance.request_id.is_some(), "Expected request_id to be Some"); + assert!(instance.tool_call_id.is_some(), "Expected tool_call_id to be Some"); + assert_eq!(instance.tool_name, "powershell"); + assert_eq!(instance.success, true); + assert!(instance.exit_code.is_some(), "Expected exit_code to be Some"); + assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); + assert!(instance.error_kind.is_some(), "Expected error_kind to be Some"); +} + +#[test] +fn test_host_tool_result_roundtrip() { + let json = r####" +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "success": true, + "exitCode": 0, + "durationMs": 250, + "errorKind": "timeout" +} +"####; + let load_ctx = LoadContext::default(); + let result = HostToolResult::from_json(json, &load_ctx); + assert!(result.is_ok(), "Failed to load: {:?}", result.err()); + let instance = result.unwrap(); + let save_ctx = SaveContext::default(); + let json_output = instance.to_json(&save_ctx); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); +} diff --git a/runtime/rust/prompty/tests/model/events/mod.rs b/runtime/rust/prompty/tests/model/events/mod.rs index 41ed2c8c..229103f1 100644 --- a/runtime/rust/prompty/tests/model/events/mod.rs +++ b/runtime/rust/prompty/tests/model/events/mod.rs @@ -8,12 +8,22 @@ mod turn_end_payload_test; mod llm_start_payload_test; mod llm_complete_payload_test; mod retry_payload_test; +mod redacted_field_test; +mod redaction_metadata_test; mod permission_requested_payload_test; mod permission_completed_payload_test; +mod permission_request_test; +mod permission_decision_test; mod token_event_payload_test; mod thinking_event_payload_test; mod tool_call_start_payload_test; mod tool_call_complete_payload_test; +mod tool_execution_start_payload_test; +mod tool_execution_complete_payload_test; +mod host_tool_request_test; +mod host_tool_result_test; +mod hook_start_payload_test; +mod hook_end_payload_test; mod tool_result_payload_test; mod status_event_payload_test; mod messages_updated_payload_test; @@ -24,4 +34,15 @@ mod compaction_complete_payload_test; mod compaction_failed_payload_test; mod turn_summary_test; mod turn_trace_test; +mod harness_context_test; +mod session_start_payload_test; +mod session_end_payload_test; +mod session_warning_payload_test; +mod session_event_test; +mod checkpoint_test; +mod trajectory_event_test; +mod session_file_ref_test; +mod session_ref_test; +mod session_summary_test; +mod session_trace_test; mod stream_chunk_test; diff --git a/runtime/rust/prompty/tests/model/events/permission_completed_payload_test.rs b/runtime/rust/prompty/tests/model/events/permission_completed_payload_test.rs index 9bf890c0..128ed55b 100644 --- a/runtime/rust/prompty/tests/model/events/permission_completed_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/permission_completed_payload_test.rs @@ -9,6 +9,8 @@ use prompty::model::context::{LoadContext, SaveContext}; fn test_permission_completed_payload_load_json() { let json = r####" { + "requestId": "perm_abc123", + "toolCallId": "call_abc123", "permission": "tool.execute", "approved": true, "reason": "user_approved" @@ -18,6 +20,10 @@ fn test_permission_completed_payload_load_json() { let result = PermissionCompletedPayload::from_json(json, &ctx); assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); + assert!(instance.request_id.is_some(), "Expected request_id to be Some"); + assert_eq!(instance.request_id.as_ref().unwrap(), &"perm_abc123"); + assert!(instance.tool_call_id.is_some(), "Expected tool_call_id to be Some"); + assert_eq!(instance.tool_call_id.as_ref().unwrap(), &"call_abc123"); assert_eq!(instance.permission, "tool.execute"); assert_eq!(instance.approved, true); assert!(instance.reason.is_some(), "Expected reason to be Some"); @@ -27,6 +33,8 @@ fn test_permission_completed_payload_load_json() { #[test] fn test_permission_completed_payload_load_yaml() { let yaml = r####" +requestId: perm_abc123 +toolCallId: call_abc123 permission: tool.execute approved: true reason: user_approved @@ -36,6 +44,8 @@ reason: user_approved let result = PermissionCompletedPayload::from_yaml(yaml, &ctx); assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); + assert!(instance.request_id.is_some(), "Expected request_id to be Some"); + assert!(instance.tool_call_id.is_some(), "Expected tool_call_id to be Some"); assert_eq!(instance.permission, "tool.execute"); assert_eq!(instance.approved, true); assert!(instance.reason.is_some(), "Expected reason to be Some"); @@ -45,6 +55,8 @@ reason: user_approved fn test_permission_completed_payload_roundtrip() { let json = r####" { + "requestId": "perm_abc123", + "toolCallId": "call_abc123", "permission": "tool.execute", "approved": true, "reason": "user_approved" diff --git a/runtime/rust/prompty/tests/model/events/permission_decision_test.rs b/runtime/rust/prompty/tests/model/events/permission_decision_test.rs new file mode 100644 index 00000000..eaef93f4 --- /dev/null +++ b/runtime/rust/prompty/tests/model/events/permission_decision_test.rs @@ -0,0 +1,72 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use prompty::model::PermissionDecision; +use prompty::model::context::{LoadContext, SaveContext}; + +#[test] +fn test_permission_decision_load_json() { + let json = r####" +{ + "requestId": "perm_abc123", + "toolCallId": "call_abc123", + "permission": "tool.execute", + "approved": true, + "reason": "user_approved" +} +"####; + let ctx = LoadContext::default(); + let result = PermissionDecision::from_json(json, &ctx); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + let instance = result.unwrap(); + assert!(instance.request_id.is_some(), "Expected request_id to be Some"); + assert_eq!(instance.request_id.as_ref().unwrap(), &"perm_abc123"); + assert!(instance.tool_call_id.is_some(), "Expected tool_call_id to be Some"); + assert_eq!(instance.tool_call_id.as_ref().unwrap(), &"call_abc123"); + assert_eq!(instance.permission, "tool.execute"); + assert_eq!(instance.approved, true); + assert!(instance.reason.is_some(), "Expected reason to be Some"); + assert_eq!(instance.reason.as_ref().unwrap(), &"user_approved"); +} + +#[test] +fn test_permission_decision_load_yaml() { + let yaml = r####" +requestId: perm_abc123 +toolCallId: call_abc123 +permission: tool.execute +approved: true +reason: user_approved + +"####; + let ctx = LoadContext::default(); + let result = PermissionDecision::from_yaml(yaml, &ctx); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + let instance = result.unwrap(); + assert!(instance.request_id.is_some(), "Expected request_id to be Some"); + assert!(instance.tool_call_id.is_some(), "Expected tool_call_id to be Some"); + assert_eq!(instance.permission, "tool.execute"); + assert_eq!(instance.approved, true); + assert!(instance.reason.is_some(), "Expected reason to be Some"); +} + +#[test] +fn test_permission_decision_roundtrip() { + let json = r####" +{ + "requestId": "perm_abc123", + "toolCallId": "call_abc123", + "permission": "tool.execute", + "approved": true, + "reason": "user_approved" +} +"####; + let load_ctx = LoadContext::default(); + let result = PermissionDecision::from_json(json, &load_ctx); + assert!(result.is_ok(), "Failed to load: {:?}", result.err()); + let instance = result.unwrap(); + let save_ctx = SaveContext::default(); + let json_output = instance.to_json(&save_ctx); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); +} diff --git a/runtime/rust/prompty/tests/model/events/permission_request_test.rs b/runtime/rust/prompty/tests/model/events/permission_request_test.rs new file mode 100644 index 00000000..efbd6ecd --- /dev/null +++ b/runtime/rust/prompty/tests/model/events/permission_request_test.rs @@ -0,0 +1,73 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use prompty::model::PermissionRequest; +use prompty::model::context::{LoadContext, SaveContext}; + +#[test] +fn test_permission_request_load_json() { + let json = r####" +{ + "requestId": "perm_abc123", + "toolCallId": "call_abc123", + "permission": "tool.execute", + "target": "shell", + "promptRequest": "Allow shell to run tests?" +} +"####; + let ctx = LoadContext::default(); + let result = PermissionRequest::from_json(json, &ctx); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + let instance = result.unwrap(); + assert!(instance.request_id.is_some(), "Expected request_id to be Some"); + assert_eq!(instance.request_id.as_ref().unwrap(), &"perm_abc123"); + assert!(instance.tool_call_id.is_some(), "Expected tool_call_id to be Some"); + assert_eq!(instance.tool_call_id.as_ref().unwrap(), &"call_abc123"); + assert_eq!(instance.permission, "tool.execute"); + assert!(instance.target.is_some(), "Expected target to be Some"); + assert_eq!(instance.target.as_ref().unwrap(), &"shell"); + assert!(instance.prompt_request.is_some(), "Expected prompt_request to be Some"); + assert_eq!(instance.prompt_request.as_ref().unwrap(), &"Allow shell to run tests?"); +} + +#[test] +fn test_permission_request_load_yaml() { + let yaml = r####" +requestId: perm_abc123 +toolCallId: call_abc123 +permission: tool.execute +target: shell +promptRequest: Allow shell to run tests? + +"####; + let ctx = LoadContext::default(); + let result = PermissionRequest::from_yaml(yaml, &ctx); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + let instance = result.unwrap(); + assert!(instance.request_id.is_some(), "Expected request_id to be Some"); + assert!(instance.tool_call_id.is_some(), "Expected tool_call_id to be Some"); + assert_eq!(instance.permission, "tool.execute"); + assert!(instance.target.is_some(), "Expected target to be Some"); + assert!(instance.prompt_request.is_some(), "Expected prompt_request to be Some"); +} + +#[test] +fn test_permission_request_roundtrip() { + let json = r####" +{ + "requestId": "perm_abc123", + "toolCallId": "call_abc123", + "permission": "tool.execute", + "target": "shell", + "promptRequest": "Allow shell to run tests?" +} +"####; + let load_ctx = LoadContext::default(); + let result = PermissionRequest::from_json(json, &load_ctx); + assert!(result.is_ok(), "Failed to load: {:?}", result.err()); + let instance = result.unwrap(); + let save_ctx = SaveContext::default(); + let json_output = instance.to_json(&save_ctx); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); +} diff --git a/runtime/rust/prompty/tests/model/events/permission_requested_payload_test.rs b/runtime/rust/prompty/tests/model/events/permission_requested_payload_test.rs index bb3b74a5..683c86a9 100644 --- a/runtime/rust/prompty/tests/model/events/permission_requested_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/permission_requested_payload_test.rs @@ -9,40 +9,58 @@ use prompty::model::context::{LoadContext, SaveContext}; fn test_permission_requested_payload_load_json() { let json = r####" { + "requestId": "perm_abc123", + "toolCallId": "call_abc123", "permission": "tool.execute", - "target": "shell" + "target": "shell", + "promptRequest": "Allow shell to run tests?" } "####; let ctx = LoadContext::default(); let result = PermissionRequestedPayload::from_json(json, &ctx); assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); + assert!(instance.request_id.is_some(), "Expected request_id to be Some"); + assert_eq!(instance.request_id.as_ref().unwrap(), &"perm_abc123"); + assert!(instance.tool_call_id.is_some(), "Expected tool_call_id to be Some"); + assert_eq!(instance.tool_call_id.as_ref().unwrap(), &"call_abc123"); assert_eq!(instance.permission, "tool.execute"); assert!(instance.target.is_some(), "Expected target to be Some"); assert_eq!(instance.target.as_ref().unwrap(), &"shell"); + assert!(instance.prompt_request.is_some(), "Expected prompt_request to be Some"); + assert_eq!(instance.prompt_request.as_ref().unwrap(), &"Allow shell to run tests?"); } #[test] fn test_permission_requested_payload_load_yaml() { let yaml = r####" +requestId: perm_abc123 +toolCallId: call_abc123 permission: tool.execute target: shell +promptRequest: Allow shell to run tests? "####; let ctx = LoadContext::default(); let result = PermissionRequestedPayload::from_yaml(yaml, &ctx); assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); + assert!(instance.request_id.is_some(), "Expected request_id to be Some"); + assert!(instance.tool_call_id.is_some(), "Expected tool_call_id to be Some"); assert_eq!(instance.permission, "tool.execute"); assert!(instance.target.is_some(), "Expected target to be Some"); + assert!(instance.prompt_request.is_some(), "Expected prompt_request to be Some"); } #[test] fn test_permission_requested_payload_roundtrip() { let json = r####" { + "requestId": "perm_abc123", + "toolCallId": "call_abc123", "permission": "tool.execute", - "target": "shell" + "target": "shell", + "promptRequest": "Allow shell to run tests?" } "####; let load_ctx = LoadContext::default(); diff --git a/runtime/rust/prompty/tests/model/events/redacted_field_test.rs b/runtime/rust/prompty/tests/model/events/redacted_field_test.rs new file mode 100644 index 00000000..41b1149a --- /dev/null +++ b/runtime/rust/prompty/tests/model/events/redacted_field_test.rs @@ -0,0 +1,61 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use prompty::model::RedactedField; +use prompty::model::RedactionMode; +use prompty::model::context::{LoadContext, SaveContext}; + +#[test] +fn test_redacted_field_load_json() { + let json = r####" +{ + "path": "$.arguments.apiKey", + "mode": "redacted", + "reason": "secret" +} +"####; + let ctx = LoadContext::default(); + let result = RedactedField::from_json(json, &ctx); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + let instance = result.unwrap(); + assert_eq!(instance.path, "$.arguments.apiKey"); + assert_eq!(instance.mode, RedactionMode::Redacted); + assert!(instance.reason.is_some(), "Expected reason to be Some"); + assert_eq!(instance.reason.as_ref().unwrap(), &"secret"); +} + +#[test] +fn test_redacted_field_load_yaml() { + let yaml = r####" +path: $.arguments.apiKey +mode: redacted +reason: secret + +"####; + let ctx = LoadContext::default(); + let result = RedactedField::from_yaml(yaml, &ctx); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + let instance = result.unwrap(); + assert_eq!(instance.path, "$.arguments.apiKey"); + assert_eq!(instance.mode, RedactionMode::Redacted); + assert!(instance.reason.is_some(), "Expected reason to be Some"); +} + +#[test] +fn test_redacted_field_roundtrip() { + let json = r####" +{ + "path": "$.arguments.apiKey", + "mode": "redacted", + "reason": "secret" +} +"####; + let load_ctx = LoadContext::default(); + let result = RedactedField::from_json(json, &load_ctx); + assert!(result.is_ok(), "Failed to load: {:?}", result.err()); + let instance = result.unwrap(); + let save_ctx = SaveContext::default(); + let json_output = instance.to_json(&save_ctx); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); +} diff --git a/runtime/rust/prompty/tests/model/events/redaction_metadata_test.rs b/runtime/rust/prompty/tests/model/events/redaction_metadata_test.rs new file mode 100644 index 00000000..1aefe7df --- /dev/null +++ b/runtime/rust/prompty/tests/model/events/redaction_metadata_test.rs @@ -0,0 +1,56 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use prompty::model::RedactionMetadata; +use prompty::model::context::{LoadContext, SaveContext}; + +#[test] +fn test_redaction_metadata_load_json() { + let json = r####" +{ + "sanitized": true, + "policy": "default-v1" +} +"####; + let ctx = LoadContext::default(); + let result = RedactionMetadata::from_json(json, &ctx); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + let instance = result.unwrap(); + assert!(instance.sanitized.is_some(), "Expected sanitized to be Some"); + assert_eq!(instance.sanitized.as_ref().unwrap(), &true); + assert!(instance.policy.is_some(), "Expected policy to be Some"); + assert_eq!(instance.policy.as_ref().unwrap(), &"default-v1"); +} + +#[test] +fn test_redaction_metadata_load_yaml() { + let yaml = r####" +sanitized: true +policy: default-v1 + +"####; + let ctx = LoadContext::default(); + let result = RedactionMetadata::from_yaml(yaml, &ctx); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + let instance = result.unwrap(); + assert!(instance.sanitized.is_some(), "Expected sanitized to be Some"); + assert!(instance.policy.is_some(), "Expected policy to be Some"); +} + +#[test] +fn test_redaction_metadata_roundtrip() { + let json = r####" +{ + "sanitized": true, + "policy": "default-v1" +} +"####; + let load_ctx = LoadContext::default(); + let result = RedactionMetadata::from_json(json, &load_ctx); + assert!(result.is_ok(), "Failed to load: {:?}", result.err()); + let instance = result.unwrap(); + let save_ctx = SaveContext::default(); + let json_output = instance.to_json(&save_ctx); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); +} diff --git a/runtime/rust/prompty/tests/model/events/session_end_payload_test.rs b/runtime/rust/prompty/tests/model/events/session_end_payload_test.rs new file mode 100644 index 00000000..5568ff32 --- /dev/null +++ b/runtime/rust/prompty/tests/model/events/session_end_payload_test.rs @@ -0,0 +1,69 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use prompty::model::SessionEndPayload; +use prompty::model::SessionEndStatus; +use prompty::model::context::{LoadContext, SaveContext}; + +#[test] +fn test_session_end_payload_load_json() { + let json = r####" +{ + "sessionId": "sess_abc123", + "status": "success", + "reason": "complete", + "durationMs": 12500 +} +"####; + let ctx = LoadContext::default(); + let result = SessionEndPayload::from_json(json, &ctx); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + let instance = result.unwrap(); + assert!(instance.session_id.is_some(), "Expected session_id to be Some"); + assert_eq!(instance.session_id.as_ref().unwrap(), &"sess_abc123"); + assert!(instance.status.is_some(), "Expected status to be Some"); + assert_eq!(instance.status.as_ref().unwrap(), &SessionEndStatus::Success); + assert!(instance.reason.is_some(), "Expected reason to be Some"); + assert_eq!(instance.reason.as_ref().unwrap(), &"complete"); + assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); + assert_eq!(instance.duration_ms.as_ref().unwrap(), &12500.0); +} + +#[test] +fn test_session_end_payload_load_yaml() { + let yaml = r####" +sessionId: sess_abc123 +status: success +reason: complete +durationMs: 12500 + +"####; + let ctx = LoadContext::default(); + let result = SessionEndPayload::from_yaml(yaml, &ctx); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + let instance = result.unwrap(); + assert!(instance.session_id.is_some(), "Expected session_id to be Some"); + assert!(instance.status.is_some(), "Expected status to be Some"); + assert!(instance.reason.is_some(), "Expected reason to be Some"); + assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); +} + +#[test] +fn test_session_end_payload_roundtrip() { + let json = r####" +{ + "sessionId": "sess_abc123", + "status": "success", + "reason": "complete", + "durationMs": 12500 +} +"####; + let load_ctx = LoadContext::default(); + let result = SessionEndPayload::from_json(json, &load_ctx); + assert!(result.is_ok(), "Failed to load: {:?}", result.err()); + let instance = result.unwrap(); + let save_ctx = SaveContext::default(); + let json_output = instance.to_json(&save_ctx); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); +} diff --git a/runtime/rust/prompty/tests/model/events/session_event_test.rs b/runtime/rust/prompty/tests/model/events/session_event_test.rs new file mode 100644 index 00000000..20310ae3 --- /dev/null +++ b/runtime/rust/prompty/tests/model/events/session_event_test.rs @@ -0,0 +1,79 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use prompty::model::SessionEvent; +use prompty::model::SessionEventType; +use prompty::model::context::{LoadContext, SaveContext}; + +#[test] +fn test_session_event_load_json() { + let json = r####" +{ + "id": "evt_abc123", + "timestamp": "2026-06-09T20:00:00Z", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "parentId": "evt_parent", + "spanId": "span_hook_001" +} +"####; + let ctx = LoadContext::default(); + let result = SessionEvent::from_json(json, &ctx); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + let instance = result.unwrap(); + assert_eq!(instance.id, "evt_abc123"); + assert_eq!(instance.timestamp, "2026-06-09T20:00:00Z"); + assert!(instance.session_id.is_some(), "Expected session_id to be Some"); + assert_eq!(instance.session_id.as_ref().unwrap(), &"sess_abc123"); + assert!(instance.turn_id.is_some(), "Expected turn_id to be Some"); + assert_eq!(instance.turn_id.as_ref().unwrap(), &"turn_001"); + assert!(instance.parent_id.is_some(), "Expected parent_id to be Some"); + assert_eq!(instance.parent_id.as_ref().unwrap(), &"evt_parent"); + assert!(instance.span_id.is_some(), "Expected span_id to be Some"); + assert_eq!(instance.span_id.as_ref().unwrap(), &"span_hook_001"); +} + +#[test] +fn test_session_event_load_yaml() { + let yaml = r####" +id: evt_abc123 +timestamp: "2026-06-09T20:00:00Z" +sessionId: sess_abc123 +turnId: turn_001 +parentId: evt_parent +spanId: span_hook_001 + +"####; + let ctx = LoadContext::default(); + let result = SessionEvent::from_yaml(yaml, &ctx); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + let instance = result.unwrap(); + assert_eq!(instance.id, "evt_abc123"); + assert_eq!(instance.timestamp, "2026-06-09T20:00:00Z"); + assert!(instance.session_id.is_some(), "Expected session_id to be Some"); + assert!(instance.turn_id.is_some(), "Expected turn_id to be Some"); + assert!(instance.parent_id.is_some(), "Expected parent_id to be Some"); + assert!(instance.span_id.is_some(), "Expected span_id to be Some"); +} + +#[test] +fn test_session_event_roundtrip() { + let json = r####" +{ + "id": "evt_abc123", + "timestamp": "2026-06-09T20:00:00Z", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "parentId": "evt_parent", + "spanId": "span_hook_001" +} +"####; + let load_ctx = LoadContext::default(); + let result = SessionEvent::from_json(json, &load_ctx); + assert!(result.is_ok(), "Failed to load: {:?}", result.err()); + let instance = result.unwrap(); + let save_ctx = SaveContext::default(); + let json_output = instance.to_json(&save_ctx); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); +} diff --git a/runtime/rust/prompty/tests/model/events/session_file_ref_test.rs b/runtime/rust/prompty/tests/model/events/session_file_ref_test.rs new file mode 100644 index 00000000..f91f7069 --- /dev/null +++ b/runtime/rust/prompty/tests/model/events/session_file_ref_test.rs @@ -0,0 +1,73 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use prompty::model::SessionFileRef; +use prompty::model::context::{LoadContext, SaveContext}; + +#[test] +fn test_session_file_ref_load_json() { + let json = r####" +{ + "sessionId": "sess_abc123", + "path": "src/index.ts", + "toolName": "view", + "turnIndex": 2, + "firstSeenAt": "2026-06-09T20:00:00Z" +} +"####; + let ctx = LoadContext::default(); + let result = SessionFileRef::from_json(json, &ctx); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + let instance = result.unwrap(); + assert!(instance.session_id.is_some(), "Expected session_id to be Some"); + assert_eq!(instance.session_id.as_ref().unwrap(), &"sess_abc123"); + assert_eq!(instance.path, "src/index.ts"); + assert!(instance.tool_name.is_some(), "Expected tool_name to be Some"); + assert_eq!(instance.tool_name.as_ref().unwrap(), &"view"); + assert!(instance.turn_index.is_some(), "Expected turn_index to be Some"); + assert_eq!(instance.turn_index.as_ref().unwrap(), &2); + assert!(instance.first_seen_at.is_some(), "Expected first_seen_at to be Some"); + assert_eq!(instance.first_seen_at.as_ref().unwrap(), &"2026-06-09T20:00:00Z"); +} + +#[test] +fn test_session_file_ref_load_yaml() { + let yaml = r####" +sessionId: sess_abc123 +path: src/index.ts +toolName: view +turnIndex: 2 +firstSeenAt: "2026-06-09T20:00:00Z" + +"####; + let ctx = LoadContext::default(); + let result = SessionFileRef::from_yaml(yaml, &ctx); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + let instance = result.unwrap(); + assert!(instance.session_id.is_some(), "Expected session_id to be Some"); + assert_eq!(instance.path, "src/index.ts"); + assert!(instance.tool_name.is_some(), "Expected tool_name to be Some"); + assert!(instance.turn_index.is_some(), "Expected turn_index to be Some"); + assert!(instance.first_seen_at.is_some(), "Expected first_seen_at to be Some"); +} + +#[test] +fn test_session_file_ref_roundtrip() { + let json = r####" +{ + "sessionId": "sess_abc123", + "path": "src/index.ts", + "toolName": "view", + "turnIndex": 2, + "firstSeenAt": "2026-06-09T20:00:00Z" +} +"####; + let load_ctx = LoadContext::default(); + let result = SessionFileRef::from_json(json, &load_ctx); + assert!(result.is_ok(), "Failed to load: {:?}", result.err()); + let instance = result.unwrap(); + let save_ctx = SaveContext::default(); + let json_output = instance.to_json(&save_ctx); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); +} diff --git a/runtime/rust/prompty/tests/model/events/session_ref_test.rs b/runtime/rust/prompty/tests/model/events/session_ref_test.rs new file mode 100644 index 00000000..01812cae --- /dev/null +++ b/runtime/rust/prompty/tests/model/events/session_ref_test.rs @@ -0,0 +1,72 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use prompty::model::SessionRef; +use prompty::model::context::{LoadContext, SaveContext}; + +#[test] +fn test_session_ref_load_json() { + let json = r####" +{ + "sessionId": "sess_abc123", + "refType": "issue", + "refValue": "owner/repo#123", + "turnIndex": 2, + "createdAt": "2026-06-09T20:00:00Z" +} +"####; + let ctx = LoadContext::default(); + let result = SessionRef::from_json(json, &ctx); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + let instance = result.unwrap(); + assert!(instance.session_id.is_some(), "Expected session_id to be Some"); + assert_eq!(instance.session_id.as_ref().unwrap(), &"sess_abc123"); + assert_eq!(instance.ref_type, "issue"); + assert_eq!(instance.ref_value, "owner/repo#123"); + assert!(instance.turn_index.is_some(), "Expected turn_index to be Some"); + assert_eq!(instance.turn_index.as_ref().unwrap(), &2); + assert!(instance.created_at.is_some(), "Expected created_at to be Some"); + assert_eq!(instance.created_at.as_ref().unwrap(), &"2026-06-09T20:00:00Z"); +} + +#[test] +fn test_session_ref_load_yaml() { + let yaml = r####" +sessionId: sess_abc123 +refType: issue +refValue: "owner/repo#123" +turnIndex: 2 +createdAt: "2026-06-09T20:00:00Z" + +"####; + let ctx = LoadContext::default(); + let result = SessionRef::from_yaml(yaml, &ctx); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + let instance = result.unwrap(); + assert!(instance.session_id.is_some(), "Expected session_id to be Some"); + assert_eq!(instance.ref_type, "issue"); + assert_eq!(instance.ref_value, "owner/repo#123"); + assert!(instance.turn_index.is_some(), "Expected turn_index to be Some"); + assert!(instance.created_at.is_some(), "Expected created_at to be Some"); +} + +#[test] +fn test_session_ref_roundtrip() { + let json = r####" +{ + "sessionId": "sess_abc123", + "refType": "issue", + "refValue": "owner/repo#123", + "turnIndex": 2, + "createdAt": "2026-06-09T20:00:00Z" +} +"####; + let load_ctx = LoadContext::default(); + let result = SessionRef::from_json(json, &load_ctx); + assert!(result.is_ok(), "Failed to load: {:?}", result.err()); + let instance = result.unwrap(); + let save_ctx = SaveContext::default(); + let json_output = instance.to_json(&save_ctx); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); +} diff --git a/runtime/rust/prompty/tests/model/events/session_start_payload_test.rs b/runtime/rust/prompty/tests/model/events/session_start_payload_test.rs new file mode 100644 index 00000000..18e4ee0e --- /dev/null +++ b/runtime/rust/prompty/tests/model/events/session_start_payload_test.rs @@ -0,0 +1,91 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use prompty::model::SessionStartPayload; +use prompty::model::context::{LoadContext, SaveContext}; + +#[test] +fn test_session_start_payload_load_json() { + let json = r####" +{ + "sessionId": "sess_abc123", + "version": 1, + "producer": "prompty-agent", + "runtime": "typescript", + "promptyVersion": "2.0.0", + "startTime": "2026-06-09T20:00:00Z", + "selectedModel": "gpt-4o-mini", + "reasoningEffort": "medium" +} +"####; + let ctx = LoadContext::default(); + let result = SessionStartPayload::from_json(json, &ctx); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + let instance = result.unwrap(); + assert_eq!(instance.session_id, "sess_abc123"); + assert!(instance.version.is_some(), "Expected version to be Some"); + assert_eq!(instance.version.as_ref().unwrap(), &1); + assert!(instance.producer.is_some(), "Expected producer to be Some"); + assert_eq!(instance.producer.as_ref().unwrap(), &"prompty-agent"); + assert!(instance.runtime.is_some(), "Expected runtime to be Some"); + assert_eq!(instance.runtime.as_ref().unwrap(), &"typescript"); + assert!(instance.prompty_version.is_some(), "Expected prompty_version to be Some"); + assert_eq!(instance.prompty_version.as_ref().unwrap(), &"2.0.0"); + assert!(instance.start_time.is_some(), "Expected start_time to be Some"); + assert_eq!(instance.start_time.as_ref().unwrap(), &"2026-06-09T20:00:00Z"); + assert!(instance.selected_model.is_some(), "Expected selected_model to be Some"); + assert_eq!(instance.selected_model.as_ref().unwrap(), &"gpt-4o-mini"); + assert!(instance.reasoning_effort.is_some(), "Expected reasoning_effort to be Some"); + assert_eq!(instance.reasoning_effort.as_ref().unwrap(), &"medium"); +} + +#[test] +fn test_session_start_payload_load_yaml() { + let yaml = r####" +sessionId: sess_abc123 +version: 1 +producer: prompty-agent +runtime: typescript +promptyVersion: 2.0.0 +startTime: "2026-06-09T20:00:00Z" +selectedModel: gpt-4o-mini +reasoningEffort: medium + +"####; + let ctx = LoadContext::default(); + let result = SessionStartPayload::from_yaml(yaml, &ctx); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + let instance = result.unwrap(); + assert_eq!(instance.session_id, "sess_abc123"); + assert!(instance.version.is_some(), "Expected version to be Some"); + assert!(instance.producer.is_some(), "Expected producer to be Some"); + assert!(instance.runtime.is_some(), "Expected runtime to be Some"); + assert!(instance.prompty_version.is_some(), "Expected prompty_version to be Some"); + assert!(instance.start_time.is_some(), "Expected start_time to be Some"); + assert!(instance.selected_model.is_some(), "Expected selected_model to be Some"); + assert!(instance.reasoning_effort.is_some(), "Expected reasoning_effort to be Some"); +} + +#[test] +fn test_session_start_payload_roundtrip() { + let json = r####" +{ + "sessionId": "sess_abc123", + "version": 1, + "producer": "prompty-agent", + "runtime": "typescript", + "promptyVersion": "2.0.0", + "startTime": "2026-06-09T20:00:00Z", + "selectedModel": "gpt-4o-mini", + "reasoningEffort": "medium" +} +"####; + let load_ctx = LoadContext::default(); + let result = SessionStartPayload::from_json(json, &load_ctx); + assert!(result.is_ok(), "Failed to load: {:?}", result.err()); + let instance = result.unwrap(); + let save_ctx = SaveContext::default(); + let json_output = instance.to_json(&save_ctx); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); +} diff --git a/runtime/rust/prompty/tests/model/events/session_summary_test.rs b/runtime/rust/prompty/tests/model/events/session_summary_test.rs new file mode 100644 index 00000000..681fc56e --- /dev/null +++ b/runtime/rust/prompty/tests/model/events/session_summary_test.rs @@ -0,0 +1,74 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use prompty::model::SessionSummary; +use prompty::model::SessionSummaryStatus; +use prompty::model::context::{LoadContext, SaveContext}; + +#[test] +fn test_session_summary_load_json() { + let json = r####" +{ + "sessionId": "sess_abc123", + "status": "success", + "turns": 5, + "checkpoints": 2, + "durationMs": 12500 +} +"####; + let ctx = LoadContext::default(); + let result = SessionSummary::from_json(json, &ctx); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + let instance = result.unwrap(); + assert_eq!(instance.session_id, "sess_abc123"); + assert!(instance.status.is_some(), "Expected status to be Some"); + assert_eq!(instance.status.as_ref().unwrap(), &SessionSummaryStatus::Success); + assert!(instance.turns.is_some(), "Expected turns to be Some"); + assert_eq!(instance.turns.as_ref().unwrap(), &5); + assert!(instance.checkpoints.is_some(), "Expected checkpoints to be Some"); + assert_eq!(instance.checkpoints.as_ref().unwrap(), &2); + assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); + assert_eq!(instance.duration_ms.as_ref().unwrap(), &12500.0); +} + +#[test] +fn test_session_summary_load_yaml() { + let yaml = r####" +sessionId: sess_abc123 +status: success +turns: 5 +checkpoints: 2 +durationMs: 12500 + +"####; + let ctx = LoadContext::default(); + let result = SessionSummary::from_yaml(yaml, &ctx); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + let instance = result.unwrap(); + assert_eq!(instance.session_id, "sess_abc123"); + assert!(instance.status.is_some(), "Expected status to be Some"); + assert!(instance.turns.is_some(), "Expected turns to be Some"); + assert!(instance.checkpoints.is_some(), "Expected checkpoints to be Some"); + assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); +} + +#[test] +fn test_session_summary_roundtrip() { + let json = r####" +{ + "sessionId": "sess_abc123", + "status": "success", + "turns": 5, + "checkpoints": 2, + "durationMs": 12500 +} +"####; + let load_ctx = LoadContext::default(); + let result = SessionSummary::from_json(json, &load_ctx); + assert!(result.is_ok(), "Failed to load: {:?}", result.err()); + let instance = result.unwrap(); + let save_ctx = SaveContext::default(); + let json_output = instance.to_json(&save_ctx); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); +} diff --git a/runtime/rust/prompty/tests/model/events/session_trace_test.rs b/runtime/rust/prompty/tests/model/events/session_trace_test.rs new file mode 100644 index 00000000..9afd8886 --- /dev/null +++ b/runtime/rust/prompty/tests/model/events/session_trace_test.rs @@ -0,0 +1,67 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use prompty::model::SessionTrace; +use prompty::model::context::{LoadContext, SaveContext}; + +#[test] +fn test_session_trace_load_json() { + let json = r####" +{ + "version": "1", + "runtime": "typescript", + "promptyVersion": "2.0.0", + "sessionId": "sess_abc123" +} +"####; + let ctx = LoadContext::default(); + let result = SessionTrace::from_json(json, &ctx); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + let instance = result.unwrap(); + assert_eq!(instance.version, "1"); + assert!(instance.runtime.is_some(), "Expected runtime to be Some"); + assert_eq!(instance.runtime.as_ref().unwrap(), &"typescript"); + assert!(instance.prompty_version.is_some(), "Expected prompty_version to be Some"); + assert_eq!(instance.prompty_version.as_ref().unwrap(), &"2.0.0"); + assert!(instance.session_id.is_some(), "Expected session_id to be Some"); + assert_eq!(instance.session_id.as_ref().unwrap(), &"sess_abc123"); +} + +#[test] +fn test_session_trace_load_yaml() { + let yaml = r####" +version: "1" +runtime: typescript +promptyVersion: 2.0.0 +sessionId: sess_abc123 + +"####; + let ctx = LoadContext::default(); + let result = SessionTrace::from_yaml(yaml, &ctx); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + let instance = result.unwrap(); + assert_eq!(instance.version, "1"); + assert!(instance.runtime.is_some(), "Expected runtime to be Some"); + assert!(instance.prompty_version.is_some(), "Expected prompty_version to be Some"); + assert!(instance.session_id.is_some(), "Expected session_id to be Some"); +} + +#[test] +fn test_session_trace_roundtrip() { + let json = r####" +{ + "version": "1", + "runtime": "typescript", + "promptyVersion": "2.0.0", + "sessionId": "sess_abc123" +} +"####; + let load_ctx = LoadContext::default(); + let result = SessionTrace::from_json(json, &load_ctx); + assert!(result.is_ok(), "Failed to load: {:?}", result.err()); + let instance = result.unwrap(); + let save_ctx = SaveContext::default(); + let json_output = instance.to_json(&save_ctx); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); +} diff --git a/runtime/rust/prompty/tests/model/events/session_warning_payload_test.rs b/runtime/rust/prompty/tests/model/events/session_warning_payload_test.rs new file mode 100644 index 00000000..56b2a90a --- /dev/null +++ b/runtime/rust/prompty/tests/model/events/session_warning_payload_test.rs @@ -0,0 +1,54 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use prompty::model::SessionWarningPayload; +use prompty::model::context::{LoadContext, SaveContext}; + +#[test] +fn test_session_warning_payload_load_json() { + let json = r####" +{ + "warningType": "remote", + "message": "Remote session disabled" +} +"####; + let ctx = LoadContext::default(); + let result = SessionWarningPayload::from_json(json, &ctx); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + let instance = result.unwrap(); + assert_eq!(instance.warning_type, "remote"); + assert_eq!(instance.message, "Remote session disabled"); +} + +#[test] +fn test_session_warning_payload_load_yaml() { + let yaml = r####" +warningType: remote +message: Remote session disabled + +"####; + let ctx = LoadContext::default(); + let result = SessionWarningPayload::from_yaml(yaml, &ctx); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + let instance = result.unwrap(); + assert_eq!(instance.warning_type, "remote"); + assert_eq!(instance.message, "Remote session disabled"); +} + +#[test] +fn test_session_warning_payload_roundtrip() { + let json = r####" +{ + "warningType": "remote", + "message": "Remote session disabled" +} +"####; + let load_ctx = LoadContext::default(); + let result = SessionWarningPayload::from_json(json, &load_ctx); + assert!(result.is_ok(), "Failed to load: {:?}", result.err()); + let instance = result.unwrap(); + let save_ctx = SaveContext::default(); + let json_output = instance.to_json(&save_ctx); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); +} diff --git a/runtime/rust/prompty/tests/model/events/tool_execution_complete_payload_test.rs b/runtime/rust/prompty/tests/model/events/tool_execution_complete_payload_test.rs new file mode 100644 index 00000000..57a58fc7 --- /dev/null +++ b/runtime/rust/prompty/tests/model/events/tool_execution_complete_payload_test.rs @@ -0,0 +1,84 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use prompty::model::ToolExecutionCompletePayload; +use prompty::model::context::{LoadContext, SaveContext}; + +#[test] +fn test_tool_execution_complete_payload_load_json() { + let json = r####" +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "success": true, + "exitCode": 0, + "durationMs": 250, + "errorKind": "timeout" +} +"####; + let ctx = LoadContext::default(); + let result = ToolExecutionCompletePayload::from_json(json, &ctx); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + let instance = result.unwrap(); + assert!(instance.request_id.is_some(), "Expected request_id to be Some"); + assert_eq!(instance.request_id.as_ref().unwrap(), &"exec_abc123"); + assert!(instance.tool_call_id.is_some(), "Expected tool_call_id to be Some"); + assert_eq!(instance.tool_call_id.as_ref().unwrap(), &"call_abc123"); + assert_eq!(instance.tool_name, "powershell"); + assert_eq!(instance.success, true); + assert!(instance.exit_code.is_some(), "Expected exit_code to be Some"); + assert_eq!(instance.exit_code.as_ref().unwrap(), &0); + assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); + assert_eq!(instance.duration_ms.as_ref().unwrap(), &250.0); + assert!(instance.error_kind.is_some(), "Expected error_kind to be Some"); + assert_eq!(instance.error_kind.as_ref().unwrap(), &"timeout"); +} + +#[test] +fn test_tool_execution_complete_payload_load_yaml() { + let yaml = r####" +requestId: exec_abc123 +toolCallId: call_abc123 +toolName: powershell +success: true +exitCode: 0 +durationMs: 250 +errorKind: timeout + +"####; + let ctx = LoadContext::default(); + let result = ToolExecutionCompletePayload::from_yaml(yaml, &ctx); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + let instance = result.unwrap(); + assert!(instance.request_id.is_some(), "Expected request_id to be Some"); + assert!(instance.tool_call_id.is_some(), "Expected tool_call_id to be Some"); + assert_eq!(instance.tool_name, "powershell"); + assert_eq!(instance.success, true); + assert!(instance.exit_code.is_some(), "Expected exit_code to be Some"); + assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); + assert!(instance.error_kind.is_some(), "Expected error_kind to be Some"); +} + +#[test] +fn test_tool_execution_complete_payload_roundtrip() { + let json = r####" +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "success": true, + "exitCode": 0, + "durationMs": 250, + "errorKind": "timeout" +} +"####; + let load_ctx = LoadContext::default(); + let result = ToolExecutionCompletePayload::from_json(json, &load_ctx); + assert!(result.is_ok(), "Failed to load: {:?}", result.err()); + let instance = result.unwrap(); + let save_ctx = SaveContext::default(); + let json_output = instance.to_json(&save_ctx); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); +} diff --git a/runtime/rust/prompty/tests/model/events/tool_execution_start_payload_test.rs b/runtime/rust/prompty/tests/model/events/tool_execution_start_payload_test.rs new file mode 100644 index 00000000..a81ac534 --- /dev/null +++ b/runtime/rust/prompty/tests/model/events/tool_execution_start_payload_test.rs @@ -0,0 +1,67 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use prompty::model::ToolExecutionStartPayload; +use prompty::model::context::{LoadContext, SaveContext}; + +#[test] +fn test_tool_execution_start_payload_load_json() { + let json = r####" +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "workingDirectory": "/workspace/project" +} +"####; + let ctx = LoadContext::default(); + let result = ToolExecutionStartPayload::from_json(json, &ctx); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + let instance = result.unwrap(); + assert!(instance.request_id.is_some(), "Expected request_id to be Some"); + assert_eq!(instance.request_id.as_ref().unwrap(), &"exec_abc123"); + assert!(instance.tool_call_id.is_some(), "Expected tool_call_id to be Some"); + assert_eq!(instance.tool_call_id.as_ref().unwrap(), &"call_abc123"); + assert_eq!(instance.tool_name, "powershell"); + assert!(instance.working_directory.is_some(), "Expected working_directory to be Some"); + assert_eq!(instance.working_directory.as_ref().unwrap(), &"/workspace/project"); +} + +#[test] +fn test_tool_execution_start_payload_load_yaml() { + let yaml = r####" +requestId: exec_abc123 +toolCallId: call_abc123 +toolName: powershell +workingDirectory: /workspace/project + +"####; + let ctx = LoadContext::default(); + let result = ToolExecutionStartPayload::from_yaml(yaml, &ctx); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + let instance = result.unwrap(); + assert!(instance.request_id.is_some(), "Expected request_id to be Some"); + assert!(instance.tool_call_id.is_some(), "Expected tool_call_id to be Some"); + assert_eq!(instance.tool_name, "powershell"); + assert!(instance.working_directory.is_some(), "Expected working_directory to be Some"); +} + +#[test] +fn test_tool_execution_start_payload_roundtrip() { + let json = r####" +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "workingDirectory": "/workspace/project" +} +"####; + let load_ctx = LoadContext::default(); + let result = ToolExecutionStartPayload::from_json(json, &load_ctx); + assert!(result.is_ok(), "Failed to load: {:?}", result.err()); + let instance = result.unwrap(); + let save_ctx = SaveContext::default(); + let json_output = instance.to_json(&save_ctx); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); +} diff --git a/runtime/rust/prompty/tests/model/events/trajectory_event_test.rs b/runtime/rust/prompty/tests/model/events/trajectory_event_test.rs new file mode 100644 index 00000000..1b481f34 --- /dev/null +++ b/runtime/rust/prompty/tests/model/events/trajectory_event_test.rs @@ -0,0 +1,85 @@ +// Code generated by Prompty emitter; DO NOT EDIT. + +#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] + +use prompty::model::TrajectoryEvent; +use prompty::model::context::{LoadContext, SaveContext}; + +#[test] +fn test_trajectory_event_load_json() { + let json = r####" +{ + "id": "traj_abc123", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "toolCallId": "call_abc123", + "turnIndex": 4, + "eventType": "command", + "createdAt": "2026-06-09T20:00:00Z" +} +"####; + let ctx = LoadContext::default(); + let result = TrajectoryEvent::from_json(json, &ctx); + assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + let instance = result.unwrap(); + assert!(instance.id.is_some(), "Expected id to be Some"); + assert_eq!(instance.id.as_ref().unwrap(), &"traj_abc123"); + assert!(instance.session_id.is_some(), "Expected session_id to be Some"); + assert_eq!(instance.session_id.as_ref().unwrap(), &"sess_abc123"); + assert!(instance.turn_id.is_some(), "Expected turn_id to be Some"); + assert_eq!(instance.turn_id.as_ref().unwrap(), &"turn_001"); + assert!(instance.tool_call_id.is_some(), "Expected tool_call_id to be Some"); + assert_eq!(instance.tool_call_id.as_ref().unwrap(), &"call_abc123"); + assert!(instance.turn_index.is_some(), "Expected turn_index to be Some"); + assert_eq!(instance.turn_index.as_ref().unwrap(), &4); + assert_eq!(instance.event_type, "command"); + assert!(instance.created_at.is_some(), "Expected created_at to be Some"); + assert_eq!(instance.created_at.as_ref().unwrap(), &"2026-06-09T20:00:00Z"); +} + +#[test] +fn test_trajectory_event_load_yaml() { + let yaml = r####" +id: traj_abc123 +sessionId: sess_abc123 +turnId: turn_001 +toolCallId: call_abc123 +turnIndex: 4 +eventType: command +createdAt: "2026-06-09T20:00:00Z" + +"####; + let ctx = LoadContext::default(); + let result = TrajectoryEvent::from_yaml(yaml, &ctx); + assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + let instance = result.unwrap(); + assert!(instance.id.is_some(), "Expected id to be Some"); + assert!(instance.session_id.is_some(), "Expected session_id to be Some"); + assert!(instance.turn_id.is_some(), "Expected turn_id to be Some"); + assert!(instance.tool_call_id.is_some(), "Expected tool_call_id to be Some"); + assert!(instance.turn_index.is_some(), "Expected turn_index to be Some"); + assert_eq!(instance.event_type, "command"); + assert!(instance.created_at.is_some(), "Expected created_at to be Some"); +} + +#[test] +fn test_trajectory_event_roundtrip() { + let json = r####" +{ + "id": "traj_abc123", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "toolCallId": "call_abc123", + "turnIndex": 4, + "eventType": "command", + "createdAt": "2026-06-09T20:00:00Z" +} +"####; + let load_ctx = LoadContext::default(); + let result = TrajectoryEvent::from_json(json, &load_ctx); + assert!(result.is_ok(), "Failed to load: {:?}", result.err()); + let instance = result.unwrap(); + let save_ctx = SaveContext::default(); + let json_output = instance.to_json(&save_ctx); + assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); +} diff --git a/runtime/typescript/packages/core/src/model/events/checkpoint.ts b/runtime/typescript/packages/core/src/model/events/checkpoint.ts new file mode 100644 index 00000000..11ba6d45 --- /dev/null +++ b/runtime/typescript/packages/core/src/model/events/checkpoint.ts @@ -0,0 +1,188 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { LoadContext, SaveContext } from "../context"; +import { RedactionMetadata } from "./redaction-metadata"; + +export class Checkpoint { + static readonly shorthandProperty: string | undefined = undefined; + + id?: string | undefined; + sessionId?: string | undefined; + turnId?: string | undefined; + checkpointNumber?: number | undefined; + title: string = ""; + overview?: string | undefined; + state?: Record | undefined; + summary?: string | undefined; + metadata?: Record | undefined; + createdAt?: string | undefined; + redaction?: RedactionMetadata | undefined; + + constructor(init?: Partial) { + if (init?.id !== undefined) { + this.id = init.id; + } + if (init?.sessionId !== undefined) { + this.sessionId = init.sessionId; + } + if (init?.turnId !== undefined) { + this.turnId = init.turnId; + } + if (init?.checkpointNumber !== undefined) { + this.checkpointNumber = init.checkpointNumber; + } + this.title = init?.title ?? ""; + if (init?.overview !== undefined) { + this.overview = init.overview; + } + if (init?.state !== undefined) { + this.state = init.state; + } + if (init?.summary !== undefined) { + this.summary = init.summary; + } + if (init?.metadata !== undefined) { + this.metadata = init.metadata; + } + if (init?.createdAt !== undefined) { + this.createdAt = init.createdAt; + } + if (init?.redaction !== undefined) { + this.redaction = init.redaction; + } + } + + //#region Load Methods + + static load( + data: Record, + context?: LoadContext, + ): Checkpoint { + if (context) { + data = context.processInput(data) as Record; + } + + const instance = new Checkpoint(); + + if (data["id"] !== undefined && data["id"] !== null) { + instance.id = String(data["id"]); + } + if (data["sessionId"] !== undefined && data["sessionId"] !== null) { + instance.sessionId = String(data["sessionId"]); + } + if (data["turnId"] !== undefined && data["turnId"] !== null) { + instance.turnId = String(data["turnId"]); + } + if ( + data["checkpointNumber"] !== undefined && + data["checkpointNumber"] !== null + ) { + instance.checkpointNumber = Number(data["checkpointNumber"]); + } + if (data["title"] !== undefined && data["title"] !== null) { + instance.title = String(data["title"]); + } + if (data["overview"] !== undefined && data["overview"] !== null) { + instance.overview = String(data["overview"]); + } + if (data["state"] !== undefined && data["state"] !== null) { + instance.state = data["state"] as Record; + } + if (data["summary"] !== undefined && data["summary"] !== null) { + instance.summary = String(data["summary"]); + } + if (data["metadata"] !== undefined && data["metadata"] !== null) { + instance.metadata = data["metadata"] as Record; + } + if (data["createdAt"] !== undefined && data["createdAt"] !== null) { + instance.createdAt = String(data["createdAt"]); + } + if (data["redaction"] !== undefined && data["redaction"] !== null) { + instance.redaction = RedactionMetadata.load( + data["redaction"] as Record, + context, + ); + } + + if (context) { + return context.processOutput(instance) as Checkpoint; + } + return instance; + } + + //#endregion + + //#region Save Methods + + save(context?: SaveContext): Record { + let obj: this = this; + if (context) { + obj = context.processObject(obj) as this; + } + + const result: Record = {}; + + if (obj.id !== undefined && obj.id !== null) { + result["id"] = obj.id; + } + if (obj.sessionId !== undefined && obj.sessionId !== null) { + result["sessionId"] = obj.sessionId; + } + if (obj.turnId !== undefined && obj.turnId !== null) { + result["turnId"] = obj.turnId; + } + if (obj.checkpointNumber !== undefined && obj.checkpointNumber !== null) { + result["checkpointNumber"] = obj.checkpointNumber; + } + if (obj.title !== undefined && obj.title !== null) { + result["title"] = obj.title; + } + if (obj.overview !== undefined && obj.overview !== null) { + result["overview"] = obj.overview; + } + if (obj.state !== undefined && obj.state !== null) { + result["state"] = obj.state; + } + if (obj.summary !== undefined && obj.summary !== null) { + result["summary"] = obj.summary; + } + if (obj.metadata !== undefined && obj.metadata !== null) { + result["metadata"] = obj.metadata; + } + if (obj.createdAt !== undefined && obj.createdAt !== null) { + result["createdAt"] = obj.createdAt; + } + if (obj.redaction !== undefined && obj.redaction !== null) { + result["redaction"] = obj.redaction.save(context); + } + + if (context) { + return context.processDict(result); + } + return result; + } + + toYaml(context?: SaveContext): string { + context = context ?? new SaveContext(); + return context.toYaml(this.save(context)); + } + + toJson(context?: SaveContext, indent: number = 2): string { + context = context ?? new SaveContext(); + return context.toJson(this.save(context), indent); + } + + static fromJson(json: string, context?: LoadContext): Checkpoint { + const data = JSON.parse(json); + return Checkpoint.load(data as Record, context); + } + + static fromYaml(yaml: string, context?: LoadContext): Checkpoint { + const { parse } = require("yaml"); + const data = parse(yaml); + return Checkpoint.load(data as Record, context); + } + + //#endregion +} diff --git a/runtime/typescript/packages/core/src/model/events/harness-context.ts b/runtime/typescript/packages/core/src/model/events/harness-context.ts new file mode 100644 index 00000000..5592f324 --- /dev/null +++ b/runtime/typescript/packages/core/src/model/events/harness-context.ts @@ -0,0 +1,103 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { LoadContext, SaveContext } from "../context"; + +export class HarnessContext { + static readonly shorthandProperty: string | undefined = undefined; + + cwd?: string | undefined; + gitRoot?: string | undefined; + metadata?: Record | undefined; + + constructor(init?: Partial) { + if (init?.cwd !== undefined) { + this.cwd = init.cwd; + } + if (init?.gitRoot !== undefined) { + this.gitRoot = init.gitRoot; + } + if (init?.metadata !== undefined) { + this.metadata = init.metadata; + } + } + + //#region Load Methods + + static load( + data: Record, + context?: LoadContext, + ): HarnessContext { + if (context) { + data = context.processInput(data) as Record; + } + + const instance = new HarnessContext(); + + if (data["cwd"] !== undefined && data["cwd"] !== null) { + instance.cwd = String(data["cwd"]); + } + if (data["gitRoot"] !== undefined && data["gitRoot"] !== null) { + instance.gitRoot = String(data["gitRoot"]); + } + if (data["metadata"] !== undefined && data["metadata"] !== null) { + instance.metadata = data["metadata"] as Record; + } + + if (context) { + return context.processOutput(instance) as HarnessContext; + } + return instance; + } + + //#endregion + + //#region Save Methods + + save(context?: SaveContext): Record { + let obj: this = this; + if (context) { + obj = context.processObject(obj) as this; + } + + const result: Record = {}; + + if (obj.cwd !== undefined && obj.cwd !== null) { + result["cwd"] = obj.cwd; + } + if (obj.gitRoot !== undefined && obj.gitRoot !== null) { + result["gitRoot"] = obj.gitRoot; + } + if (obj.metadata !== undefined && obj.metadata !== null) { + result["metadata"] = obj.metadata; + } + + if (context) { + return context.processDict(result); + } + return result; + } + + toYaml(context?: SaveContext): string { + context = context ?? new SaveContext(); + return context.toYaml(this.save(context)); + } + + toJson(context?: SaveContext, indent: number = 2): string { + context = context ?? new SaveContext(); + return context.toJson(this.save(context), indent); + } + + static fromJson(json: string, context?: LoadContext): HarnessContext { + const data = JSON.parse(json); + return HarnessContext.load(data as Record, context); + } + + static fromYaml(yaml: string, context?: LoadContext): HarnessContext { + const { parse } = require("yaml"); + const data = parse(yaml); + return HarnessContext.load(data as Record, context); + } + + //#endregion +} diff --git a/runtime/typescript/packages/core/src/model/events/hook-end-payload.ts b/runtime/typescript/packages/core/src/model/events/hook-end-payload.ts new file mode 100644 index 00000000..796eb93c --- /dev/null +++ b/runtime/typescript/packages/core/src/model/events/hook-end-payload.ts @@ -0,0 +1,144 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { LoadContext, SaveContext } from "../context"; +import { RedactionMetadata } from "./redaction-metadata"; + +export class HookEndPayload { + static readonly shorthandProperty: string | undefined = undefined; + + hookInvocationId: string = ""; + hookType: string = ""; + success: boolean = false; + output?: Record | undefined; + durationMs?: number | undefined; + error?: string | undefined; + redaction?: RedactionMetadata | undefined; + + constructor(init?: Partial) { + this.hookInvocationId = init?.hookInvocationId ?? ""; + this.hookType = init?.hookType ?? ""; + this.success = init?.success ?? false; + if (init?.output !== undefined) { + this.output = init.output; + } + if (init?.durationMs !== undefined) { + this.durationMs = init.durationMs; + } + if (init?.error !== undefined) { + this.error = init.error; + } + if (init?.redaction !== undefined) { + this.redaction = init.redaction; + } + } + + //#region Load Methods + + static load( + data: Record, + context?: LoadContext, + ): HookEndPayload { + if (context) { + data = context.processInput(data) as Record; + } + + const instance = new HookEndPayload(); + + if ( + data["hookInvocationId"] !== undefined && + data["hookInvocationId"] !== null + ) { + instance.hookInvocationId = String(data["hookInvocationId"]); + } + if (data["hookType"] !== undefined && data["hookType"] !== null) { + instance.hookType = String(data["hookType"]); + } + if (data["success"] !== undefined && data["success"] !== null) { + instance.success = Boolean(data["success"]); + } + if (data["output"] !== undefined && data["output"] !== null) { + instance.output = data["output"] as Record; + } + if (data["durationMs"] !== undefined && data["durationMs"] !== null) { + instance.durationMs = Number(data["durationMs"]); + } + if (data["error"] !== undefined && data["error"] !== null) { + instance.error = String(data["error"]); + } + if (data["redaction"] !== undefined && data["redaction"] !== null) { + instance.redaction = RedactionMetadata.load( + data["redaction"] as Record, + context, + ); + } + + if (context) { + return context.processOutput(instance) as HookEndPayload; + } + return instance; + } + + //#endregion + + //#region Save Methods + + save(context?: SaveContext): Record { + let obj: this = this; + if (context) { + obj = context.processObject(obj) as this; + } + + const result: Record = {}; + + if (obj.hookInvocationId !== undefined && obj.hookInvocationId !== null) { + result["hookInvocationId"] = obj.hookInvocationId; + } + if (obj.hookType !== undefined && obj.hookType !== null) { + result["hookType"] = obj.hookType; + } + if (obj.success !== undefined && obj.success !== null) { + result["success"] = obj.success; + } + if (obj.output !== undefined && obj.output !== null) { + result["output"] = obj.output; + } + if (obj.durationMs !== undefined && obj.durationMs !== null) { + result["durationMs"] = obj.durationMs; + } + if (obj.error !== undefined && obj.error !== null) { + result["error"] = obj.error; + } + if (obj.redaction !== undefined && obj.redaction !== null) { + result["redaction"] = obj.redaction.save(context); + } + + if (context) { + return context.processDict(result); + } + return result; + } + + toYaml(context?: SaveContext): string { + context = context ?? new SaveContext(); + return context.toYaml(this.save(context)); + } + + toJson(context?: SaveContext, indent: number = 2): string { + context = context ?? new SaveContext(); + return context.toJson(this.save(context), indent); + } + + static fromJson(json: string, context?: LoadContext): HookEndPayload { + const data = JSON.parse(json); + return HookEndPayload.load(data as Record, context); + } + + static fromYaml(yaml: string, context?: LoadContext): HookEndPayload { + const { parse } = require("yaml"); + const data = parse(yaml); + return HookEndPayload.load(data as Record, context); + } + + //#endregion +} diff --git a/runtime/typescript/packages/core/src/model/events/hook-start-payload.ts b/runtime/typescript/packages/core/src/model/events/hook-start-payload.ts new file mode 100644 index 00000000..a76195f3 --- /dev/null +++ b/runtime/typescript/packages/core/src/model/events/hook-start-payload.ts @@ -0,0 +1,116 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { LoadContext, SaveContext } from "../context"; +import { RedactionMetadata } from "./redaction-metadata"; + +export class HookStartPayload { + static readonly shorthandProperty: string | undefined = undefined; + + hookInvocationId: string = ""; + hookType: string = ""; + input?: Record | undefined; + redaction?: RedactionMetadata | undefined; + + constructor(init?: Partial) { + this.hookInvocationId = init?.hookInvocationId ?? ""; + this.hookType = init?.hookType ?? ""; + if (init?.input !== undefined) { + this.input = init.input; + } + if (init?.redaction !== undefined) { + this.redaction = init.redaction; + } + } + + //#region Load Methods + + static load( + data: Record, + context?: LoadContext, + ): HookStartPayload { + if (context) { + data = context.processInput(data) as Record; + } + + const instance = new HookStartPayload(); + + if ( + data["hookInvocationId"] !== undefined && + data["hookInvocationId"] !== null + ) { + instance.hookInvocationId = String(data["hookInvocationId"]); + } + if (data["hookType"] !== undefined && data["hookType"] !== null) { + instance.hookType = String(data["hookType"]); + } + if (data["input"] !== undefined && data["input"] !== null) { + instance.input = data["input"] as Record; + } + if (data["redaction"] !== undefined && data["redaction"] !== null) { + instance.redaction = RedactionMetadata.load( + data["redaction"] as Record, + context, + ); + } + + if (context) { + return context.processOutput(instance) as HookStartPayload; + } + return instance; + } + + //#endregion + + //#region Save Methods + + save(context?: SaveContext): Record { + let obj: this = this; + if (context) { + obj = context.processObject(obj) as this; + } + + const result: Record = {}; + + if (obj.hookInvocationId !== undefined && obj.hookInvocationId !== null) { + result["hookInvocationId"] = obj.hookInvocationId; + } + if (obj.hookType !== undefined && obj.hookType !== null) { + result["hookType"] = obj.hookType; + } + if (obj.input !== undefined && obj.input !== null) { + result["input"] = obj.input; + } + if (obj.redaction !== undefined && obj.redaction !== null) { + result["redaction"] = obj.redaction.save(context); + } + + if (context) { + return context.processDict(result); + } + return result; + } + + toYaml(context?: SaveContext): string { + context = context ?? new SaveContext(); + return context.toYaml(this.save(context)); + } + + toJson(context?: SaveContext, indent: number = 2): string { + context = context ?? new SaveContext(); + return context.toJson(this.save(context), indent); + } + + static fromJson(json: string, context?: LoadContext): HookStartPayload { + const data = JSON.parse(json); + return HookStartPayload.load(data as Record, context); + } + + static fromYaml(yaml: string, context?: LoadContext): HookStartPayload { + const { parse } = require("yaml"); + const data = parse(yaml); + return HookStartPayload.load(data as Record, context); + } + + //#endregion +} diff --git a/runtime/typescript/packages/core/src/model/events/host-tool-request.ts b/runtime/typescript/packages/core/src/model/events/host-tool-request.ts new file mode 100644 index 00000000..734fc5bc --- /dev/null +++ b/runtime/typescript/packages/core/src/model/events/host-tool-request.ts @@ -0,0 +1,124 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { LoadContext, SaveContext } from "../context"; + +export class HostToolRequest { + static readonly shorthandProperty: string | undefined = undefined; + + requestId?: string | undefined; + toolCallId?: string | undefined; + toolName: string = ""; + arguments?: Record | undefined; + workingDirectory?: string | undefined; + + constructor(init?: Partial) { + if (init?.requestId !== undefined) { + this.requestId = init.requestId; + } + if (init?.toolCallId !== undefined) { + this.toolCallId = init.toolCallId; + } + this.toolName = init?.toolName ?? ""; + if (init?.arguments !== undefined) { + this.arguments = init.arguments; + } + if (init?.workingDirectory !== undefined) { + this.workingDirectory = init.workingDirectory; + } + } + + //#region Load Methods + + static load( + data: Record, + context?: LoadContext, + ): HostToolRequest { + if (context) { + data = context.processInput(data) as Record; + } + + const instance = new HostToolRequest(); + + if (data["requestId"] !== undefined && data["requestId"] !== null) { + instance.requestId = String(data["requestId"]); + } + if (data["toolCallId"] !== undefined && data["toolCallId"] !== null) { + instance.toolCallId = String(data["toolCallId"]); + } + if (data["toolName"] !== undefined && data["toolName"] !== null) { + instance.toolName = String(data["toolName"]); + } + if (data["arguments"] !== undefined && data["arguments"] !== null) { + instance.arguments = data["arguments"] as Record; + } + if ( + data["workingDirectory"] !== undefined && + data["workingDirectory"] !== null + ) { + instance.workingDirectory = String(data["workingDirectory"]); + } + + if (context) { + return context.processOutput(instance) as HostToolRequest; + } + return instance; + } + + //#endregion + + //#region Save Methods + + save(context?: SaveContext): Record { + let obj: this = this; + if (context) { + obj = context.processObject(obj) as this; + } + + const result: Record = {}; + + if (obj.requestId !== undefined && obj.requestId !== null) { + result["requestId"] = obj.requestId; + } + if (obj.toolCallId !== undefined && obj.toolCallId !== null) { + result["toolCallId"] = obj.toolCallId; + } + if (obj.toolName !== undefined && obj.toolName !== null) { + result["toolName"] = obj.toolName; + } + if (obj.arguments !== undefined && obj.arguments !== null) { + result["arguments"] = obj.arguments; + } + if (obj.workingDirectory !== undefined && obj.workingDirectory !== null) { + result["workingDirectory"] = obj.workingDirectory; + } + + if (context) { + return context.processDict(result); + } + return result; + } + + toYaml(context?: SaveContext): string { + context = context ?? new SaveContext(); + return context.toYaml(this.save(context)); + } + + toJson(context?: SaveContext, indent: number = 2): string { + context = context ?? new SaveContext(); + return context.toJson(this.save(context), indent); + } + + static fromJson(json: string, context?: LoadContext): HostToolRequest { + const data = JSON.parse(json); + return HostToolRequest.load(data as Record, context); + } + + static fromYaml(yaml: string, context?: LoadContext): HostToolRequest { + const { parse } = require("yaml"); + const data = parse(yaml); + return HostToolRequest.load(data as Record, context); + } + + //#endregion +} diff --git a/runtime/typescript/packages/core/src/model/events/host-tool-result.ts b/runtime/typescript/packages/core/src/model/events/host-tool-result.ts new file mode 100644 index 00000000..4265b17b --- /dev/null +++ b/runtime/typescript/packages/core/src/model/events/host-tool-result.ts @@ -0,0 +1,159 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { LoadContext, SaveContext } from "../context"; + +export class HostToolResult { + static readonly shorthandProperty: string | undefined = undefined; + + requestId?: string | undefined; + toolCallId?: string | undefined; + toolName: string = ""; + success: boolean = false; + result?: unknown | undefined; + exitCode?: number | undefined; + durationMs?: number | undefined; + errorKind?: string | undefined; + telemetry?: Record | undefined; + + constructor(init?: Partial) { + if (init?.requestId !== undefined) { + this.requestId = init.requestId; + } + if (init?.toolCallId !== undefined) { + this.toolCallId = init.toolCallId; + } + this.toolName = init?.toolName ?? ""; + this.success = init?.success ?? false; + if (init?.result !== undefined) { + this.result = init.result; + } + if (init?.exitCode !== undefined) { + this.exitCode = init.exitCode; + } + if (init?.durationMs !== undefined) { + this.durationMs = init.durationMs; + } + if (init?.errorKind !== undefined) { + this.errorKind = init.errorKind; + } + if (init?.telemetry !== undefined) { + this.telemetry = init.telemetry; + } + } + + //#region Load Methods + + static load( + data: Record, + context?: LoadContext, + ): HostToolResult { + if (context) { + data = context.processInput(data) as Record; + } + + const instance = new HostToolResult(); + + if (data["requestId"] !== undefined && data["requestId"] !== null) { + instance.requestId = String(data["requestId"]); + } + if (data["toolCallId"] !== undefined && data["toolCallId"] !== null) { + instance.toolCallId = String(data["toolCallId"]); + } + if (data["toolName"] !== undefined && data["toolName"] !== null) { + instance.toolName = String(data["toolName"]); + } + if (data["success"] !== undefined && data["success"] !== null) { + instance.success = Boolean(data["success"]); + } + if (data["result"] !== undefined && data["result"] !== null) { + instance.result = data["result"] as unknown; + } + if (data["exitCode"] !== undefined && data["exitCode"] !== null) { + instance.exitCode = Number(data["exitCode"]); + } + if (data["durationMs"] !== undefined && data["durationMs"] !== null) { + instance.durationMs = Number(data["durationMs"]); + } + if (data["errorKind"] !== undefined && data["errorKind"] !== null) { + instance.errorKind = String(data["errorKind"]); + } + if (data["telemetry"] !== undefined && data["telemetry"] !== null) { + instance.telemetry = data["telemetry"] as Record; + } + + if (context) { + return context.processOutput(instance) as HostToolResult; + } + return instance; + } + + //#endregion + + //#region Save Methods + + save(context?: SaveContext): Record { + let obj: this = this; + if (context) { + obj = context.processObject(obj) as this; + } + + const result: Record = {}; + + if (obj.requestId !== undefined && obj.requestId !== null) { + result["requestId"] = obj.requestId; + } + if (obj.toolCallId !== undefined && obj.toolCallId !== null) { + result["toolCallId"] = obj.toolCallId; + } + if (obj.toolName !== undefined && obj.toolName !== null) { + result["toolName"] = obj.toolName; + } + if (obj.success !== undefined && obj.success !== null) { + result["success"] = obj.success; + } + if (obj.result !== undefined && obj.result !== null) { + result["result"] = obj.result; + } + if (obj.exitCode !== undefined && obj.exitCode !== null) { + result["exitCode"] = obj.exitCode; + } + if (obj.durationMs !== undefined && obj.durationMs !== null) { + result["durationMs"] = obj.durationMs; + } + if (obj.errorKind !== undefined && obj.errorKind !== null) { + result["errorKind"] = obj.errorKind; + } + if (obj.telemetry !== undefined && obj.telemetry !== null) { + result["telemetry"] = obj.telemetry; + } + + if (context) { + return context.processDict(result); + } + return result; + } + + toYaml(context?: SaveContext): string { + context = context ?? new SaveContext(); + return context.toYaml(this.save(context)); + } + + toJson(context?: SaveContext, indent: number = 2): string { + context = context ?? new SaveContext(); + return context.toJson(this.save(context), indent); + } + + static fromJson(json: string, context?: LoadContext): HostToolResult { + const data = JSON.parse(json); + return HostToolResult.load(data as Record, context); + } + + static fromYaml(yaml: string, context?: LoadContext): HostToolResult { + const { parse } = require("yaml"); + const data = parse(yaml); + return HostToolResult.load(data as Record, context); + } + + //#endregion +} diff --git a/runtime/typescript/packages/core/src/model/events/index.ts b/runtime/typescript/packages/core/src/model/events/index.ts index 34d8f612..76bff945 100644 --- a/runtime/typescript/packages/core/src/model/events/index.ts +++ b/runtime/typescript/packages/core/src/model/events/index.ts @@ -7,12 +7,22 @@ export { TurnEndPayload } from "./turn-end-payload"; export { LlmStartPayload } from "./llm-start-payload"; export { LlmCompletePayload } from "./llm-complete-payload"; export { RetryPayload } from "./retry-payload"; +export { RedactedField } from "./redacted-field"; +export { RedactionMetadata } from "./redaction-metadata"; export { PermissionRequestedPayload } from "./permission-requested-payload"; export { PermissionCompletedPayload } from "./permission-completed-payload"; +export { PermissionRequest } from "./permission-request"; +export { PermissionDecision } from "./permission-decision"; export { TokenEventPayload } from "./token-event-payload"; export { ThinkingEventPayload } from "./thinking-event-payload"; export { ToolCallStartPayload } from "./tool-call-start-payload"; export { ToolCallCompletePayload } from "./tool-call-complete-payload"; +export { ToolExecutionStartPayload } from "./tool-execution-start-payload"; +export { ToolExecutionCompletePayload } from "./tool-execution-complete-payload"; +export { HostToolRequest } from "./host-tool-request"; +export { HostToolResult } from "./host-tool-result"; +export { HookStartPayload } from "./hook-start-payload"; +export { HookEndPayload } from "./hook-end-payload"; export { ToolResultPayload } from "./tool-result-payload"; export { StatusEventPayload } from "./status-event-payload"; export { MessagesUpdatedPayload } from "./messages-updated-payload"; @@ -23,6 +33,17 @@ export { CompactionCompletePayload } from "./compaction-complete-payload"; export { CompactionFailedPayload } from "./compaction-failed-payload"; export { TurnSummary } from "./turn-summary"; export { TurnTrace } from "./turn-trace"; +export { HarnessContext } from "./harness-context"; +export { SessionStartPayload } from "./session-start-payload"; +export { SessionEndPayload } from "./session-end-payload"; +export { SessionWarningPayload } from "./session-warning-payload"; +export { SessionEvent } from "./session-event"; +export { Checkpoint } from "./checkpoint"; +export { TrajectoryEvent } from "./trajectory-event"; +export { SessionFileRef } from "./session-file-ref"; +export { SessionRef } from "./session-ref"; +export { SessionSummary } from "./session-summary"; +export { SessionTrace } from "./session-trace"; export { StreamChunk, TextChunk, diff --git a/runtime/typescript/packages/core/src/model/events/permission-completed-payload.ts b/runtime/typescript/packages/core/src/model/events/permission-completed-payload.ts index 0ab61ace..7a760ed6 100644 --- a/runtime/typescript/packages/core/src/model/events/permission-completed-payload.ts +++ b/runtime/typescript/packages/core/src/model/events/permission-completed-payload.ts @@ -6,16 +6,28 @@ import { LoadContext, SaveContext } from "../context"; export class PermissionCompletedPayload { static readonly shorthandProperty: string | undefined = undefined; + requestId?: string | undefined; + toolCallId?: string | undefined; permission: string = ""; approved: boolean = false; reason?: string | undefined; + result?: Record | undefined; constructor(init?: Partial) { + if (init?.requestId !== undefined) { + this.requestId = init.requestId; + } + if (init?.toolCallId !== undefined) { + this.toolCallId = init.toolCallId; + } this.permission = init?.permission ?? ""; this.approved = init?.approved ?? false; if (init?.reason !== undefined) { this.reason = init.reason; } + if (init?.result !== undefined) { + this.result = init.result; + } } //#region Load Methods @@ -30,6 +42,12 @@ export class PermissionCompletedPayload { const instance = new PermissionCompletedPayload(); + if (data["requestId"] !== undefined && data["requestId"] !== null) { + instance.requestId = String(data["requestId"]); + } + if (data["toolCallId"] !== undefined && data["toolCallId"] !== null) { + instance.toolCallId = String(data["toolCallId"]); + } if (data["permission"] !== undefined && data["permission"] !== null) { instance.permission = String(data["permission"]); } @@ -39,6 +57,9 @@ export class PermissionCompletedPayload { if (data["reason"] !== undefined && data["reason"] !== null) { instance.reason = String(data["reason"]); } + if (data["result"] !== undefined && data["result"] !== null) { + instance.result = data["result"] as Record; + } if (context) { return context.processOutput(instance) as PermissionCompletedPayload; @@ -58,6 +79,12 @@ export class PermissionCompletedPayload { const result: Record = {}; + if (obj.requestId !== undefined && obj.requestId !== null) { + result["requestId"] = obj.requestId; + } + if (obj.toolCallId !== undefined && obj.toolCallId !== null) { + result["toolCallId"] = obj.toolCallId; + } if (obj.permission !== undefined && obj.permission !== null) { result["permission"] = obj.permission; } @@ -67,6 +94,9 @@ export class PermissionCompletedPayload { if (obj.reason !== undefined && obj.reason !== null) { result["reason"] = obj.reason; } + if (obj.result !== undefined && obj.result !== null) { + result["result"] = obj.result; + } if (context) { return context.processDict(result); diff --git a/runtime/typescript/packages/core/src/model/events/permission-decision.ts b/runtime/typescript/packages/core/src/model/events/permission-decision.ts new file mode 100644 index 00000000..1eaee0a4 --- /dev/null +++ b/runtime/typescript/packages/core/src/model/events/permission-decision.ts @@ -0,0 +1,129 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { LoadContext, SaveContext } from "../context"; + +export class PermissionDecision { + static readonly shorthandProperty: string | undefined = undefined; + + requestId?: string | undefined; + toolCallId?: string | undefined; + permission: string = ""; + approved: boolean = false; + reason?: string | undefined; + result?: Record | undefined; + + constructor(init?: Partial) { + if (init?.requestId !== undefined) { + this.requestId = init.requestId; + } + if (init?.toolCallId !== undefined) { + this.toolCallId = init.toolCallId; + } + this.permission = init?.permission ?? ""; + this.approved = init?.approved ?? false; + if (init?.reason !== undefined) { + this.reason = init.reason; + } + if (init?.result !== undefined) { + this.result = init.result; + } + } + + //#region Load Methods + + static load( + data: Record, + context?: LoadContext, + ): PermissionDecision { + if (context) { + data = context.processInput(data) as Record; + } + + const instance = new PermissionDecision(); + + if (data["requestId"] !== undefined && data["requestId"] !== null) { + instance.requestId = String(data["requestId"]); + } + if (data["toolCallId"] !== undefined && data["toolCallId"] !== null) { + instance.toolCallId = String(data["toolCallId"]); + } + if (data["permission"] !== undefined && data["permission"] !== null) { + instance.permission = String(data["permission"]); + } + if (data["approved"] !== undefined && data["approved"] !== null) { + instance.approved = Boolean(data["approved"]); + } + if (data["reason"] !== undefined && data["reason"] !== null) { + instance.reason = String(data["reason"]); + } + if (data["result"] !== undefined && data["result"] !== null) { + instance.result = data["result"] as Record; + } + + if (context) { + return context.processOutput(instance) as PermissionDecision; + } + return instance; + } + + //#endregion + + //#region Save Methods + + save(context?: SaveContext): Record { + let obj: this = this; + if (context) { + obj = context.processObject(obj) as this; + } + + const result: Record = {}; + + if (obj.requestId !== undefined && obj.requestId !== null) { + result["requestId"] = obj.requestId; + } + if (obj.toolCallId !== undefined && obj.toolCallId !== null) { + result["toolCallId"] = obj.toolCallId; + } + if (obj.permission !== undefined && obj.permission !== null) { + result["permission"] = obj.permission; + } + if (obj.approved !== undefined && obj.approved !== null) { + result["approved"] = obj.approved; + } + if (obj.reason !== undefined && obj.reason !== null) { + result["reason"] = obj.reason; + } + if (obj.result !== undefined && obj.result !== null) { + result["result"] = obj.result; + } + + if (context) { + return context.processDict(result); + } + return result; + } + + toYaml(context?: SaveContext): string { + context = context ?? new SaveContext(); + return context.toYaml(this.save(context)); + } + + toJson(context?: SaveContext, indent: number = 2): string { + context = context ?? new SaveContext(); + return context.toJson(this.save(context), indent); + } + + static fromJson(json: string, context?: LoadContext): PermissionDecision { + const data = JSON.parse(json); + return PermissionDecision.load(data as Record, context); + } + + static fromYaml(yaml: string, context?: LoadContext): PermissionDecision { + const { parse } = require("yaml"); + const data = parse(yaml); + return PermissionDecision.load(data as Record, context); + } + + //#endregion +} diff --git a/runtime/typescript/packages/core/src/model/events/permission-request.ts b/runtime/typescript/packages/core/src/model/events/permission-request.ts new file mode 100644 index 00000000..e39c58e4 --- /dev/null +++ b/runtime/typescript/packages/core/src/model/events/permission-request.ts @@ -0,0 +1,141 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { LoadContext, SaveContext } from "../context"; + +export class PermissionRequest { + static readonly shorthandProperty: string | undefined = undefined; + + requestId?: string | undefined; + toolCallId?: string | undefined; + permission: string = ""; + target?: string | undefined; + details?: Record | undefined; + promptRequest?: string | undefined; + policy?: Record | undefined; + + constructor(init?: Partial) { + if (init?.requestId !== undefined) { + this.requestId = init.requestId; + } + if (init?.toolCallId !== undefined) { + this.toolCallId = init.toolCallId; + } + this.permission = init?.permission ?? ""; + if (init?.target !== undefined) { + this.target = init.target; + } + if (init?.details !== undefined) { + this.details = init.details; + } + if (init?.promptRequest !== undefined) { + this.promptRequest = init.promptRequest; + } + if (init?.policy !== undefined) { + this.policy = init.policy; + } + } + + //#region Load Methods + + static load( + data: Record, + context?: LoadContext, + ): PermissionRequest { + if (context) { + data = context.processInput(data) as Record; + } + + const instance = new PermissionRequest(); + + if (data["requestId"] !== undefined && data["requestId"] !== null) { + instance.requestId = String(data["requestId"]); + } + if (data["toolCallId"] !== undefined && data["toolCallId"] !== null) { + instance.toolCallId = String(data["toolCallId"]); + } + if (data["permission"] !== undefined && data["permission"] !== null) { + instance.permission = String(data["permission"]); + } + if (data["target"] !== undefined && data["target"] !== null) { + instance.target = String(data["target"]); + } + if (data["details"] !== undefined && data["details"] !== null) { + instance.details = data["details"] as Record; + } + if (data["promptRequest"] !== undefined && data["promptRequest"] !== null) { + instance.promptRequest = String(data["promptRequest"]); + } + if (data["policy"] !== undefined && data["policy"] !== null) { + instance.policy = data["policy"] as Record; + } + + if (context) { + return context.processOutput(instance) as PermissionRequest; + } + return instance; + } + + //#endregion + + //#region Save Methods + + save(context?: SaveContext): Record { + let obj: this = this; + if (context) { + obj = context.processObject(obj) as this; + } + + const result: Record = {}; + + if (obj.requestId !== undefined && obj.requestId !== null) { + result["requestId"] = obj.requestId; + } + if (obj.toolCallId !== undefined && obj.toolCallId !== null) { + result["toolCallId"] = obj.toolCallId; + } + if (obj.permission !== undefined && obj.permission !== null) { + result["permission"] = obj.permission; + } + if (obj.target !== undefined && obj.target !== null) { + result["target"] = obj.target; + } + if (obj.details !== undefined && obj.details !== null) { + result["details"] = obj.details; + } + if (obj.promptRequest !== undefined && obj.promptRequest !== null) { + result["promptRequest"] = obj.promptRequest; + } + if (obj.policy !== undefined && obj.policy !== null) { + result["policy"] = obj.policy; + } + + if (context) { + return context.processDict(result); + } + return result; + } + + toYaml(context?: SaveContext): string { + context = context ?? new SaveContext(); + return context.toYaml(this.save(context)); + } + + toJson(context?: SaveContext, indent: number = 2): string { + context = context ?? new SaveContext(); + return context.toJson(this.save(context), indent); + } + + static fromJson(json: string, context?: LoadContext): PermissionRequest { + const data = JSON.parse(json); + return PermissionRequest.load(data as Record, context); + } + + static fromYaml(yaml: string, context?: LoadContext): PermissionRequest { + const { parse } = require("yaml"); + const data = parse(yaml); + return PermissionRequest.load(data as Record, context); + } + + //#endregion +} diff --git a/runtime/typescript/packages/core/src/model/events/permission-requested-payload.ts b/runtime/typescript/packages/core/src/model/events/permission-requested-payload.ts index a7f8483c..5beaa5ab 100644 --- a/runtime/typescript/packages/core/src/model/events/permission-requested-payload.ts +++ b/runtime/typescript/packages/core/src/model/events/permission-requested-payload.ts @@ -2,15 +2,27 @@ // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. import { LoadContext, SaveContext } from "../context"; +import { RedactionMetadata } from "./redaction-metadata"; export class PermissionRequestedPayload { static readonly shorthandProperty: string | undefined = undefined; + requestId?: string | undefined; + toolCallId?: string | undefined; permission: string = ""; target?: string | undefined; details?: Record | undefined; + promptRequest?: string | undefined; + policy?: Record | undefined; + redaction?: RedactionMetadata | undefined; constructor(init?: Partial) { + if (init?.requestId !== undefined) { + this.requestId = init.requestId; + } + if (init?.toolCallId !== undefined) { + this.toolCallId = init.toolCallId; + } this.permission = init?.permission ?? ""; if (init?.target !== undefined) { this.target = init.target; @@ -18,6 +30,15 @@ export class PermissionRequestedPayload { if (init?.details !== undefined) { this.details = init.details; } + if (init?.promptRequest !== undefined) { + this.promptRequest = init.promptRequest; + } + if (init?.policy !== undefined) { + this.policy = init.policy; + } + if (init?.redaction !== undefined) { + this.redaction = init.redaction; + } } //#region Load Methods @@ -32,6 +53,12 @@ export class PermissionRequestedPayload { const instance = new PermissionRequestedPayload(); + if (data["requestId"] !== undefined && data["requestId"] !== null) { + instance.requestId = String(data["requestId"]); + } + if (data["toolCallId"] !== undefined && data["toolCallId"] !== null) { + instance.toolCallId = String(data["toolCallId"]); + } if (data["permission"] !== undefined && data["permission"] !== null) { instance.permission = String(data["permission"]); } @@ -41,6 +68,18 @@ export class PermissionRequestedPayload { if (data["details"] !== undefined && data["details"] !== null) { instance.details = data["details"] as Record; } + if (data["promptRequest"] !== undefined && data["promptRequest"] !== null) { + instance.promptRequest = String(data["promptRequest"]); + } + if (data["policy"] !== undefined && data["policy"] !== null) { + instance.policy = data["policy"] as Record; + } + if (data["redaction"] !== undefined && data["redaction"] !== null) { + instance.redaction = RedactionMetadata.load( + data["redaction"] as Record, + context, + ); + } if (context) { return context.processOutput(instance) as PermissionRequestedPayload; @@ -60,6 +99,12 @@ export class PermissionRequestedPayload { const result: Record = {}; + if (obj.requestId !== undefined && obj.requestId !== null) { + result["requestId"] = obj.requestId; + } + if (obj.toolCallId !== undefined && obj.toolCallId !== null) { + result["toolCallId"] = obj.toolCallId; + } if (obj.permission !== undefined && obj.permission !== null) { result["permission"] = obj.permission; } @@ -69,6 +114,15 @@ export class PermissionRequestedPayload { if (obj.details !== undefined && obj.details !== null) { result["details"] = obj.details; } + if (obj.promptRequest !== undefined && obj.promptRequest !== null) { + result["promptRequest"] = obj.promptRequest; + } + if (obj.policy !== undefined && obj.policy !== null) { + result["policy"] = obj.policy; + } + if (obj.redaction !== undefined && obj.redaction !== null) { + result["redaction"] = obj.redaction.save(context); + } if (context) { return context.processDict(result); diff --git a/runtime/typescript/packages/core/src/model/events/redacted-field.ts b/runtime/typescript/packages/core/src/model/events/redacted-field.ts new file mode 100644 index 00000000..ce94680c --- /dev/null +++ b/runtime/typescript/packages/core/src/model/events/redacted-field.ts @@ -0,0 +1,106 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { LoadContext, SaveContext } from "../context"; + +export type RedactionMode = + | "none" + | "redacted" + | "hashed" + | "summary" + | "reference"; + +export class RedactedField { + static readonly shorthandProperty: string | undefined = undefined; + + path: string = ""; + mode: RedactionMode = "none"; + reason?: string | undefined; + + constructor(init?: Partial) { + this.path = init?.path ?? ""; + this.mode = init?.mode ?? "none"; + if (init?.reason !== undefined) { + this.reason = init.reason; + } + } + + //#region Load Methods + + static load( + data: Record, + context?: LoadContext, + ): RedactedField { + if (context) { + data = context.processInput(data) as Record; + } + + const instance = new RedactedField(); + + if (data["path"] !== undefined && data["path"] !== null) { + instance.path = String(data["path"]); + } + if (data["mode"] !== undefined && data["mode"] !== null) { + instance.mode = String(data["mode"]) as RedactionMode; + } + if (data["reason"] !== undefined && data["reason"] !== null) { + instance.reason = String(data["reason"]); + } + + if (context) { + return context.processOutput(instance) as RedactedField; + } + return instance; + } + + //#endregion + + //#region Save Methods + + save(context?: SaveContext): Record { + let obj: this = this; + if (context) { + obj = context.processObject(obj) as this; + } + + const result: Record = {}; + + if (obj.path !== undefined && obj.path !== null) { + result["path"] = obj.path; + } + if (obj.mode !== undefined && obj.mode !== null) { + result["mode"] = obj.mode; + } + if (obj.reason !== undefined && obj.reason !== null) { + result["reason"] = obj.reason; + } + + if (context) { + return context.processDict(result); + } + return result; + } + + toYaml(context?: SaveContext): string { + context = context ?? new SaveContext(); + return context.toYaml(this.save(context)); + } + + toJson(context?: SaveContext, indent: number = 2): string { + context = context ?? new SaveContext(); + return context.toJson(this.save(context), indent); + } + + static fromJson(json: string, context?: LoadContext): RedactedField { + const data = JSON.parse(json); + return RedactedField.load(data as Record, context); + } + + static fromYaml(yaml: string, context?: LoadContext): RedactedField { + const { parse } = require("yaml"); + const data = parse(yaml); + return RedactedField.load(data as Record, context); + } + + //#endregion +} diff --git a/runtime/typescript/packages/core/src/model/events/redaction-metadata.ts b/runtime/typescript/packages/core/src/model/events/redaction-metadata.ts new file mode 100644 index 00000000..643434ae --- /dev/null +++ b/runtime/typescript/packages/core/src/model/events/redaction-metadata.ts @@ -0,0 +1,140 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { LoadContext, SaveContext } from "../context"; +import { RedactedField } from "./redacted-field"; + +export class RedactionMetadata { + static readonly shorthandProperty: string | undefined = undefined; + + sanitized?: boolean | undefined; + fields?: RedactedField[] = []; + policy?: string | undefined; + + constructor(init?: Partial) { + if (init?.sanitized !== undefined) { + this.sanitized = init.sanitized; + } + if (init?.fields !== undefined) { + this.fields = init.fields; + } + if (init?.policy !== undefined) { + this.policy = init.policy; + } + } + + //#region Load Methods + + static load( + data: Record, + context?: LoadContext, + ): RedactionMetadata { + if (context) { + data = context.processInput(data) as Record; + } + + const instance = new RedactionMetadata(); + + if (data["sanitized"] !== undefined && data["sanitized"] !== null) { + instance.sanitized = Boolean(data["sanitized"]); + } + if (data["fields"] !== undefined && data["fields"] !== null) { + instance.fields = RedactionMetadata.loadFields( + data["fields"] as unknown[], + context, + ); + } + if (data["policy"] !== undefined && data["policy"] !== null) { + instance.policy = String(data["policy"]); + } + + if (context) { + return context.processOutput(instance) as RedactionMetadata; + } + return instance; + } + + static loadFields( + data: Record[] | unknown[], + context?: LoadContext, + ): RedactedField[] { + if (!Array.isArray(data)) { + // Convert dict/object format to array format + const result: Record[] = []; + for (const [k, v] of Object.entries(data)) { + if (typeof v === "object" && v !== null && !Array.isArray(v)) { + result.push({ name: k, ...(v as Record) }); + } else { + result.push({ name: k, path: v }); + } + } + data = result; + } + return data.map((item) => + RedactedField.load(item as Record, context), + ); + } + + static saveFields( + items: RedactedField[], + context?: SaveContext, + ): Record[] | Record { + if (!context) { + context = new SaveContext(); + } + + // This type doesn't have a 'name' property, so always use array format + return items.map((item) => item.save(context)); + } + + //#endregion + + //#region Save Methods + + save(context?: SaveContext): Record { + let obj: this = this; + if (context) { + obj = context.processObject(obj) as this; + } + + const result: Record = {}; + + if (obj.sanitized !== undefined && obj.sanitized !== null) { + result["sanitized"] = obj.sanitized; + } + if (obj.fields !== undefined && obj.fields !== null) { + result["fields"] = RedactionMetadata.saveFields(obj.fields, context); + } + if (obj.policy !== undefined && obj.policy !== null) { + result["policy"] = obj.policy; + } + + if (context) { + return context.processDict(result); + } + return result; + } + + toYaml(context?: SaveContext): string { + context = context ?? new SaveContext(); + return context.toYaml(this.save(context)); + } + + toJson(context?: SaveContext, indent: number = 2): string { + context = context ?? new SaveContext(); + return context.toJson(this.save(context), indent); + } + + static fromJson(json: string, context?: LoadContext): RedactionMetadata { + const data = JSON.parse(json); + return RedactionMetadata.load(data as Record, context); + } + + static fromYaml(yaml: string, context?: LoadContext): RedactionMetadata { + const { parse } = require("yaml"); + const data = parse(yaml); + return RedactionMetadata.load(data as Record, context); + } + + //#endregion +} diff --git a/runtime/typescript/packages/core/src/model/events/session-end-payload.ts b/runtime/typescript/packages/core/src/model/events/session-end-payload.ts new file mode 100644 index 00000000..977382f3 --- /dev/null +++ b/runtime/typescript/packages/core/src/model/events/session-end-payload.ts @@ -0,0 +1,119 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { LoadContext, SaveContext } from "../context"; + +export type SessionEndStatus = + | "success" + | "error" + | "cancelled" + | "interrupted"; + +export class SessionEndPayload { + static readonly shorthandProperty: string | undefined = undefined; + + sessionId?: string | undefined; + status?: SessionEndStatus | undefined; + reason?: string | undefined; + durationMs?: number | undefined; + + constructor(init?: Partial) { + if (init?.sessionId !== undefined) { + this.sessionId = init.sessionId; + } + if (init?.status !== undefined) { + this.status = init.status; + } + if (init?.reason !== undefined) { + this.reason = init.reason; + } + if (init?.durationMs !== undefined) { + this.durationMs = init.durationMs; + } + } + + //#region Load Methods + + static load( + data: Record, + context?: LoadContext, + ): SessionEndPayload { + if (context) { + data = context.processInput(data) as Record; + } + + const instance = new SessionEndPayload(); + + if (data["sessionId"] !== undefined && data["sessionId"] !== null) { + instance.sessionId = String(data["sessionId"]); + } + if (data["status"] !== undefined && data["status"] !== null) { + instance.status = String(data["status"]) as SessionEndStatus; + } + if (data["reason"] !== undefined && data["reason"] !== null) { + instance.reason = String(data["reason"]); + } + if (data["durationMs"] !== undefined && data["durationMs"] !== null) { + instance.durationMs = Number(data["durationMs"]); + } + + if (context) { + return context.processOutput(instance) as SessionEndPayload; + } + return instance; + } + + //#endregion + + //#region Save Methods + + save(context?: SaveContext): Record { + let obj: this = this; + if (context) { + obj = context.processObject(obj) as this; + } + + const result: Record = {}; + + if (obj.sessionId !== undefined && obj.sessionId !== null) { + result["sessionId"] = obj.sessionId; + } + if (obj.status !== undefined && obj.status !== null) { + result["status"] = obj.status; + } + if (obj.reason !== undefined && obj.reason !== null) { + result["reason"] = obj.reason; + } + if (obj.durationMs !== undefined && obj.durationMs !== null) { + result["durationMs"] = obj.durationMs; + } + + if (context) { + return context.processDict(result); + } + return result; + } + + toYaml(context?: SaveContext): string { + context = context ?? new SaveContext(); + return context.toYaml(this.save(context)); + } + + toJson(context?: SaveContext, indent: number = 2): string { + context = context ?? new SaveContext(); + return context.toJson(this.save(context), indent); + } + + static fromJson(json: string, context?: LoadContext): SessionEndPayload { + const data = JSON.parse(json); + return SessionEndPayload.load(data as Record, context); + } + + static fromYaml(yaml: string, context?: LoadContext): SessionEndPayload { + const { parse } = require("yaml"); + const data = parse(yaml); + return SessionEndPayload.load(data as Record, context); + } + + //#endregion +} diff --git a/runtime/typescript/packages/core/src/model/events/session-event.ts b/runtime/typescript/packages/core/src/model/events/session-event.ts new file mode 100644 index 00000000..602fc186 --- /dev/null +++ b/runtime/typescript/packages/core/src/model/events/session-event.ts @@ -0,0 +1,168 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { LoadContext, SaveContext } from "../context"; +import { RedactionMetadata } from "./redaction-metadata"; + +export type SessionEventType = + | "session_start" + | "session_end" + | "session_warning" + | "session_hook_start" + | "session_hook_end" + | "checkpoint_created" + | "trajectory_event"; + +export class SessionEvent { + static readonly shorthandProperty: string | undefined = undefined; + + id: string = ""; + type: SessionEventType = "session_start"; + timestamp: string = ""; + sessionId?: string | undefined; + turnId?: string | undefined; + parentId?: string | undefined; + spanId?: string | undefined; + payload: Record = {}; + redaction?: RedactionMetadata | undefined; + + constructor(init?: Partial) { + this.id = init?.id ?? ""; + this.type = init?.type ?? "session_start"; + this.timestamp = init?.timestamp ?? ""; + if (init?.sessionId !== undefined) { + this.sessionId = init.sessionId; + } + if (init?.turnId !== undefined) { + this.turnId = init.turnId; + } + if (init?.parentId !== undefined) { + this.parentId = init.parentId; + } + if (init?.spanId !== undefined) { + this.spanId = init.spanId; + } + this.payload = init?.payload ?? {}; + if (init?.redaction !== undefined) { + this.redaction = init.redaction; + } + } + + //#region Load Methods + + static load( + data: Record, + context?: LoadContext, + ): SessionEvent { + if (context) { + data = context.processInput(data) as Record; + } + + const instance = new SessionEvent(); + + if (data["id"] !== undefined && data["id"] !== null) { + instance.id = String(data["id"]); + } + if (data["type"] !== undefined && data["type"] !== null) { + instance.type = String(data["type"]) as SessionEventType; + } + if (data["timestamp"] !== undefined && data["timestamp"] !== null) { + instance.timestamp = String(data["timestamp"]); + } + if (data["sessionId"] !== undefined && data["sessionId"] !== null) { + instance.sessionId = String(data["sessionId"]); + } + if (data["turnId"] !== undefined && data["turnId"] !== null) { + instance.turnId = String(data["turnId"]); + } + if (data["parentId"] !== undefined && data["parentId"] !== null) { + instance.parentId = String(data["parentId"]); + } + if (data["spanId"] !== undefined && data["spanId"] !== null) { + instance.spanId = String(data["spanId"]); + } + if (data["payload"] !== undefined && data["payload"] !== null) { + instance.payload = data["payload"] as Record; + } + if (data["redaction"] !== undefined && data["redaction"] !== null) { + instance.redaction = RedactionMetadata.load( + data["redaction"] as Record, + context, + ); + } + + if (context) { + return context.processOutput(instance) as SessionEvent; + } + return instance; + } + + //#endregion + + //#region Save Methods + + save(context?: SaveContext): Record { + let obj: this = this; + if (context) { + obj = context.processObject(obj) as this; + } + + const result: Record = {}; + + if (obj.id !== undefined && obj.id !== null) { + result["id"] = obj.id; + } + if (obj.type !== undefined && obj.type !== null) { + result["type"] = obj.type; + } + if (obj.timestamp !== undefined && obj.timestamp !== null) { + result["timestamp"] = obj.timestamp; + } + if (obj.sessionId !== undefined && obj.sessionId !== null) { + result["sessionId"] = obj.sessionId; + } + if (obj.turnId !== undefined && obj.turnId !== null) { + result["turnId"] = obj.turnId; + } + if (obj.parentId !== undefined && obj.parentId !== null) { + result["parentId"] = obj.parentId; + } + if (obj.spanId !== undefined && obj.spanId !== null) { + result["spanId"] = obj.spanId; + } + if (obj.payload !== undefined && obj.payload !== null) { + result["payload"] = obj.payload; + } + if (obj.redaction !== undefined && obj.redaction !== null) { + result["redaction"] = obj.redaction.save(context); + } + + if (context) { + return context.processDict(result); + } + return result; + } + + toYaml(context?: SaveContext): string { + context = context ?? new SaveContext(); + return context.toYaml(this.save(context)); + } + + toJson(context?: SaveContext, indent: number = 2): string { + context = context ?? new SaveContext(); + return context.toJson(this.save(context), indent); + } + + static fromJson(json: string, context?: LoadContext): SessionEvent { + const data = JSON.parse(json); + return SessionEvent.load(data as Record, context); + } + + static fromYaml(yaml: string, context?: LoadContext): SessionEvent { + const { parse } = require("yaml"); + const data = parse(yaml); + return SessionEvent.load(data as Record, context); + } + + //#endregion +} diff --git a/runtime/typescript/packages/core/src/model/events/session-file-ref.ts b/runtime/typescript/packages/core/src/model/events/session-file-ref.ts new file mode 100644 index 00000000..ba09a16a --- /dev/null +++ b/runtime/typescript/packages/core/src/model/events/session-file-ref.ts @@ -0,0 +1,121 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { LoadContext, SaveContext } from "../context"; + +export class SessionFileRef { + static readonly shorthandProperty: string | undefined = undefined; + + sessionId?: string | undefined; + path: string = ""; + toolName?: string | undefined; + turnIndex?: number | undefined; + firstSeenAt?: string | undefined; + + constructor(init?: Partial) { + if (init?.sessionId !== undefined) { + this.sessionId = init.sessionId; + } + this.path = init?.path ?? ""; + if (init?.toolName !== undefined) { + this.toolName = init.toolName; + } + if (init?.turnIndex !== undefined) { + this.turnIndex = init.turnIndex; + } + if (init?.firstSeenAt !== undefined) { + this.firstSeenAt = init.firstSeenAt; + } + } + + //#region Load Methods + + static load( + data: Record, + context?: LoadContext, + ): SessionFileRef { + if (context) { + data = context.processInput(data) as Record; + } + + const instance = new SessionFileRef(); + + if (data["sessionId"] !== undefined && data["sessionId"] !== null) { + instance.sessionId = String(data["sessionId"]); + } + if (data["path"] !== undefined && data["path"] !== null) { + instance.path = String(data["path"]); + } + if (data["toolName"] !== undefined && data["toolName"] !== null) { + instance.toolName = String(data["toolName"]); + } + if (data["turnIndex"] !== undefined && data["turnIndex"] !== null) { + instance.turnIndex = Number(data["turnIndex"]); + } + if (data["firstSeenAt"] !== undefined && data["firstSeenAt"] !== null) { + instance.firstSeenAt = String(data["firstSeenAt"]); + } + + if (context) { + return context.processOutput(instance) as SessionFileRef; + } + return instance; + } + + //#endregion + + //#region Save Methods + + save(context?: SaveContext): Record { + let obj: this = this; + if (context) { + obj = context.processObject(obj) as this; + } + + const result: Record = {}; + + if (obj.sessionId !== undefined && obj.sessionId !== null) { + result["sessionId"] = obj.sessionId; + } + if (obj.path !== undefined && obj.path !== null) { + result["path"] = obj.path; + } + if (obj.toolName !== undefined && obj.toolName !== null) { + result["toolName"] = obj.toolName; + } + if (obj.turnIndex !== undefined && obj.turnIndex !== null) { + result["turnIndex"] = obj.turnIndex; + } + if (obj.firstSeenAt !== undefined && obj.firstSeenAt !== null) { + result["firstSeenAt"] = obj.firstSeenAt; + } + + if (context) { + return context.processDict(result); + } + return result; + } + + toYaml(context?: SaveContext): string { + context = context ?? new SaveContext(); + return context.toYaml(this.save(context)); + } + + toJson(context?: SaveContext, indent: number = 2): string { + context = context ?? new SaveContext(); + return context.toJson(this.save(context), indent); + } + + static fromJson(json: string, context?: LoadContext): SessionFileRef { + const data = JSON.parse(json); + return SessionFileRef.load(data as Record, context); + } + + static fromYaml(yaml: string, context?: LoadContext): SessionFileRef { + const { parse } = require("yaml"); + const data = parse(yaml); + return SessionFileRef.load(data as Record, context); + } + + //#endregion +} diff --git a/runtime/typescript/packages/core/src/model/events/session-ref.ts b/runtime/typescript/packages/core/src/model/events/session-ref.ts new file mode 100644 index 00000000..566ae841 --- /dev/null +++ b/runtime/typescript/packages/core/src/model/events/session-ref.ts @@ -0,0 +1,119 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { LoadContext, SaveContext } from "../context"; + +export class SessionRef { + static readonly shorthandProperty: string | undefined = undefined; + + sessionId?: string | undefined; + refType: string = ""; + refValue: string = ""; + turnIndex?: number | undefined; + createdAt?: string | undefined; + + constructor(init?: Partial) { + if (init?.sessionId !== undefined) { + this.sessionId = init.sessionId; + } + this.refType = init?.refType ?? ""; + this.refValue = init?.refValue ?? ""; + if (init?.turnIndex !== undefined) { + this.turnIndex = init.turnIndex; + } + if (init?.createdAt !== undefined) { + this.createdAt = init.createdAt; + } + } + + //#region Load Methods + + static load( + data: Record, + context?: LoadContext, + ): SessionRef { + if (context) { + data = context.processInput(data) as Record; + } + + const instance = new SessionRef(); + + if (data["sessionId"] !== undefined && data["sessionId"] !== null) { + instance.sessionId = String(data["sessionId"]); + } + if (data["refType"] !== undefined && data["refType"] !== null) { + instance.refType = String(data["refType"]); + } + if (data["refValue"] !== undefined && data["refValue"] !== null) { + instance.refValue = String(data["refValue"]); + } + if (data["turnIndex"] !== undefined && data["turnIndex"] !== null) { + instance.turnIndex = Number(data["turnIndex"]); + } + if (data["createdAt"] !== undefined && data["createdAt"] !== null) { + instance.createdAt = String(data["createdAt"]); + } + + if (context) { + return context.processOutput(instance) as SessionRef; + } + return instance; + } + + //#endregion + + //#region Save Methods + + save(context?: SaveContext): Record { + let obj: this = this; + if (context) { + obj = context.processObject(obj) as this; + } + + const result: Record = {}; + + if (obj.sessionId !== undefined && obj.sessionId !== null) { + result["sessionId"] = obj.sessionId; + } + if (obj.refType !== undefined && obj.refType !== null) { + result["refType"] = obj.refType; + } + if (obj.refValue !== undefined && obj.refValue !== null) { + result["refValue"] = obj.refValue; + } + if (obj.turnIndex !== undefined && obj.turnIndex !== null) { + result["turnIndex"] = obj.turnIndex; + } + if (obj.createdAt !== undefined && obj.createdAt !== null) { + result["createdAt"] = obj.createdAt; + } + + if (context) { + return context.processDict(result); + } + return result; + } + + toYaml(context?: SaveContext): string { + context = context ?? new SaveContext(); + return context.toYaml(this.save(context)); + } + + toJson(context?: SaveContext, indent: number = 2): string { + context = context ?? new SaveContext(); + return context.toJson(this.save(context), indent); + } + + static fromJson(json: string, context?: LoadContext): SessionRef { + const data = JSON.parse(json); + return SessionRef.load(data as Record, context); + } + + static fromYaml(yaml: string, context?: LoadContext): SessionRef { + const { parse } = require("yaml"); + const data = parse(yaml); + return SessionRef.load(data as Record, context); + } + + //#endregion +} diff --git a/runtime/typescript/packages/core/src/model/events/session-start-payload.ts b/runtime/typescript/packages/core/src/model/events/session-start-payload.ts new file mode 100644 index 00000000..4852f8d3 --- /dev/null +++ b/runtime/typescript/packages/core/src/model/events/session-start-payload.ts @@ -0,0 +1,171 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { LoadContext, SaveContext } from "../context"; +import { HarnessContext } from "./harness-context"; + +export class SessionStartPayload { + static readonly shorthandProperty: string | undefined = undefined; + + sessionId: string = ""; + version?: number | undefined; + producer?: string | undefined; + runtime?: string | undefined; + promptyVersion?: string | undefined; + startTime?: string | undefined; + selectedModel?: string | undefined; + reasoningEffort?: string | undefined; + context?: HarnessContext | undefined; + + constructor(init?: Partial) { + this.sessionId = init?.sessionId ?? ""; + if (init?.version !== undefined) { + this.version = init.version; + } + if (init?.producer !== undefined) { + this.producer = init.producer; + } + if (init?.runtime !== undefined) { + this.runtime = init.runtime; + } + if (init?.promptyVersion !== undefined) { + this.promptyVersion = init.promptyVersion; + } + if (init?.startTime !== undefined) { + this.startTime = init.startTime; + } + if (init?.selectedModel !== undefined) { + this.selectedModel = init.selectedModel; + } + if (init?.reasoningEffort !== undefined) { + this.reasoningEffort = init.reasoningEffort; + } + if (init?.context !== undefined) { + this.context = init.context; + } + } + + //#region Load Methods + + static load( + data: Record, + context?: LoadContext, + ): SessionStartPayload { + if (context) { + data = context.processInput(data) as Record; + } + + const instance = new SessionStartPayload(); + + if (data["sessionId"] !== undefined && data["sessionId"] !== null) { + instance.sessionId = String(data["sessionId"]); + } + if (data["version"] !== undefined && data["version"] !== null) { + instance.version = Number(data["version"]); + } + if (data["producer"] !== undefined && data["producer"] !== null) { + instance.producer = String(data["producer"]); + } + if (data["runtime"] !== undefined && data["runtime"] !== null) { + instance.runtime = String(data["runtime"]); + } + if ( + data["promptyVersion"] !== undefined && + data["promptyVersion"] !== null + ) { + instance.promptyVersion = String(data["promptyVersion"]); + } + if (data["startTime"] !== undefined && data["startTime"] !== null) { + instance.startTime = String(data["startTime"]); + } + if (data["selectedModel"] !== undefined && data["selectedModel"] !== null) { + instance.selectedModel = String(data["selectedModel"]); + } + if ( + data["reasoningEffort"] !== undefined && + data["reasoningEffort"] !== null + ) { + instance.reasoningEffort = String(data["reasoningEffort"]); + } + if (data["context"] !== undefined && data["context"] !== null) { + instance.context = HarnessContext.load( + data["context"] as Record, + context, + ); + } + + if (context) { + return context.processOutput(instance) as SessionStartPayload; + } + return instance; + } + + //#endregion + + //#region Save Methods + + save(context?: SaveContext): Record { + let obj: this = this; + if (context) { + obj = context.processObject(obj) as this; + } + + const result: Record = {}; + + if (obj.sessionId !== undefined && obj.sessionId !== null) { + result["sessionId"] = obj.sessionId; + } + if (obj.version !== undefined && obj.version !== null) { + result["version"] = obj.version; + } + if (obj.producer !== undefined && obj.producer !== null) { + result["producer"] = obj.producer; + } + if (obj.runtime !== undefined && obj.runtime !== null) { + result["runtime"] = obj.runtime; + } + if (obj.promptyVersion !== undefined && obj.promptyVersion !== null) { + result["promptyVersion"] = obj.promptyVersion; + } + if (obj.startTime !== undefined && obj.startTime !== null) { + result["startTime"] = obj.startTime; + } + if (obj.selectedModel !== undefined && obj.selectedModel !== null) { + result["selectedModel"] = obj.selectedModel; + } + if (obj.reasoningEffort !== undefined && obj.reasoningEffort !== null) { + result["reasoningEffort"] = obj.reasoningEffort; + } + if (obj.context !== undefined && obj.context !== null) { + result["context"] = obj.context.save(context); + } + + if (context) { + return context.processDict(result); + } + return result; + } + + toYaml(context?: SaveContext): string { + context = context ?? new SaveContext(); + return context.toYaml(this.save(context)); + } + + toJson(context?: SaveContext, indent: number = 2): string { + context = context ?? new SaveContext(); + return context.toJson(this.save(context), indent); + } + + static fromJson(json: string, context?: LoadContext): SessionStartPayload { + const data = JSON.parse(json); + return SessionStartPayload.load(data as Record, context); + } + + static fromYaml(yaml: string, context?: LoadContext): SessionStartPayload { + const { parse } = require("yaml"); + const data = parse(yaml); + return SessionStartPayload.load(data as Record, context); + } + + //#endregion +} diff --git a/runtime/typescript/packages/core/src/model/events/session-summary.ts b/runtime/typescript/packages/core/src/model/events/session-summary.ts new file mode 100644 index 00000000..f882c83e --- /dev/null +++ b/runtime/typescript/packages/core/src/model/events/session-summary.ts @@ -0,0 +1,141 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { LoadContext, SaveContext } from "../context"; +import { TokenUsage } from "../model/token-usage"; + +export type SessionSummaryStatus = + | "success" + | "error" + | "cancelled" + | "interrupted"; + +export class SessionSummary { + static readonly shorthandProperty: string | undefined = undefined; + + sessionId: string = ""; + status?: SessionSummaryStatus | undefined; + turns?: number | undefined; + checkpoints?: number | undefined; + usage?: TokenUsage | undefined; + durationMs?: number | undefined; + + constructor(init?: Partial) { + this.sessionId = init?.sessionId ?? ""; + if (init?.status !== undefined) { + this.status = init.status; + } + if (init?.turns !== undefined) { + this.turns = init.turns; + } + if (init?.checkpoints !== undefined) { + this.checkpoints = init.checkpoints; + } + if (init?.usage !== undefined) { + this.usage = init.usage; + } + if (init?.durationMs !== undefined) { + this.durationMs = init.durationMs; + } + } + + //#region Load Methods + + static load( + data: Record, + context?: LoadContext, + ): SessionSummary { + if (context) { + data = context.processInput(data) as Record; + } + + const instance = new SessionSummary(); + + if (data["sessionId"] !== undefined && data["sessionId"] !== null) { + instance.sessionId = String(data["sessionId"]); + } + if (data["status"] !== undefined && data["status"] !== null) { + instance.status = String(data["status"]) as SessionSummaryStatus; + } + if (data["turns"] !== undefined && data["turns"] !== null) { + instance.turns = Number(data["turns"]); + } + if (data["checkpoints"] !== undefined && data["checkpoints"] !== null) { + instance.checkpoints = Number(data["checkpoints"]); + } + if (data["usage"] !== undefined && data["usage"] !== null) { + instance.usage = TokenUsage.load( + data["usage"] as Record, + context, + ); + } + if (data["durationMs"] !== undefined && data["durationMs"] !== null) { + instance.durationMs = Number(data["durationMs"]); + } + + if (context) { + return context.processOutput(instance) as SessionSummary; + } + return instance; + } + + //#endregion + + //#region Save Methods + + save(context?: SaveContext): Record { + let obj: this = this; + if (context) { + obj = context.processObject(obj) as this; + } + + const result: Record = {}; + + if (obj.sessionId !== undefined && obj.sessionId !== null) { + result["sessionId"] = obj.sessionId; + } + if (obj.status !== undefined && obj.status !== null) { + result["status"] = obj.status; + } + if (obj.turns !== undefined && obj.turns !== null) { + result["turns"] = obj.turns; + } + if (obj.checkpoints !== undefined && obj.checkpoints !== null) { + result["checkpoints"] = obj.checkpoints; + } + if (obj.usage !== undefined && obj.usage !== null) { + result["usage"] = obj.usage.save(context); + } + if (obj.durationMs !== undefined && obj.durationMs !== null) { + result["durationMs"] = obj.durationMs; + } + + if (context) { + return context.processDict(result); + } + return result; + } + + toYaml(context?: SaveContext): string { + context = context ?? new SaveContext(); + return context.toYaml(this.save(context)); + } + + toJson(context?: SaveContext, indent: number = 2): string { + context = context ?? new SaveContext(); + return context.toJson(this.save(context), indent); + } + + static fromJson(json: string, context?: LoadContext): SessionSummary { + const data = JSON.parse(json); + return SessionSummary.load(data as Record, context); + } + + static fromYaml(yaml: string, context?: LoadContext): SessionSummary { + const { parse } = require("yaml"); + const data = parse(yaml); + return SessionSummary.load(data as Record, context); + } + + //#endregion +} diff --git a/runtime/typescript/packages/core/src/model/events/session-trace.ts b/runtime/typescript/packages/core/src/model/events/session-trace.ts new file mode 100644 index 00000000..d5fc7963 --- /dev/null +++ b/runtime/typescript/packages/core/src/model/events/session-trace.ts @@ -0,0 +1,411 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { LoadContext, SaveContext } from "../context"; +import { Checkpoint } from "./checkpoint"; +import { SessionEvent } from "./session-event"; +import { SessionFileRef } from "./session-file-ref"; +import { SessionRef } from "./session-ref"; +import { SessionSummary } from "./session-summary"; +import { TrajectoryEvent } from "./trajectory-event"; +import { TurnTrace } from "./turn-trace"; + +export class SessionTrace { + static readonly shorthandProperty: string | undefined = undefined; + + version: string = "1"; + runtime?: string | undefined; + promptyVersion?: string | undefined; + sessionId?: string | undefined; + events: SessionEvent[] = []; + turns?: TurnTrace[] = []; + checkpoints?: Checkpoint[] = []; + trajectory?: TrajectoryEvent[] = []; + files?: SessionFileRef[] = []; + refs?: SessionRef[] = []; + summary?: SessionSummary | undefined; + + constructor(init?: Partial) { + this.version = init?.version ?? "1"; + if (init?.runtime !== undefined) { + this.runtime = init.runtime; + } + if (init?.promptyVersion !== undefined) { + this.promptyVersion = init.promptyVersion; + } + if (init?.sessionId !== undefined) { + this.sessionId = init.sessionId; + } + this.events = init?.events ?? []; + if (init?.turns !== undefined) { + this.turns = init.turns; + } + if (init?.checkpoints !== undefined) { + this.checkpoints = init.checkpoints; + } + if (init?.trajectory !== undefined) { + this.trajectory = init.trajectory; + } + if (init?.files !== undefined) { + this.files = init.files; + } + if (init?.refs !== undefined) { + this.refs = init.refs; + } + if (init?.summary !== undefined) { + this.summary = init.summary; + } + } + + //#region Load Methods + + static load( + data: Record, + context?: LoadContext, + ): SessionTrace { + if (context) { + data = context.processInput(data) as Record; + } + + const instance = new SessionTrace(); + + if (data["version"] !== undefined && data["version"] !== null) { + instance.version = String(data["version"]); + } + if (data["runtime"] !== undefined && data["runtime"] !== null) { + instance.runtime = String(data["runtime"]); + } + if ( + data["promptyVersion"] !== undefined && + data["promptyVersion"] !== null + ) { + instance.promptyVersion = String(data["promptyVersion"]); + } + if (data["sessionId"] !== undefined && data["sessionId"] !== null) { + instance.sessionId = String(data["sessionId"]); + } + if (data["events"] !== undefined && data["events"] !== null) { + instance.events = SessionTrace.loadEvents( + data["events"] as unknown[], + context, + ); + } + if (data["turns"] !== undefined && data["turns"] !== null) { + instance.turns = SessionTrace.loadTurns( + data["turns"] as unknown[], + context, + ); + } + if (data["checkpoints"] !== undefined && data["checkpoints"] !== null) { + instance.checkpoints = SessionTrace.loadCheckpoints( + data["checkpoints"] as unknown[], + context, + ); + } + if (data["trajectory"] !== undefined && data["trajectory"] !== null) { + instance.trajectory = SessionTrace.loadTrajectory( + data["trajectory"] as unknown[], + context, + ); + } + if (data["files"] !== undefined && data["files"] !== null) { + instance.files = SessionTrace.loadFiles( + data["files"] as unknown[], + context, + ); + } + if (data["refs"] !== undefined && data["refs"] !== null) { + instance.refs = SessionTrace.loadRefs(data["refs"] as unknown[], context); + } + if (data["summary"] !== undefined && data["summary"] !== null) { + instance.summary = SessionSummary.load( + data["summary"] as Record, + context, + ); + } + + if (context) { + return context.processOutput(instance) as SessionTrace; + } + return instance; + } + + static loadEvents( + data: Record[] | unknown[], + context?: LoadContext, + ): SessionEvent[] { + if (!Array.isArray(data)) { + // Convert dict/object format to array format + const result: Record[] = []; + for (const [k, v] of Object.entries(data)) { + if (typeof v === "object" && v !== null && !Array.isArray(v)) { + result.push({ name: k, ...(v as Record) }); + } else { + result.push({ name: k, id: v }); + } + } + data = result; + } + return data.map((item) => + SessionEvent.load(item as Record, context), + ); + } + + static saveEvents( + items: SessionEvent[], + context?: SaveContext, + ): Record[] | Record { + if (!context) { + context = new SaveContext(); + } + + // This type doesn't have a 'name' property, so always use array format + return items.map((item) => item.save(context)); + } + + static loadTurns( + data: Record[] | unknown[], + context?: LoadContext, + ): TurnTrace[] { + if (!Array.isArray(data)) { + // Convert dict/object format to array format + const result: Record[] = []; + for (const [k, v] of Object.entries(data)) { + if (typeof v === "object" && v !== null && !Array.isArray(v)) { + result.push({ name: k, ...(v as Record) }); + } else { + result.push({ name: k, version: v }); + } + } + data = result; + } + return data.map((item) => + TurnTrace.load(item as Record, context), + ); + } + + static saveTurns( + items: TurnTrace[], + context?: SaveContext, + ): Record[] | Record { + if (!context) { + context = new SaveContext(); + } + + // This type doesn't have a 'name' property, so always use array format + return items.map((item) => item.save(context)); + } + + static loadCheckpoints( + data: Record[] | unknown[], + context?: LoadContext, + ): Checkpoint[] { + if (!Array.isArray(data)) { + // Convert dict/object format to array format + const result: Record[] = []; + for (const [k, v] of Object.entries(data)) { + if (typeof v === "object" && v !== null && !Array.isArray(v)) { + result.push({ name: k, ...(v as Record) }); + } else { + result.push({ name: k, id: v }); + } + } + data = result; + } + return data.map((item) => + Checkpoint.load(item as Record, context), + ); + } + + static saveCheckpoints( + items: Checkpoint[], + context?: SaveContext, + ): Record[] | Record { + if (!context) { + context = new SaveContext(); + } + + // This type doesn't have a 'name' property, so always use array format + return items.map((item) => item.save(context)); + } + + static loadTrajectory( + data: Record[] | unknown[], + context?: LoadContext, + ): TrajectoryEvent[] { + if (!Array.isArray(data)) { + // Convert dict/object format to array format + const result: Record[] = []; + for (const [k, v] of Object.entries(data)) { + if (typeof v === "object" && v !== null && !Array.isArray(v)) { + result.push({ name: k, ...(v as Record) }); + } else { + result.push({ name: k, id: v }); + } + } + data = result; + } + return data.map((item) => + TrajectoryEvent.load(item as Record, context), + ); + } + + static saveTrajectory( + items: TrajectoryEvent[], + context?: SaveContext, + ): Record[] | Record { + if (!context) { + context = new SaveContext(); + } + + // This type doesn't have a 'name' property, so always use array format + return items.map((item) => item.save(context)); + } + + static loadFiles( + data: Record[] | unknown[], + context?: LoadContext, + ): SessionFileRef[] { + if (!Array.isArray(data)) { + // Convert dict/object format to array format + const result: Record[] = []; + for (const [k, v] of Object.entries(data)) { + if (typeof v === "object" && v !== null && !Array.isArray(v)) { + result.push({ name: k, ...(v as Record) }); + } else { + result.push({ name: k, sessionId: v }); + } + } + data = result; + } + return data.map((item) => + SessionFileRef.load(item as Record, context), + ); + } + + static saveFiles( + items: SessionFileRef[], + context?: SaveContext, + ): Record[] | Record { + if (!context) { + context = new SaveContext(); + } + + // This type doesn't have a 'name' property, so always use array format + return items.map((item) => item.save(context)); + } + + static loadRefs( + data: Record[] | unknown[], + context?: LoadContext, + ): SessionRef[] { + if (!Array.isArray(data)) { + // Convert dict/object format to array format + const result: Record[] = []; + for (const [k, v] of Object.entries(data)) { + if (typeof v === "object" && v !== null && !Array.isArray(v)) { + result.push({ name: k, ...(v as Record) }); + } else { + result.push({ name: k, sessionId: v }); + } + } + data = result; + } + return data.map((item) => + SessionRef.load(item as Record, context), + ); + } + + static saveRefs( + items: SessionRef[], + context?: SaveContext, + ): Record[] | Record { + if (!context) { + context = new SaveContext(); + } + + // This type doesn't have a 'name' property, so always use array format + return items.map((item) => item.save(context)); + } + + //#endregion + + //#region Save Methods + + save(context?: SaveContext): Record { + let obj: this = this; + if (context) { + obj = context.processObject(obj) as this; + } + + const result: Record = {}; + + if (obj.version !== undefined && obj.version !== null) { + result["version"] = obj.version; + } + if (obj.runtime !== undefined && obj.runtime !== null) { + result["runtime"] = obj.runtime; + } + if (obj.promptyVersion !== undefined && obj.promptyVersion !== null) { + result["promptyVersion"] = obj.promptyVersion; + } + if (obj.sessionId !== undefined && obj.sessionId !== null) { + result["sessionId"] = obj.sessionId; + } + if (obj.events !== undefined && obj.events !== null) { + result["events"] = SessionTrace.saveEvents(obj.events, context); + } + if (obj.turns !== undefined && obj.turns !== null) { + result["turns"] = SessionTrace.saveTurns(obj.turns, context); + } + if (obj.checkpoints !== undefined && obj.checkpoints !== null) { + result["checkpoints"] = SessionTrace.saveCheckpoints( + obj.checkpoints, + context, + ); + } + if (obj.trajectory !== undefined && obj.trajectory !== null) { + result["trajectory"] = SessionTrace.saveTrajectory( + obj.trajectory, + context, + ); + } + if (obj.files !== undefined && obj.files !== null) { + result["files"] = SessionTrace.saveFiles(obj.files, context); + } + if (obj.refs !== undefined && obj.refs !== null) { + result["refs"] = SessionTrace.saveRefs(obj.refs, context); + } + if (obj.summary !== undefined && obj.summary !== null) { + result["summary"] = obj.summary.save(context); + } + + if (context) { + return context.processDict(result); + } + return result; + } + + toYaml(context?: SaveContext): string { + context = context ?? new SaveContext(); + return context.toYaml(this.save(context)); + } + + toJson(context?: SaveContext, indent: number = 2): string { + context = context ?? new SaveContext(); + return context.toJson(this.save(context), indent); + } + + static fromJson(json: string, context?: LoadContext): SessionTrace { + const data = JSON.parse(json); + return SessionTrace.load(data as Record, context); + } + + static fromYaml(yaml: string, context?: LoadContext): SessionTrace { + const { parse } = require("yaml"); + const data = parse(yaml); + return SessionTrace.load(data as Record, context); + } + + //#endregion +} diff --git a/runtime/typescript/packages/core/src/model/events/session-warning-payload.ts b/runtime/typescript/packages/core/src/model/events/session-warning-payload.ts new file mode 100644 index 00000000..255c0a89 --- /dev/null +++ b/runtime/typescript/packages/core/src/model/events/session-warning-payload.ts @@ -0,0 +1,99 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { LoadContext, SaveContext } from "../context"; + +export class SessionWarningPayload { + static readonly shorthandProperty: string | undefined = undefined; + + warningType: string = ""; + message: string = ""; + details?: Record | undefined; + + constructor(init?: Partial) { + this.warningType = init?.warningType ?? ""; + this.message = init?.message ?? ""; + if (init?.details !== undefined) { + this.details = init.details; + } + } + + //#region Load Methods + + static load( + data: Record, + context?: LoadContext, + ): SessionWarningPayload { + if (context) { + data = context.processInput(data) as Record; + } + + const instance = new SessionWarningPayload(); + + if (data["warningType"] !== undefined && data["warningType"] !== null) { + instance.warningType = String(data["warningType"]); + } + if (data["message"] !== undefined && data["message"] !== null) { + instance.message = String(data["message"]); + } + if (data["details"] !== undefined && data["details"] !== null) { + instance.details = data["details"] as Record; + } + + if (context) { + return context.processOutput(instance) as SessionWarningPayload; + } + return instance; + } + + //#endregion + + //#region Save Methods + + save(context?: SaveContext): Record { + let obj: this = this; + if (context) { + obj = context.processObject(obj) as this; + } + + const result: Record = {}; + + if (obj.warningType !== undefined && obj.warningType !== null) { + result["warningType"] = obj.warningType; + } + if (obj.message !== undefined && obj.message !== null) { + result["message"] = obj.message; + } + if (obj.details !== undefined && obj.details !== null) { + result["details"] = obj.details; + } + + if (context) { + return context.processDict(result); + } + return result; + } + + toYaml(context?: SaveContext): string { + context = context ?? new SaveContext(); + return context.toYaml(this.save(context)); + } + + toJson(context?: SaveContext, indent: number = 2): string { + context = context ?? new SaveContext(); + return context.toJson(this.save(context), indent); + } + + static fromJson(json: string, context?: LoadContext): SessionWarningPayload { + const data = JSON.parse(json); + return SessionWarningPayload.load(data as Record, context); + } + + static fromYaml(yaml: string, context?: LoadContext): SessionWarningPayload { + const { parse } = require("yaml"); + const data = parse(yaml); + return SessionWarningPayload.load(data as Record, context); + } + + //#endregion +} diff --git a/runtime/typescript/packages/core/src/model/events/tool-execution-complete-payload.ts b/runtime/typescript/packages/core/src/model/events/tool-execution-complete-payload.ts new file mode 100644 index 00000000..124dd1f8 --- /dev/null +++ b/runtime/typescript/packages/core/src/model/events/tool-execution-complete-payload.ts @@ -0,0 +1,185 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { LoadContext, SaveContext } from "../context"; +import { RedactionMetadata } from "./redaction-metadata"; + +export class ToolExecutionCompletePayload { + static readonly shorthandProperty: string | undefined = undefined; + + requestId?: string | undefined; + toolCallId?: string | undefined; + toolName: string = ""; + success: boolean = false; + result?: unknown | undefined; + exitCode?: number | undefined; + durationMs?: number | undefined; + errorKind?: string | undefined; + telemetry?: Record | undefined; + redaction?: RedactionMetadata | undefined; + + constructor(init?: Partial) { + if (init?.requestId !== undefined) { + this.requestId = init.requestId; + } + if (init?.toolCallId !== undefined) { + this.toolCallId = init.toolCallId; + } + this.toolName = init?.toolName ?? ""; + this.success = init?.success ?? false; + if (init?.result !== undefined) { + this.result = init.result; + } + if (init?.exitCode !== undefined) { + this.exitCode = init.exitCode; + } + if (init?.durationMs !== undefined) { + this.durationMs = init.durationMs; + } + if (init?.errorKind !== undefined) { + this.errorKind = init.errorKind; + } + if (init?.telemetry !== undefined) { + this.telemetry = init.telemetry; + } + if (init?.redaction !== undefined) { + this.redaction = init.redaction; + } + } + + //#region Load Methods + + static load( + data: Record, + context?: LoadContext, + ): ToolExecutionCompletePayload { + if (context) { + data = context.processInput(data) as Record; + } + + const instance = new ToolExecutionCompletePayload(); + + if (data["requestId"] !== undefined && data["requestId"] !== null) { + instance.requestId = String(data["requestId"]); + } + if (data["toolCallId"] !== undefined && data["toolCallId"] !== null) { + instance.toolCallId = String(data["toolCallId"]); + } + if (data["toolName"] !== undefined && data["toolName"] !== null) { + instance.toolName = String(data["toolName"]); + } + if (data["success"] !== undefined && data["success"] !== null) { + instance.success = Boolean(data["success"]); + } + if (data["result"] !== undefined && data["result"] !== null) { + instance.result = data["result"] as unknown; + } + if (data["exitCode"] !== undefined && data["exitCode"] !== null) { + instance.exitCode = Number(data["exitCode"]); + } + if (data["durationMs"] !== undefined && data["durationMs"] !== null) { + instance.durationMs = Number(data["durationMs"]); + } + if (data["errorKind"] !== undefined && data["errorKind"] !== null) { + instance.errorKind = String(data["errorKind"]); + } + if (data["telemetry"] !== undefined && data["telemetry"] !== null) { + instance.telemetry = data["telemetry"] as Record; + } + if (data["redaction"] !== undefined && data["redaction"] !== null) { + instance.redaction = RedactionMetadata.load( + data["redaction"] as Record, + context, + ); + } + + if (context) { + return context.processOutput(instance) as ToolExecutionCompletePayload; + } + return instance; + } + + //#endregion + + //#region Save Methods + + save(context?: SaveContext): Record { + let obj: this = this; + if (context) { + obj = context.processObject(obj) as this; + } + + const result: Record = {}; + + if (obj.requestId !== undefined && obj.requestId !== null) { + result["requestId"] = obj.requestId; + } + if (obj.toolCallId !== undefined && obj.toolCallId !== null) { + result["toolCallId"] = obj.toolCallId; + } + if (obj.toolName !== undefined && obj.toolName !== null) { + result["toolName"] = obj.toolName; + } + if (obj.success !== undefined && obj.success !== null) { + result["success"] = obj.success; + } + if (obj.result !== undefined && obj.result !== null) { + result["result"] = obj.result; + } + if (obj.exitCode !== undefined && obj.exitCode !== null) { + result["exitCode"] = obj.exitCode; + } + if (obj.durationMs !== undefined && obj.durationMs !== null) { + result["durationMs"] = obj.durationMs; + } + if (obj.errorKind !== undefined && obj.errorKind !== null) { + result["errorKind"] = obj.errorKind; + } + if (obj.telemetry !== undefined && obj.telemetry !== null) { + result["telemetry"] = obj.telemetry; + } + if (obj.redaction !== undefined && obj.redaction !== null) { + result["redaction"] = obj.redaction.save(context); + } + + if (context) { + return context.processDict(result); + } + return result; + } + + toYaml(context?: SaveContext): string { + context = context ?? new SaveContext(); + return context.toYaml(this.save(context)); + } + + toJson(context?: SaveContext, indent: number = 2): string { + context = context ?? new SaveContext(); + return context.toJson(this.save(context), indent); + } + + static fromJson( + json: string, + context?: LoadContext, + ): ToolExecutionCompletePayload { + const data = JSON.parse(json); + return ToolExecutionCompletePayload.load( + data as Record, + context, + ); + } + + static fromYaml( + yaml: string, + context?: LoadContext, + ): ToolExecutionCompletePayload { + const { parse } = require("yaml"); + const data = parse(yaml); + return ToolExecutionCompletePayload.load( + data as Record, + context, + ); + } + + //#endregion +} diff --git a/runtime/typescript/packages/core/src/model/events/tool-execution-start-payload.ts b/runtime/typescript/packages/core/src/model/events/tool-execution-start-payload.ts new file mode 100644 index 00000000..14a7b7df --- /dev/null +++ b/runtime/typescript/packages/core/src/model/events/tool-execution-start-payload.ts @@ -0,0 +1,150 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { LoadContext, SaveContext } from "../context"; +import { RedactionMetadata } from "./redaction-metadata"; + +export class ToolExecutionStartPayload { + static readonly shorthandProperty: string | undefined = undefined; + + requestId?: string | undefined; + toolCallId?: string | undefined; + toolName: string = ""; + arguments?: Record | undefined; + workingDirectory?: string | undefined; + redaction?: RedactionMetadata | undefined; + + constructor(init?: Partial) { + if (init?.requestId !== undefined) { + this.requestId = init.requestId; + } + if (init?.toolCallId !== undefined) { + this.toolCallId = init.toolCallId; + } + this.toolName = init?.toolName ?? ""; + if (init?.arguments !== undefined) { + this.arguments = init.arguments; + } + if (init?.workingDirectory !== undefined) { + this.workingDirectory = init.workingDirectory; + } + if (init?.redaction !== undefined) { + this.redaction = init.redaction; + } + } + + //#region Load Methods + + static load( + data: Record, + context?: LoadContext, + ): ToolExecutionStartPayload { + if (context) { + data = context.processInput(data) as Record; + } + + const instance = new ToolExecutionStartPayload(); + + if (data["requestId"] !== undefined && data["requestId"] !== null) { + instance.requestId = String(data["requestId"]); + } + if (data["toolCallId"] !== undefined && data["toolCallId"] !== null) { + instance.toolCallId = String(data["toolCallId"]); + } + if (data["toolName"] !== undefined && data["toolName"] !== null) { + instance.toolName = String(data["toolName"]); + } + if (data["arguments"] !== undefined && data["arguments"] !== null) { + instance.arguments = data["arguments"] as Record; + } + if ( + data["workingDirectory"] !== undefined && + data["workingDirectory"] !== null + ) { + instance.workingDirectory = String(data["workingDirectory"]); + } + if (data["redaction"] !== undefined && data["redaction"] !== null) { + instance.redaction = RedactionMetadata.load( + data["redaction"] as Record, + context, + ); + } + + if (context) { + return context.processOutput(instance) as ToolExecutionStartPayload; + } + return instance; + } + + //#endregion + + //#region Save Methods + + save(context?: SaveContext): Record { + let obj: this = this; + if (context) { + obj = context.processObject(obj) as this; + } + + const result: Record = {}; + + if (obj.requestId !== undefined && obj.requestId !== null) { + result["requestId"] = obj.requestId; + } + if (obj.toolCallId !== undefined && obj.toolCallId !== null) { + result["toolCallId"] = obj.toolCallId; + } + if (obj.toolName !== undefined && obj.toolName !== null) { + result["toolName"] = obj.toolName; + } + if (obj.arguments !== undefined && obj.arguments !== null) { + result["arguments"] = obj.arguments; + } + if (obj.workingDirectory !== undefined && obj.workingDirectory !== null) { + result["workingDirectory"] = obj.workingDirectory; + } + if (obj.redaction !== undefined && obj.redaction !== null) { + result["redaction"] = obj.redaction.save(context); + } + + if (context) { + return context.processDict(result); + } + return result; + } + + toYaml(context?: SaveContext): string { + context = context ?? new SaveContext(); + return context.toYaml(this.save(context)); + } + + toJson(context?: SaveContext, indent: number = 2): string { + context = context ?? new SaveContext(); + return context.toJson(this.save(context), indent); + } + + static fromJson( + json: string, + context?: LoadContext, + ): ToolExecutionStartPayload { + const data = JSON.parse(json); + return ToolExecutionStartPayload.load( + data as Record, + context, + ); + } + + static fromYaml( + yaml: string, + context?: LoadContext, + ): ToolExecutionStartPayload { + const { parse } = require("yaml"); + const data = parse(yaml); + return ToolExecutionStartPayload.load( + data as Record, + context, + ); + } + + //#endregion +} diff --git a/runtime/typescript/packages/core/src/model/events/trajectory-event.ts b/runtime/typescript/packages/core/src/model/events/trajectory-event.ts new file mode 100644 index 00000000..ab15d277 --- /dev/null +++ b/runtime/typescript/packages/core/src/model/events/trajectory-event.ts @@ -0,0 +1,165 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { LoadContext, SaveContext } from "../context"; +import { RedactionMetadata } from "./redaction-metadata"; + +export class TrajectoryEvent { + static readonly shorthandProperty: string | undefined = undefined; + + id?: string | undefined; + sessionId?: string | undefined; + turnId?: string | undefined; + toolCallId?: string | undefined; + turnIndex?: number | undefined; + eventType: string = ""; + data?: Record | undefined; + createdAt?: string | undefined; + redaction?: RedactionMetadata | undefined; + + constructor(init?: Partial) { + if (init?.id !== undefined) { + this.id = init.id; + } + if (init?.sessionId !== undefined) { + this.sessionId = init.sessionId; + } + if (init?.turnId !== undefined) { + this.turnId = init.turnId; + } + if (init?.toolCallId !== undefined) { + this.toolCallId = init.toolCallId; + } + if (init?.turnIndex !== undefined) { + this.turnIndex = init.turnIndex; + } + this.eventType = init?.eventType ?? ""; + if (init?.data !== undefined) { + this.data = init.data; + } + if (init?.createdAt !== undefined) { + this.createdAt = init.createdAt; + } + if (init?.redaction !== undefined) { + this.redaction = init.redaction; + } + } + + //#region Load Methods + + static load( + data: Record, + context?: LoadContext, + ): TrajectoryEvent { + if (context) { + data = context.processInput(data) as Record; + } + + const instance = new TrajectoryEvent(); + + if (data["id"] !== undefined && data["id"] !== null) { + instance.id = String(data["id"]); + } + if (data["sessionId"] !== undefined && data["sessionId"] !== null) { + instance.sessionId = String(data["sessionId"]); + } + if (data["turnId"] !== undefined && data["turnId"] !== null) { + instance.turnId = String(data["turnId"]); + } + if (data["toolCallId"] !== undefined && data["toolCallId"] !== null) { + instance.toolCallId = String(data["toolCallId"]); + } + if (data["turnIndex"] !== undefined && data["turnIndex"] !== null) { + instance.turnIndex = Number(data["turnIndex"]); + } + if (data["eventType"] !== undefined && data["eventType"] !== null) { + instance.eventType = String(data["eventType"]); + } + if (data["data"] !== undefined && data["data"] !== null) { + instance.data = data["data"] as Record; + } + if (data["createdAt"] !== undefined && data["createdAt"] !== null) { + instance.createdAt = String(data["createdAt"]); + } + if (data["redaction"] !== undefined && data["redaction"] !== null) { + instance.redaction = RedactionMetadata.load( + data["redaction"] as Record, + context, + ); + } + + if (context) { + return context.processOutput(instance) as TrajectoryEvent; + } + return instance; + } + + //#endregion + + //#region Save Methods + + save(context?: SaveContext): Record { + let obj: this = this; + if (context) { + obj = context.processObject(obj) as this; + } + + const result: Record = {}; + + if (obj.id !== undefined && obj.id !== null) { + result["id"] = obj.id; + } + if (obj.sessionId !== undefined && obj.sessionId !== null) { + result["sessionId"] = obj.sessionId; + } + if (obj.turnId !== undefined && obj.turnId !== null) { + result["turnId"] = obj.turnId; + } + if (obj.toolCallId !== undefined && obj.toolCallId !== null) { + result["toolCallId"] = obj.toolCallId; + } + if (obj.turnIndex !== undefined && obj.turnIndex !== null) { + result["turnIndex"] = obj.turnIndex; + } + if (obj.eventType !== undefined && obj.eventType !== null) { + result["eventType"] = obj.eventType; + } + if (obj.data !== undefined && obj.data !== null) { + result["data"] = obj.data; + } + if (obj.createdAt !== undefined && obj.createdAt !== null) { + result["createdAt"] = obj.createdAt; + } + if (obj.redaction !== undefined && obj.redaction !== null) { + result["redaction"] = obj.redaction.save(context); + } + + if (context) { + return context.processDict(result); + } + return result; + } + + toYaml(context?: SaveContext): string { + context = context ?? new SaveContext(); + return context.toYaml(this.save(context)); + } + + toJson(context?: SaveContext, indent: number = 2): string { + context = context ?? new SaveContext(); + return context.toJson(this.save(context), indent); + } + + static fromJson(json: string, context?: LoadContext): TrajectoryEvent { + const data = JSON.parse(json); + return TrajectoryEvent.load(data as Record, context); + } + + static fromYaml(yaml: string, context?: LoadContext): TrajectoryEvent { + const { parse } = require("yaml"); + const data = parse(yaml); + return TrajectoryEvent.load(data as Record, context); + } + + //#endregion +} diff --git a/runtime/typescript/packages/core/src/model/events/turn-event.ts b/runtime/typescript/packages/core/src/model/events/turn-event.ts index 19219cc2..b30d1ce2 100644 --- a/runtime/typescript/packages/core/src/model/events/turn-event.ts +++ b/runtime/typescript/packages/core/src/model/events/turn-event.ts @@ -15,7 +15,11 @@ export type TurnEventType = | "thinking" | "tool_call_start" | "tool_call_complete" + | "tool_execution_start" + | "tool_execution_complete" | "tool_result" + | "hook_start" + | "hook_end" | "status" | "messages_updated" | "done" diff --git a/runtime/typescript/packages/core/src/model/index.ts b/runtime/typescript/packages/core/src/model/index.ts index 66442384..86ff1cd5 100644 --- a/runtime/typescript/packages/core/src/model/index.ts +++ b/runtime/typescript/packages/core/src/model/index.ts @@ -40,12 +40,22 @@ export { TurnEndPayload } from "./events/turn-end-payload"; export { LlmStartPayload } from "./events/llm-start-payload"; export { LlmCompletePayload } from "./events/llm-complete-payload"; export { RetryPayload } from "./events/retry-payload"; +export { RedactedField } from "./events/redacted-field"; +export { RedactionMetadata } from "./events/redaction-metadata"; export { PermissionRequestedPayload } from "./events/permission-requested-payload"; export { PermissionCompletedPayload } from "./events/permission-completed-payload"; +export { PermissionRequest } from "./events/permission-request"; +export { PermissionDecision } from "./events/permission-decision"; export { TokenEventPayload } from "./events/token-event-payload"; export { ThinkingEventPayload } from "./events/thinking-event-payload"; export { ToolCallStartPayload } from "./events/tool-call-start-payload"; export { ToolCallCompletePayload } from "./events/tool-call-complete-payload"; +export { ToolExecutionStartPayload } from "./events/tool-execution-start-payload"; +export { ToolExecutionCompletePayload } from "./events/tool-execution-complete-payload"; +export { HostToolRequest } from "./events/host-tool-request"; +export { HostToolResult } from "./events/host-tool-result"; +export { HookStartPayload } from "./events/hook-start-payload"; +export { HookEndPayload } from "./events/hook-end-payload"; export { ToolResultPayload } from "./events/tool-result-payload"; export { StatusEventPayload } from "./events/status-event-payload"; export { MessagesUpdatedPayload } from "./events/messages-updated-payload"; @@ -56,6 +66,17 @@ export { CompactionCompletePayload } from "./events/compaction-complete-payload" export { CompactionFailedPayload } from "./events/compaction-failed-payload"; export { TurnSummary } from "./events/turn-summary"; export { TurnTrace } from "./events/turn-trace"; +export { HarnessContext } from "./events/harness-context"; +export { SessionStartPayload } from "./events/session-start-payload"; +export { SessionEndPayload } from "./events/session-end-payload"; +export { SessionWarningPayload } from "./events/session-warning-payload"; +export { SessionEvent } from "./events/session-event"; +export { Checkpoint } from "./events/checkpoint"; +export { TrajectoryEvent } from "./events/trajectory-event"; +export { SessionFileRef } from "./events/session-file-ref"; +export { SessionRef } from "./events/session-ref"; +export { SessionSummary } from "./events/session-summary"; +export { SessionTrace } from "./events/session-trace"; export { StreamChunk, TextChunk, @@ -75,6 +96,11 @@ export type { Renderer } from "./pipeline/renderer"; export type { Parser } from "./pipeline/parser"; export type { Executor } from "./pipeline/executor"; export type { Processor } from "./pipeline/processor"; +export type { EventSink } from "./pipeline/event-sink"; +export type { TraceWriter } from "./pipeline/trace-writer"; +export type { PermissionResolver } from "./pipeline/permission-resolver"; +export type { CheckpointStore } from "./pipeline/checkpoint-store"; +export type { HostToolExecutor } from "./pipeline/host-tool-executor"; export { StreamOptions } from "./streaming/stream-options"; diff --git a/runtime/typescript/packages/core/src/model/pipeline/checkpoint-store.ts b/runtime/typescript/packages/core/src/model/pipeline/checkpoint-store.ts new file mode 100644 index 00000000..f05ee30d --- /dev/null +++ b/runtime/typescript/packages/core/src/model/pipeline/checkpoint-store.ts @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { Checkpoint } from "../events/checkpoint"; + +/** Stores and retrieves resumable session checkpoints. */ +export interface CheckpointStore { + /** Persist a session checkpoint and return the stored checkpoint */ + save(checkpoint: Checkpoint): Promise; + /** Load a checkpoint by session and checkpoint identifier */ + load(sessionId: string, checkpointId: string): Promise; + /** List checkpoints for a session */ + listCheckpoints(sessionId: string): Promise; +} diff --git a/runtime/typescript/packages/core/src/model/pipeline/event-sink.ts b/runtime/typescript/packages/core/src/model/pipeline/event-sink.ts new file mode 100644 index 00000000..9666d03a --- /dev/null +++ b/runtime/typescript/packages/core/src/model/pipeline/event-sink.ts @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { SessionEvent } from "../events/session-event"; +import { TurnEvent } from "../events/turn-event"; + +/** Receives typed turn and session events from a harness. */ +export interface EventSink { + /** Emit a typed turn event to a host sink */ + emitTurn(turnEvent: TurnEvent): boolean; + /** Emit a typed session event to a host sink */ + emitSession(sessionEvent: SessionEvent): boolean; +} diff --git a/runtime/typescript/packages/core/src/model/pipeline/host-tool-executor.ts b/runtime/typescript/packages/core/src/model/pipeline/host-tool-executor.ts new file mode 100644 index 00000000..e2456f33 --- /dev/null +++ b/runtime/typescript/packages/core/src/model/pipeline/host-tool-executor.ts @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { HostToolRequest } from "../events/host-tool-request"; +import { HostToolResult } from "../events/host-tool-result"; + +/** Executes host tools after policy and permission checks. */ +export interface HostToolExecutor { + /** Execute a concrete host tool request and return its completion payload */ + execute(request: HostToolRequest): Promise; +} diff --git a/runtime/typescript/packages/core/src/model/pipeline/index.ts b/runtime/typescript/packages/core/src/model/pipeline/index.ts index 269fd9d4..c44e4018 100644 --- a/runtime/typescript/packages/core/src/model/pipeline/index.ts +++ b/runtime/typescript/packages/core/src/model/pipeline/index.ts @@ -7,3 +7,8 @@ export type { Renderer } from "./renderer"; export type { Parser } from "./parser"; export type { Executor } from "./executor"; export type { Processor } from "./processor"; +export type { EventSink } from "./event-sink"; +export type { TraceWriter } from "./trace-writer"; +export type { PermissionResolver } from "./permission-resolver"; +export type { CheckpointStore } from "./checkpoint-store"; +export type { HostToolExecutor } from "./host-tool-executor"; diff --git a/runtime/typescript/packages/core/src/model/pipeline/permission-resolver.ts b/runtime/typescript/packages/core/src/model/pipeline/permission-resolver.ts new file mode 100644 index 00000000..1e32c3a0 --- /dev/null +++ b/runtime/typescript/packages/core/src/model/pipeline/permission-resolver.ts @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { PermissionDecision } from "../events/permission-decision"; +import { PermissionRequest } from "../events/permission-request"; + +/** Resolves host permission requests for potentially sensitive actions. */ +export interface PermissionResolver { + /** Resolve a host permission request */ + request(request: PermissionRequest): Promise; +} diff --git a/runtime/typescript/packages/core/src/model/pipeline/trace-writer.ts b/runtime/typescript/packages/core/src/model/pipeline/trace-writer.ts new file mode 100644 index 00000000..05a69803 --- /dev/null +++ b/runtime/typescript/packages/core/src/model/pipeline/trace-writer.ts @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { SessionEvent } from "../events/session-event"; +import { SessionSummary } from "../events/session-summary"; +import { TurnEvent } from "../events/turn-event"; + +/** Persists typed events to a replayable trace. */ +export interface TraceWriter { + /** Append a turn event to a replayable trace */ + appendTurn(turnEvent: TurnEvent): boolean; + /** Append a session event to a replayable trace */ + appendSession(sessionEvent: SessionEvent): boolean; + /** Finalize the trace with an optional session summary */ + close(summary: SessionSummary | null): boolean; +} diff --git a/runtime/typescript/packages/core/tests/model/events/checkpoint.test.ts b/runtime/typescript/packages/core/tests/model/events/checkpoint.test.ts new file mode 100644 index 00000000..2eb4115b --- /dev/null +++ b/runtime/typescript/packages/core/tests/model/events/checkpoint.test.ts @@ -0,0 +1,87 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { Checkpoint } from "../../../src/model/index"; + +describe("Checkpoint", () => { + describe("construction", () => { + it("should create a new instance with defaults", () => { + const instance = new Checkpoint(); + expect(instance).toBeDefined(); + }); + + it("should create a new instance with partial initialization", () => { + const instance = new Checkpoint({}); + expect(instance).toBeDefined(); + }); + }); + + describe("JSON serialization", () => { + it("should load from JSON - example 1", () => { + const json = `{\n "id": "chk_abc123",\n "sessionId": "sess_abc123",\n "turnId": "turn_001",\n "checkpointNumber": 3,\n "title": "Added harness contracts",\n "createdAt": "2026-06-09T20:00:00Z"\n}`; + const instance = Checkpoint.fromJson(json); + expect(instance).toBeDefined(); + expect(instance.id).toEqual("chk_abc123"); + expect(instance.sessionId).toEqual("sess_abc123"); + expect(instance.turnId).toEqual("turn_001"); + expect(instance.checkpointNumber).toEqual(3); + expect(instance.title).toEqual("Added harness contracts"); + expect(instance.createdAt).toEqual("2026-06-09T20:00:00Z"); + }); + + it("should round-trip JSON - example 1", () => { + const json = `{\n "id": "chk_abc123",\n "sessionId": "sess_abc123",\n "turnId": "turn_001",\n "checkpointNumber": 3,\n "title": "Added harness contracts",\n "createdAt": "2026-06-09T20:00:00Z"\n}`; + const instance = Checkpoint.fromJson(json); + const output = instance.toJson(); + const reloaded = Checkpoint.fromJson(output); + expect(reloaded.id).toEqual(instance.id); + expect(reloaded.sessionId).toEqual(instance.sessionId); + expect(reloaded.turnId).toEqual(instance.turnId); + expect(reloaded.checkpointNumber).toEqual(instance.checkpointNumber); + expect(reloaded.title).toEqual(instance.title); + expect(reloaded.createdAt).toEqual(instance.createdAt); + }); + }); + + describe("YAML serialization", () => { + it("should load from YAML - example 1", () => { + const yaml = `id: chk_abc123\nsessionId: sess_abc123\nturnId: turn_001\ncheckpointNumber: 3\ntitle: Added harness contracts\ncreatedAt: "2026-06-09T20:00:00Z"\n`; + const instance = Checkpoint.fromYaml(yaml); + expect(instance).toBeDefined(); + expect(instance.id).toEqual("chk_abc123"); + expect(instance.sessionId).toEqual("sess_abc123"); + expect(instance.turnId).toEqual("turn_001"); + expect(instance.checkpointNumber).toEqual(3); + expect(instance.title).toEqual("Added harness contracts"); + expect(instance.createdAt).toEqual("2026-06-09T20:00:00Z"); + }); + + it("should round-trip YAML - example 1", () => { + const yaml = `id: chk_abc123\nsessionId: sess_abc123\nturnId: turn_001\ncheckpointNumber: 3\ntitle: Added harness contracts\ncreatedAt: "2026-06-09T20:00:00Z"\n`; + const instance = Checkpoint.fromYaml(yaml); + const output = instance.toYaml(); + const reloaded = Checkpoint.fromYaml(output); + expect(reloaded.id).toEqual(instance.id); + expect(reloaded.sessionId).toEqual(instance.sessionId); + expect(reloaded.turnId).toEqual(instance.turnId); + expect(reloaded.checkpointNumber).toEqual(instance.checkpointNumber); + expect(reloaded.title).toEqual(instance.title); + expect(reloaded.createdAt).toEqual(instance.createdAt); + }); + }); + + describe("load and save", () => { + it("should load from dictionary", () => { + const data: Record = {}; + const instance = Checkpoint.load(data); + expect(instance).toBeDefined(); + }); + + it("should save to dictionary", () => { + const instance = new Checkpoint(); + const data = instance.save(); + expect(data).toBeDefined(); + expect(typeof data).toBe("object"); + }); + }); +}); diff --git a/runtime/typescript/packages/core/tests/model/events/harness-context.test.ts b/runtime/typescript/packages/core/tests/model/events/harness-context.test.ts new file mode 100644 index 00000000..0f0359c2 --- /dev/null +++ b/runtime/typescript/packages/core/tests/model/events/harness-context.test.ts @@ -0,0 +1,71 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { HarnessContext } from "../../../src/model/index"; + +describe("HarnessContext", () => { + describe("construction", () => { + it("should create a new instance with defaults", () => { + const instance = new HarnessContext(); + expect(instance).toBeDefined(); + }); + + it("should create a new instance with partial initialization", () => { + const instance = new HarnessContext({}); + expect(instance).toBeDefined(); + }); + }); + + describe("JSON serialization", () => { + it("should load from JSON - example 1", () => { + const json = `{\n "cwd": "/workspace/project",\n "gitRoot": "/workspace/project"\n}`; + const instance = HarnessContext.fromJson(json); + expect(instance).toBeDefined(); + expect(instance.cwd).toEqual("/workspace/project"); + expect(instance.gitRoot).toEqual("/workspace/project"); + }); + + it("should round-trip JSON - example 1", () => { + const json = `{\n "cwd": "/workspace/project",\n "gitRoot": "/workspace/project"\n}`; + const instance = HarnessContext.fromJson(json); + const output = instance.toJson(); + const reloaded = HarnessContext.fromJson(output); + expect(reloaded.cwd).toEqual(instance.cwd); + expect(reloaded.gitRoot).toEqual(instance.gitRoot); + }); + }); + + describe("YAML serialization", () => { + it("should load from YAML - example 1", () => { + const yaml = `cwd: /workspace/project\ngitRoot: /workspace/project\n`; + const instance = HarnessContext.fromYaml(yaml); + expect(instance).toBeDefined(); + expect(instance.cwd).toEqual("/workspace/project"); + expect(instance.gitRoot).toEqual("/workspace/project"); + }); + + it("should round-trip YAML - example 1", () => { + const yaml = `cwd: /workspace/project\ngitRoot: /workspace/project\n`; + const instance = HarnessContext.fromYaml(yaml); + const output = instance.toYaml(); + const reloaded = HarnessContext.fromYaml(output); + expect(reloaded.cwd).toEqual(instance.cwd); + expect(reloaded.gitRoot).toEqual(instance.gitRoot); + }); + }); + + describe("load and save", () => { + it("should load from dictionary", () => { + const data: Record = {}; + const instance = HarnessContext.load(data); + expect(instance).toBeDefined(); + }); + + it("should save to dictionary", () => { + const instance = new HarnessContext(); + const data = instance.save(); + expect(data).toBeDefined(); + expect(typeof data).toBe("object"); + }); + }); +}); diff --git a/runtime/typescript/packages/core/tests/model/events/hook-end-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/hook-end-payload.test.ts new file mode 100644 index 00000000..de9bb3b8 --- /dev/null +++ b/runtime/typescript/packages/core/tests/model/events/hook-end-payload.test.ts @@ -0,0 +1,83 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { HookEndPayload } from "../../../src/model/index"; + +describe("HookEndPayload", () => { + describe("construction", () => { + it("should create a new instance with defaults", () => { + const instance = new HookEndPayload(); + expect(instance).toBeDefined(); + }); + + it("should create a new instance with partial initialization", () => { + const instance = new HookEndPayload({}); + expect(instance).toBeDefined(); + }); + }); + + describe("JSON serialization", () => { + it("should load from JSON - example 1", () => { + const json = `{\n "hookInvocationId": "hook_abc123",\n "hookType": "preToolUse",\n "success": true,\n "durationMs": 12,\n "error": "hook failed"\n}`; + const instance = HookEndPayload.fromJson(json); + expect(instance).toBeDefined(); + expect(instance.hookInvocationId).toEqual("hook_abc123"); + expect(instance.hookType).toEqual("preToolUse"); + expect(instance.success).toEqual(true); + expect(instance.durationMs).toEqual(12); + expect(instance.error).toEqual("hook failed"); + }); + + it("should round-trip JSON - example 1", () => { + const json = `{\n "hookInvocationId": "hook_abc123",\n "hookType": "preToolUse",\n "success": true,\n "durationMs": 12,\n "error": "hook failed"\n}`; + const instance = HookEndPayload.fromJson(json); + const output = instance.toJson(); + const reloaded = HookEndPayload.fromJson(output); + expect(reloaded.hookInvocationId).toEqual(instance.hookInvocationId); + expect(reloaded.hookType).toEqual(instance.hookType); + expect(reloaded.success).toEqual(instance.success); + expect(reloaded.durationMs).toEqual(instance.durationMs); + expect(reloaded.error).toEqual(instance.error); + }); + }); + + describe("YAML serialization", () => { + it("should load from YAML - example 1", () => { + const yaml = `hookInvocationId: hook_abc123\nhookType: preToolUse\nsuccess: true\ndurationMs: 12\nerror: hook failed\n`; + const instance = HookEndPayload.fromYaml(yaml); + expect(instance).toBeDefined(); + expect(instance.hookInvocationId).toEqual("hook_abc123"); + expect(instance.hookType).toEqual("preToolUse"); + expect(instance.success).toEqual(true); + expect(instance.durationMs).toEqual(12); + expect(instance.error).toEqual("hook failed"); + }); + + it("should round-trip YAML - example 1", () => { + const yaml = `hookInvocationId: hook_abc123\nhookType: preToolUse\nsuccess: true\ndurationMs: 12\nerror: hook failed\n`; + const instance = HookEndPayload.fromYaml(yaml); + const output = instance.toYaml(); + const reloaded = HookEndPayload.fromYaml(output); + expect(reloaded.hookInvocationId).toEqual(instance.hookInvocationId); + expect(reloaded.hookType).toEqual(instance.hookType); + expect(reloaded.success).toEqual(instance.success); + expect(reloaded.durationMs).toEqual(instance.durationMs); + expect(reloaded.error).toEqual(instance.error); + }); + }); + + describe("load and save", () => { + it("should load from dictionary", () => { + const data: Record = {}; + const instance = HookEndPayload.load(data); + expect(instance).toBeDefined(); + }); + + it("should save to dictionary", () => { + const instance = new HookEndPayload(); + const data = instance.save(); + expect(data).toBeDefined(); + expect(typeof data).toBe("object"); + }); + }); +}); diff --git a/runtime/typescript/packages/core/tests/model/events/hook-start-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/hook-start-payload.test.ts new file mode 100644 index 00000000..772b0099 --- /dev/null +++ b/runtime/typescript/packages/core/tests/model/events/hook-start-payload.test.ts @@ -0,0 +1,71 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { HookStartPayload } from "../../../src/model/index"; + +describe("HookStartPayload", () => { + describe("construction", () => { + it("should create a new instance with defaults", () => { + const instance = new HookStartPayload(); + expect(instance).toBeDefined(); + }); + + it("should create a new instance with partial initialization", () => { + const instance = new HookStartPayload({}); + expect(instance).toBeDefined(); + }); + }); + + describe("JSON serialization", () => { + it("should load from JSON - example 1", () => { + const json = `{\n "hookInvocationId": "hook_abc123",\n "hookType": "preToolUse"\n}`; + const instance = HookStartPayload.fromJson(json); + expect(instance).toBeDefined(); + expect(instance.hookInvocationId).toEqual("hook_abc123"); + expect(instance.hookType).toEqual("preToolUse"); + }); + + it("should round-trip JSON - example 1", () => { + const json = `{\n "hookInvocationId": "hook_abc123",\n "hookType": "preToolUse"\n}`; + const instance = HookStartPayload.fromJson(json); + const output = instance.toJson(); + const reloaded = HookStartPayload.fromJson(output); + expect(reloaded.hookInvocationId).toEqual(instance.hookInvocationId); + expect(reloaded.hookType).toEqual(instance.hookType); + }); + }); + + describe("YAML serialization", () => { + it("should load from YAML - example 1", () => { + const yaml = `hookInvocationId: hook_abc123\nhookType: preToolUse\n`; + const instance = HookStartPayload.fromYaml(yaml); + expect(instance).toBeDefined(); + expect(instance.hookInvocationId).toEqual("hook_abc123"); + expect(instance.hookType).toEqual("preToolUse"); + }); + + it("should round-trip YAML - example 1", () => { + const yaml = `hookInvocationId: hook_abc123\nhookType: preToolUse\n`; + const instance = HookStartPayload.fromYaml(yaml); + const output = instance.toYaml(); + const reloaded = HookStartPayload.fromYaml(output); + expect(reloaded.hookInvocationId).toEqual(instance.hookInvocationId); + expect(reloaded.hookType).toEqual(instance.hookType); + }); + }); + + describe("load and save", () => { + it("should load from dictionary", () => { + const data: Record = {}; + const instance = HookStartPayload.load(data); + expect(instance).toBeDefined(); + }); + + it("should save to dictionary", () => { + const instance = new HookStartPayload(); + const data = instance.save(); + expect(data).toBeDefined(); + expect(typeof data).toBe("object"); + }); + }); +}); diff --git a/runtime/typescript/packages/core/tests/model/events/host-tool-request.test.ts b/runtime/typescript/packages/core/tests/model/events/host-tool-request.test.ts new file mode 100644 index 00000000..76c03450 --- /dev/null +++ b/runtime/typescript/packages/core/tests/model/events/host-tool-request.test.ts @@ -0,0 +1,79 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { HostToolRequest } from "../../../src/model/index"; + +describe("HostToolRequest", () => { + describe("construction", () => { + it("should create a new instance with defaults", () => { + const instance = new HostToolRequest(); + expect(instance).toBeDefined(); + }); + + it("should create a new instance with partial initialization", () => { + const instance = new HostToolRequest({}); + expect(instance).toBeDefined(); + }); + }); + + describe("JSON serialization", () => { + it("should load from JSON - example 1", () => { + const json = `{\n "requestId": "exec_abc123",\n "toolCallId": "call_abc123",\n "toolName": "powershell",\n "workingDirectory": "/workspace/project"\n}`; + const instance = HostToolRequest.fromJson(json); + expect(instance).toBeDefined(); + expect(instance.requestId).toEqual("exec_abc123"); + expect(instance.toolCallId).toEqual("call_abc123"); + expect(instance.toolName).toEqual("powershell"); + expect(instance.workingDirectory).toEqual("/workspace/project"); + }); + + it("should round-trip JSON - example 1", () => { + const json = `{\n "requestId": "exec_abc123",\n "toolCallId": "call_abc123",\n "toolName": "powershell",\n "workingDirectory": "/workspace/project"\n}`; + const instance = HostToolRequest.fromJson(json); + const output = instance.toJson(); + const reloaded = HostToolRequest.fromJson(output); + expect(reloaded.requestId).toEqual(instance.requestId); + expect(reloaded.toolCallId).toEqual(instance.toolCallId); + expect(reloaded.toolName).toEqual(instance.toolName); + expect(reloaded.workingDirectory).toEqual(instance.workingDirectory); + }); + }); + + describe("YAML serialization", () => { + it("should load from YAML - example 1", () => { + const yaml = `requestId: exec_abc123\ntoolCallId: call_abc123\ntoolName: powershell\nworkingDirectory: /workspace/project\n`; + const instance = HostToolRequest.fromYaml(yaml); + expect(instance).toBeDefined(); + expect(instance.requestId).toEqual("exec_abc123"); + expect(instance.toolCallId).toEqual("call_abc123"); + expect(instance.toolName).toEqual("powershell"); + expect(instance.workingDirectory).toEqual("/workspace/project"); + }); + + it("should round-trip YAML - example 1", () => { + const yaml = `requestId: exec_abc123\ntoolCallId: call_abc123\ntoolName: powershell\nworkingDirectory: /workspace/project\n`; + const instance = HostToolRequest.fromYaml(yaml); + const output = instance.toYaml(); + const reloaded = HostToolRequest.fromYaml(output); + expect(reloaded.requestId).toEqual(instance.requestId); + expect(reloaded.toolCallId).toEqual(instance.toolCallId); + expect(reloaded.toolName).toEqual(instance.toolName); + expect(reloaded.workingDirectory).toEqual(instance.workingDirectory); + }); + }); + + describe("load and save", () => { + it("should load from dictionary", () => { + const data: Record = {}; + const instance = HostToolRequest.load(data); + expect(instance).toBeDefined(); + }); + + it("should save to dictionary", () => { + const instance = new HostToolRequest(); + const data = instance.save(); + expect(data).toBeDefined(); + expect(typeof data).toBe("object"); + }); + }); +}); diff --git a/runtime/typescript/packages/core/tests/model/events/host-tool-result.test.ts b/runtime/typescript/packages/core/tests/model/events/host-tool-result.test.ts new file mode 100644 index 00000000..e6e200f1 --- /dev/null +++ b/runtime/typescript/packages/core/tests/model/events/host-tool-result.test.ts @@ -0,0 +1,91 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { HostToolResult } from "../../../src/model/index"; + +describe("HostToolResult", () => { + describe("construction", () => { + it("should create a new instance with defaults", () => { + const instance = new HostToolResult(); + expect(instance).toBeDefined(); + }); + + it("should create a new instance with partial initialization", () => { + const instance = new HostToolResult({}); + expect(instance).toBeDefined(); + }); + }); + + describe("JSON serialization", () => { + it("should load from JSON - example 1", () => { + const json = `{\n "requestId": "exec_abc123",\n "toolCallId": "call_abc123",\n "toolName": "powershell",\n "success": true,\n "exitCode": 0,\n "durationMs": 250,\n "errorKind": "timeout"\n}`; + const instance = HostToolResult.fromJson(json); + expect(instance).toBeDefined(); + expect(instance.requestId).toEqual("exec_abc123"); + expect(instance.toolCallId).toEqual("call_abc123"); + expect(instance.toolName).toEqual("powershell"); + expect(instance.success).toEqual(true); + expect(instance.exitCode).toEqual(0); + expect(instance.durationMs).toEqual(250); + expect(instance.errorKind).toEqual("timeout"); + }); + + it("should round-trip JSON - example 1", () => { + const json = `{\n "requestId": "exec_abc123",\n "toolCallId": "call_abc123",\n "toolName": "powershell",\n "success": true,\n "exitCode": 0,\n "durationMs": 250,\n "errorKind": "timeout"\n}`; + const instance = HostToolResult.fromJson(json); + const output = instance.toJson(); + const reloaded = HostToolResult.fromJson(output); + expect(reloaded.requestId).toEqual(instance.requestId); + expect(reloaded.toolCallId).toEqual(instance.toolCallId); + expect(reloaded.toolName).toEqual(instance.toolName); + expect(reloaded.success).toEqual(instance.success); + expect(reloaded.exitCode).toEqual(instance.exitCode); + expect(reloaded.durationMs).toEqual(instance.durationMs); + expect(reloaded.errorKind).toEqual(instance.errorKind); + }); + }); + + describe("YAML serialization", () => { + it("should load from YAML - example 1", () => { + const yaml = `requestId: exec_abc123\ntoolCallId: call_abc123\ntoolName: powershell\nsuccess: true\nexitCode: 0\ndurationMs: 250\nerrorKind: timeout\n`; + const instance = HostToolResult.fromYaml(yaml); + expect(instance).toBeDefined(); + expect(instance.requestId).toEqual("exec_abc123"); + expect(instance.toolCallId).toEqual("call_abc123"); + expect(instance.toolName).toEqual("powershell"); + expect(instance.success).toEqual(true); + expect(instance.exitCode).toEqual(0); + expect(instance.durationMs).toEqual(250); + expect(instance.errorKind).toEqual("timeout"); + }); + + it("should round-trip YAML - example 1", () => { + const yaml = `requestId: exec_abc123\ntoolCallId: call_abc123\ntoolName: powershell\nsuccess: true\nexitCode: 0\ndurationMs: 250\nerrorKind: timeout\n`; + const instance = HostToolResult.fromYaml(yaml); + const output = instance.toYaml(); + const reloaded = HostToolResult.fromYaml(output); + expect(reloaded.requestId).toEqual(instance.requestId); + expect(reloaded.toolCallId).toEqual(instance.toolCallId); + expect(reloaded.toolName).toEqual(instance.toolName); + expect(reloaded.success).toEqual(instance.success); + expect(reloaded.exitCode).toEqual(instance.exitCode); + expect(reloaded.durationMs).toEqual(instance.durationMs); + expect(reloaded.errorKind).toEqual(instance.errorKind); + }); + }); + + describe("load and save", () => { + it("should load from dictionary", () => { + const data: Record = {}; + const instance = HostToolResult.load(data); + expect(instance).toBeDefined(); + }); + + it("should save to dictionary", () => { + const instance = new HostToolResult(); + const data = instance.save(); + expect(data).toBeDefined(); + expect(typeof data).toBe("object"); + }); + }); +}); diff --git a/runtime/typescript/packages/core/tests/model/events/permission-completed-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/permission-completed-payload.test.ts index 8d450523..20f1c55a 100644 --- a/runtime/typescript/packages/core/tests/model/events/permission-completed-payload.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/permission-completed-payload.test.ts @@ -18,19 +18,23 @@ describe("PermissionCompletedPayload", () => { describe("JSON serialization", () => { it("should load from JSON - example 1", () => { - const json = `{\n "permission": "tool.execute",\n "approved": true,\n "reason": "user_approved"\n}`; + const json = `{\n "requestId": "perm_abc123",\n "toolCallId": "call_abc123",\n "permission": "tool.execute",\n "approved": true,\n "reason": "user_approved"\n}`; const instance = PermissionCompletedPayload.fromJson(json); expect(instance).toBeDefined(); + expect(instance.requestId).toEqual("perm_abc123"); + expect(instance.toolCallId).toEqual("call_abc123"); expect(instance.permission).toEqual("tool.execute"); expect(instance.approved).toEqual(true); expect(instance.reason).toEqual("user_approved"); }); it("should round-trip JSON - example 1", () => { - const json = `{\n "permission": "tool.execute",\n "approved": true,\n "reason": "user_approved"\n}`; + const json = `{\n "requestId": "perm_abc123",\n "toolCallId": "call_abc123",\n "permission": "tool.execute",\n "approved": true,\n "reason": "user_approved"\n}`; const instance = PermissionCompletedPayload.fromJson(json); const output = instance.toJson(); const reloaded = PermissionCompletedPayload.fromJson(output); + expect(reloaded.requestId).toEqual(instance.requestId); + expect(reloaded.toolCallId).toEqual(instance.toolCallId); expect(reloaded.permission).toEqual(instance.permission); expect(reloaded.approved).toEqual(instance.approved); expect(reloaded.reason).toEqual(instance.reason); @@ -39,19 +43,23 @@ describe("PermissionCompletedPayload", () => { describe("YAML serialization", () => { it("should load from YAML - example 1", () => { - const yaml = `permission: tool.execute\napproved: true\nreason: user_approved\n`; + const yaml = `requestId: perm_abc123\ntoolCallId: call_abc123\npermission: tool.execute\napproved: true\nreason: user_approved\n`; const instance = PermissionCompletedPayload.fromYaml(yaml); expect(instance).toBeDefined(); + expect(instance.requestId).toEqual("perm_abc123"); + expect(instance.toolCallId).toEqual("call_abc123"); expect(instance.permission).toEqual("tool.execute"); expect(instance.approved).toEqual(true); expect(instance.reason).toEqual("user_approved"); }); it("should round-trip YAML - example 1", () => { - const yaml = `permission: tool.execute\napproved: true\nreason: user_approved\n`; + const yaml = `requestId: perm_abc123\ntoolCallId: call_abc123\npermission: tool.execute\napproved: true\nreason: user_approved\n`; const instance = PermissionCompletedPayload.fromYaml(yaml); const output = instance.toYaml(); const reloaded = PermissionCompletedPayload.fromYaml(output); + expect(reloaded.requestId).toEqual(instance.requestId); + expect(reloaded.toolCallId).toEqual(instance.toolCallId); expect(reloaded.permission).toEqual(instance.permission); expect(reloaded.approved).toEqual(instance.approved); expect(reloaded.reason).toEqual(instance.reason); diff --git a/runtime/typescript/packages/core/tests/model/events/permission-decision.test.ts b/runtime/typescript/packages/core/tests/model/events/permission-decision.test.ts new file mode 100644 index 00000000..7d14694c --- /dev/null +++ b/runtime/typescript/packages/core/tests/model/events/permission-decision.test.ts @@ -0,0 +1,83 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { PermissionDecision } from "../../../src/model/index"; + +describe("PermissionDecision", () => { + describe("construction", () => { + it("should create a new instance with defaults", () => { + const instance = new PermissionDecision(); + expect(instance).toBeDefined(); + }); + + it("should create a new instance with partial initialization", () => { + const instance = new PermissionDecision({}); + expect(instance).toBeDefined(); + }); + }); + + describe("JSON serialization", () => { + it("should load from JSON - example 1", () => { + const json = `{\n "requestId": "perm_abc123",\n "toolCallId": "call_abc123",\n "permission": "tool.execute",\n "approved": true,\n "reason": "user_approved"\n}`; + const instance = PermissionDecision.fromJson(json); + expect(instance).toBeDefined(); + expect(instance.requestId).toEqual("perm_abc123"); + expect(instance.toolCallId).toEqual("call_abc123"); + expect(instance.permission).toEqual("tool.execute"); + expect(instance.approved).toEqual(true); + expect(instance.reason).toEqual("user_approved"); + }); + + it("should round-trip JSON - example 1", () => { + const json = `{\n "requestId": "perm_abc123",\n "toolCallId": "call_abc123",\n "permission": "tool.execute",\n "approved": true,\n "reason": "user_approved"\n}`; + const instance = PermissionDecision.fromJson(json); + const output = instance.toJson(); + const reloaded = PermissionDecision.fromJson(output); + expect(reloaded.requestId).toEqual(instance.requestId); + expect(reloaded.toolCallId).toEqual(instance.toolCallId); + expect(reloaded.permission).toEqual(instance.permission); + expect(reloaded.approved).toEqual(instance.approved); + expect(reloaded.reason).toEqual(instance.reason); + }); + }); + + describe("YAML serialization", () => { + it("should load from YAML - example 1", () => { + const yaml = `requestId: perm_abc123\ntoolCallId: call_abc123\npermission: tool.execute\napproved: true\nreason: user_approved\n`; + const instance = PermissionDecision.fromYaml(yaml); + expect(instance).toBeDefined(); + expect(instance.requestId).toEqual("perm_abc123"); + expect(instance.toolCallId).toEqual("call_abc123"); + expect(instance.permission).toEqual("tool.execute"); + expect(instance.approved).toEqual(true); + expect(instance.reason).toEqual("user_approved"); + }); + + it("should round-trip YAML - example 1", () => { + const yaml = `requestId: perm_abc123\ntoolCallId: call_abc123\npermission: tool.execute\napproved: true\nreason: user_approved\n`; + const instance = PermissionDecision.fromYaml(yaml); + const output = instance.toYaml(); + const reloaded = PermissionDecision.fromYaml(output); + expect(reloaded.requestId).toEqual(instance.requestId); + expect(reloaded.toolCallId).toEqual(instance.toolCallId); + expect(reloaded.permission).toEqual(instance.permission); + expect(reloaded.approved).toEqual(instance.approved); + expect(reloaded.reason).toEqual(instance.reason); + }); + }); + + describe("load and save", () => { + it("should load from dictionary", () => { + const data: Record = {}; + const instance = PermissionDecision.load(data); + expect(instance).toBeDefined(); + }); + + it("should save to dictionary", () => { + const instance = new PermissionDecision(); + const data = instance.save(); + expect(data).toBeDefined(); + expect(typeof data).toBe("object"); + }); + }); +}); diff --git a/runtime/typescript/packages/core/tests/model/events/permission-request.test.ts b/runtime/typescript/packages/core/tests/model/events/permission-request.test.ts new file mode 100644 index 00000000..598184c3 --- /dev/null +++ b/runtime/typescript/packages/core/tests/model/events/permission-request.test.ts @@ -0,0 +1,83 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { PermissionRequest } from "../../../src/model/index"; + +describe("PermissionRequest", () => { + describe("construction", () => { + it("should create a new instance with defaults", () => { + const instance = new PermissionRequest(); + expect(instance).toBeDefined(); + }); + + it("should create a new instance with partial initialization", () => { + const instance = new PermissionRequest({}); + expect(instance).toBeDefined(); + }); + }); + + describe("JSON serialization", () => { + it("should load from JSON - example 1", () => { + const json = `{\n "requestId": "perm_abc123",\n "toolCallId": "call_abc123",\n "permission": "tool.execute",\n "target": "shell",\n "promptRequest": "Allow shell to run tests?"\n}`; + const instance = PermissionRequest.fromJson(json); + expect(instance).toBeDefined(); + expect(instance.requestId).toEqual("perm_abc123"); + expect(instance.toolCallId).toEqual("call_abc123"); + expect(instance.permission).toEqual("tool.execute"); + expect(instance.target).toEqual("shell"); + expect(instance.promptRequest).toEqual("Allow shell to run tests?"); + }); + + it("should round-trip JSON - example 1", () => { + const json = `{\n "requestId": "perm_abc123",\n "toolCallId": "call_abc123",\n "permission": "tool.execute",\n "target": "shell",\n "promptRequest": "Allow shell to run tests?"\n}`; + const instance = PermissionRequest.fromJson(json); + const output = instance.toJson(); + const reloaded = PermissionRequest.fromJson(output); + expect(reloaded.requestId).toEqual(instance.requestId); + expect(reloaded.toolCallId).toEqual(instance.toolCallId); + expect(reloaded.permission).toEqual(instance.permission); + expect(reloaded.target).toEqual(instance.target); + expect(reloaded.promptRequest).toEqual(instance.promptRequest); + }); + }); + + describe("YAML serialization", () => { + it("should load from YAML - example 1", () => { + const yaml = `requestId: perm_abc123\ntoolCallId: call_abc123\npermission: tool.execute\ntarget: shell\npromptRequest: Allow shell to run tests?\n`; + const instance = PermissionRequest.fromYaml(yaml); + expect(instance).toBeDefined(); + expect(instance.requestId).toEqual("perm_abc123"); + expect(instance.toolCallId).toEqual("call_abc123"); + expect(instance.permission).toEqual("tool.execute"); + expect(instance.target).toEqual("shell"); + expect(instance.promptRequest).toEqual("Allow shell to run tests?"); + }); + + it("should round-trip YAML - example 1", () => { + const yaml = `requestId: perm_abc123\ntoolCallId: call_abc123\npermission: tool.execute\ntarget: shell\npromptRequest: Allow shell to run tests?\n`; + const instance = PermissionRequest.fromYaml(yaml); + const output = instance.toYaml(); + const reloaded = PermissionRequest.fromYaml(output); + expect(reloaded.requestId).toEqual(instance.requestId); + expect(reloaded.toolCallId).toEqual(instance.toolCallId); + expect(reloaded.permission).toEqual(instance.permission); + expect(reloaded.target).toEqual(instance.target); + expect(reloaded.promptRequest).toEqual(instance.promptRequest); + }); + }); + + describe("load and save", () => { + it("should load from dictionary", () => { + const data: Record = {}; + const instance = PermissionRequest.load(data); + expect(instance).toBeDefined(); + }); + + it("should save to dictionary", () => { + const instance = new PermissionRequest(); + const data = instance.save(); + expect(data).toBeDefined(); + expect(typeof data).toBe("object"); + }); + }); +}); diff --git a/runtime/typescript/packages/core/tests/model/events/permission-requested-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/permission-requested-payload.test.ts index e19ad6f2..9e9a71d6 100644 --- a/runtime/typescript/packages/core/tests/model/events/permission-requested-payload.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/permission-requested-payload.test.ts @@ -18,39 +18,51 @@ describe("PermissionRequestedPayload", () => { describe("JSON serialization", () => { it("should load from JSON - example 1", () => { - const json = `{\n "permission": "tool.execute",\n "target": "shell"\n}`; + const json = `{\n "requestId": "perm_abc123",\n "toolCallId": "call_abc123",\n "permission": "tool.execute",\n "target": "shell",\n "promptRequest": "Allow shell to run tests?"\n}`; const instance = PermissionRequestedPayload.fromJson(json); expect(instance).toBeDefined(); + expect(instance.requestId).toEqual("perm_abc123"); + expect(instance.toolCallId).toEqual("call_abc123"); expect(instance.permission).toEqual("tool.execute"); expect(instance.target).toEqual("shell"); + expect(instance.promptRequest).toEqual("Allow shell to run tests?"); }); it("should round-trip JSON - example 1", () => { - const json = `{\n "permission": "tool.execute",\n "target": "shell"\n}`; + const json = `{\n "requestId": "perm_abc123",\n "toolCallId": "call_abc123",\n "permission": "tool.execute",\n "target": "shell",\n "promptRequest": "Allow shell to run tests?"\n}`; const instance = PermissionRequestedPayload.fromJson(json); const output = instance.toJson(); const reloaded = PermissionRequestedPayload.fromJson(output); + expect(reloaded.requestId).toEqual(instance.requestId); + expect(reloaded.toolCallId).toEqual(instance.toolCallId); expect(reloaded.permission).toEqual(instance.permission); expect(reloaded.target).toEqual(instance.target); + expect(reloaded.promptRequest).toEqual(instance.promptRequest); }); }); describe("YAML serialization", () => { it("should load from YAML - example 1", () => { - const yaml = `permission: tool.execute\ntarget: shell\n`; + const yaml = `requestId: perm_abc123\ntoolCallId: call_abc123\npermission: tool.execute\ntarget: shell\npromptRequest: Allow shell to run tests?\n`; const instance = PermissionRequestedPayload.fromYaml(yaml); expect(instance).toBeDefined(); + expect(instance.requestId).toEqual("perm_abc123"); + expect(instance.toolCallId).toEqual("call_abc123"); expect(instance.permission).toEqual("tool.execute"); expect(instance.target).toEqual("shell"); + expect(instance.promptRequest).toEqual("Allow shell to run tests?"); }); it("should round-trip YAML - example 1", () => { - const yaml = `permission: tool.execute\ntarget: shell\n`; + const yaml = `requestId: perm_abc123\ntoolCallId: call_abc123\npermission: tool.execute\ntarget: shell\npromptRequest: Allow shell to run tests?\n`; const instance = PermissionRequestedPayload.fromYaml(yaml); const output = instance.toYaml(); const reloaded = PermissionRequestedPayload.fromYaml(output); + expect(reloaded.requestId).toEqual(instance.requestId); + expect(reloaded.toolCallId).toEqual(instance.toolCallId); expect(reloaded.permission).toEqual(instance.permission); expect(reloaded.target).toEqual(instance.target); + expect(reloaded.promptRequest).toEqual(instance.promptRequest); }); }); diff --git a/runtime/typescript/packages/core/tests/model/events/redacted-field.test.ts b/runtime/typescript/packages/core/tests/model/events/redacted-field.test.ts new file mode 100644 index 00000000..950d8492 --- /dev/null +++ b/runtime/typescript/packages/core/tests/model/events/redacted-field.test.ts @@ -0,0 +1,75 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { RedactedField } from "../../../src/model/index"; + +describe("RedactedField", () => { + describe("construction", () => { + it("should create a new instance with defaults", () => { + const instance = new RedactedField(); + expect(instance).toBeDefined(); + }); + + it("should create a new instance with partial initialization", () => { + const instance = new RedactedField({}); + expect(instance).toBeDefined(); + }); + }); + + describe("JSON serialization", () => { + it("should load from JSON - example 1", () => { + const json = `{\n "path": "$.arguments.apiKey",\n "mode": "redacted",\n "reason": "secret"\n}`; + const instance = RedactedField.fromJson(json); + expect(instance).toBeDefined(); + expect(instance.path).toEqual("$.arguments.apiKey"); + expect(instance.mode).toEqual("redacted"); + expect(instance.reason).toEqual("secret"); + }); + + it("should round-trip JSON - example 1", () => { + const json = `{\n "path": "$.arguments.apiKey",\n "mode": "redacted",\n "reason": "secret"\n}`; + const instance = RedactedField.fromJson(json); + const output = instance.toJson(); + const reloaded = RedactedField.fromJson(output); + expect(reloaded.path).toEqual(instance.path); + expect(reloaded.mode).toEqual(instance.mode); + expect(reloaded.reason).toEqual(instance.reason); + }); + }); + + describe("YAML serialization", () => { + it("should load from YAML - example 1", () => { + const yaml = `path: $.arguments.apiKey\nmode: redacted\nreason: secret\n`; + const instance = RedactedField.fromYaml(yaml); + expect(instance).toBeDefined(); + expect(instance.path).toEqual("$.arguments.apiKey"); + expect(instance.mode).toEqual("redacted"); + expect(instance.reason).toEqual("secret"); + }); + + it("should round-trip YAML - example 1", () => { + const yaml = `path: $.arguments.apiKey\nmode: redacted\nreason: secret\n`; + const instance = RedactedField.fromYaml(yaml); + const output = instance.toYaml(); + const reloaded = RedactedField.fromYaml(output); + expect(reloaded.path).toEqual(instance.path); + expect(reloaded.mode).toEqual(instance.mode); + expect(reloaded.reason).toEqual(instance.reason); + }); + }); + + describe("load and save", () => { + it("should load from dictionary", () => { + const data: Record = {}; + const instance = RedactedField.load(data); + expect(instance).toBeDefined(); + }); + + it("should save to dictionary", () => { + const instance = new RedactedField(); + const data = instance.save(); + expect(data).toBeDefined(); + expect(typeof data).toBe("object"); + }); + }); +}); diff --git a/runtime/typescript/packages/core/tests/model/events/redaction-metadata.test.ts b/runtime/typescript/packages/core/tests/model/events/redaction-metadata.test.ts new file mode 100644 index 00000000..e0fc58d1 --- /dev/null +++ b/runtime/typescript/packages/core/tests/model/events/redaction-metadata.test.ts @@ -0,0 +1,71 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { RedactionMetadata } from "../../../src/model/index"; + +describe("RedactionMetadata", () => { + describe("construction", () => { + it("should create a new instance with defaults", () => { + const instance = new RedactionMetadata(); + expect(instance).toBeDefined(); + }); + + it("should create a new instance with partial initialization", () => { + const instance = new RedactionMetadata({}); + expect(instance).toBeDefined(); + }); + }); + + describe("JSON serialization", () => { + it("should load from JSON - example 1", () => { + const json = `{\n "sanitized": true,\n "policy": "default-v1"\n}`; + const instance = RedactionMetadata.fromJson(json); + expect(instance).toBeDefined(); + expect(instance.sanitized).toEqual(true); + expect(instance.policy).toEqual("default-v1"); + }); + + it("should round-trip JSON - example 1", () => { + const json = `{\n "sanitized": true,\n "policy": "default-v1"\n}`; + const instance = RedactionMetadata.fromJson(json); + const output = instance.toJson(); + const reloaded = RedactionMetadata.fromJson(output); + expect(reloaded.sanitized).toEqual(instance.sanitized); + expect(reloaded.policy).toEqual(instance.policy); + }); + }); + + describe("YAML serialization", () => { + it("should load from YAML - example 1", () => { + const yaml = `sanitized: true\npolicy: default-v1\n`; + const instance = RedactionMetadata.fromYaml(yaml); + expect(instance).toBeDefined(); + expect(instance.sanitized).toEqual(true); + expect(instance.policy).toEqual("default-v1"); + }); + + it("should round-trip YAML - example 1", () => { + const yaml = `sanitized: true\npolicy: default-v1\n`; + const instance = RedactionMetadata.fromYaml(yaml); + const output = instance.toYaml(); + const reloaded = RedactionMetadata.fromYaml(output); + expect(reloaded.sanitized).toEqual(instance.sanitized); + expect(reloaded.policy).toEqual(instance.policy); + }); + }); + + describe("load and save", () => { + it("should load from dictionary", () => { + const data: Record = {}; + const instance = RedactionMetadata.load(data); + expect(instance).toBeDefined(); + }); + + it("should save to dictionary", () => { + const instance = new RedactionMetadata(); + const data = instance.save(); + expect(data).toBeDefined(); + expect(typeof data).toBe("object"); + }); + }); +}); diff --git a/runtime/typescript/packages/core/tests/model/events/session-end-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/session-end-payload.test.ts new file mode 100644 index 00000000..ca0bd132 --- /dev/null +++ b/runtime/typescript/packages/core/tests/model/events/session-end-payload.test.ts @@ -0,0 +1,79 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { SessionEndPayload } from "../../../src/model/index"; + +describe("SessionEndPayload", () => { + describe("construction", () => { + it("should create a new instance with defaults", () => { + const instance = new SessionEndPayload(); + expect(instance).toBeDefined(); + }); + + it("should create a new instance with partial initialization", () => { + const instance = new SessionEndPayload({}); + expect(instance).toBeDefined(); + }); + }); + + describe("JSON serialization", () => { + it("should load from JSON - example 1", () => { + const json = `{\n "sessionId": "sess_abc123",\n "status": "success",\n "reason": "complete",\n "durationMs": 12500\n}`; + const instance = SessionEndPayload.fromJson(json); + expect(instance).toBeDefined(); + expect(instance.sessionId).toEqual("sess_abc123"); + expect(instance.status).toEqual("success"); + expect(instance.reason).toEqual("complete"); + expect(instance.durationMs).toEqual(12500); + }); + + it("should round-trip JSON - example 1", () => { + const json = `{\n "sessionId": "sess_abc123",\n "status": "success",\n "reason": "complete",\n "durationMs": 12500\n}`; + const instance = SessionEndPayload.fromJson(json); + const output = instance.toJson(); + const reloaded = SessionEndPayload.fromJson(output); + expect(reloaded.sessionId).toEqual(instance.sessionId); + expect(reloaded.status).toEqual(instance.status); + expect(reloaded.reason).toEqual(instance.reason); + expect(reloaded.durationMs).toEqual(instance.durationMs); + }); + }); + + describe("YAML serialization", () => { + it("should load from YAML - example 1", () => { + const yaml = `sessionId: sess_abc123\nstatus: success\nreason: complete\ndurationMs: 12500\n`; + const instance = SessionEndPayload.fromYaml(yaml); + expect(instance).toBeDefined(); + expect(instance.sessionId).toEqual("sess_abc123"); + expect(instance.status).toEqual("success"); + expect(instance.reason).toEqual("complete"); + expect(instance.durationMs).toEqual(12500); + }); + + it("should round-trip YAML - example 1", () => { + const yaml = `sessionId: sess_abc123\nstatus: success\nreason: complete\ndurationMs: 12500\n`; + const instance = SessionEndPayload.fromYaml(yaml); + const output = instance.toYaml(); + const reloaded = SessionEndPayload.fromYaml(output); + expect(reloaded.sessionId).toEqual(instance.sessionId); + expect(reloaded.status).toEqual(instance.status); + expect(reloaded.reason).toEqual(instance.reason); + expect(reloaded.durationMs).toEqual(instance.durationMs); + }); + }); + + describe("load and save", () => { + it("should load from dictionary", () => { + const data: Record = {}; + const instance = SessionEndPayload.load(data); + expect(instance).toBeDefined(); + }); + + it("should save to dictionary", () => { + const instance = new SessionEndPayload(); + const data = instance.save(); + expect(data).toBeDefined(); + expect(typeof data).toBe("object"); + }); + }); +}); diff --git a/runtime/typescript/packages/core/tests/model/events/session-event.test.ts b/runtime/typescript/packages/core/tests/model/events/session-event.test.ts new file mode 100644 index 00000000..09fd07ab --- /dev/null +++ b/runtime/typescript/packages/core/tests/model/events/session-event.test.ts @@ -0,0 +1,87 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { SessionEvent } from "../../../src/model/index"; + +describe("SessionEvent", () => { + describe("construction", () => { + it("should create a new instance with defaults", () => { + const instance = new SessionEvent(); + expect(instance).toBeDefined(); + }); + + it("should create a new instance with partial initialization", () => { + const instance = new SessionEvent({}); + expect(instance).toBeDefined(); + }); + }); + + describe("JSON serialization", () => { + it("should load from JSON - example 1", () => { + const json = `{\n "id": "evt_abc123",\n "timestamp": "2026-06-09T20:00:00Z",\n "sessionId": "sess_abc123",\n "turnId": "turn_001",\n "parentId": "evt_parent",\n "spanId": "span_hook_001"\n}`; + const instance = SessionEvent.fromJson(json); + expect(instance).toBeDefined(); + expect(instance.id).toEqual("evt_abc123"); + expect(instance.timestamp).toEqual("2026-06-09T20:00:00Z"); + expect(instance.sessionId).toEqual("sess_abc123"); + expect(instance.turnId).toEqual("turn_001"); + expect(instance.parentId).toEqual("evt_parent"); + expect(instance.spanId).toEqual("span_hook_001"); + }); + + it("should round-trip JSON - example 1", () => { + const json = `{\n "id": "evt_abc123",\n "timestamp": "2026-06-09T20:00:00Z",\n "sessionId": "sess_abc123",\n "turnId": "turn_001",\n "parentId": "evt_parent",\n "spanId": "span_hook_001"\n}`; + const instance = SessionEvent.fromJson(json); + const output = instance.toJson(); + const reloaded = SessionEvent.fromJson(output); + expect(reloaded.id).toEqual(instance.id); + expect(reloaded.timestamp).toEqual(instance.timestamp); + expect(reloaded.sessionId).toEqual(instance.sessionId); + expect(reloaded.turnId).toEqual(instance.turnId); + expect(reloaded.parentId).toEqual(instance.parentId); + expect(reloaded.spanId).toEqual(instance.spanId); + }); + }); + + describe("YAML serialization", () => { + it("should load from YAML - example 1", () => { + const yaml = `id: evt_abc123\ntimestamp: "2026-06-09T20:00:00Z"\nsessionId: sess_abc123\nturnId: turn_001\nparentId: evt_parent\nspanId: span_hook_001\n`; + const instance = SessionEvent.fromYaml(yaml); + expect(instance).toBeDefined(); + expect(instance.id).toEqual("evt_abc123"); + expect(instance.timestamp).toEqual("2026-06-09T20:00:00Z"); + expect(instance.sessionId).toEqual("sess_abc123"); + expect(instance.turnId).toEqual("turn_001"); + expect(instance.parentId).toEqual("evt_parent"); + expect(instance.spanId).toEqual("span_hook_001"); + }); + + it("should round-trip YAML - example 1", () => { + const yaml = `id: evt_abc123\ntimestamp: "2026-06-09T20:00:00Z"\nsessionId: sess_abc123\nturnId: turn_001\nparentId: evt_parent\nspanId: span_hook_001\n`; + const instance = SessionEvent.fromYaml(yaml); + const output = instance.toYaml(); + const reloaded = SessionEvent.fromYaml(output); + expect(reloaded.id).toEqual(instance.id); + expect(reloaded.timestamp).toEqual(instance.timestamp); + expect(reloaded.sessionId).toEqual(instance.sessionId); + expect(reloaded.turnId).toEqual(instance.turnId); + expect(reloaded.parentId).toEqual(instance.parentId); + expect(reloaded.spanId).toEqual(instance.spanId); + }); + }); + + describe("load and save", () => { + it("should load from dictionary", () => { + const data: Record = {}; + const instance = SessionEvent.load(data); + expect(instance).toBeDefined(); + }); + + it("should save to dictionary", () => { + const instance = new SessionEvent(); + const data = instance.save(); + expect(data).toBeDefined(); + expect(typeof data).toBe("object"); + }); + }); +}); diff --git a/runtime/typescript/packages/core/tests/model/events/session-file-ref.test.ts b/runtime/typescript/packages/core/tests/model/events/session-file-ref.test.ts new file mode 100644 index 00000000..26ebb767 --- /dev/null +++ b/runtime/typescript/packages/core/tests/model/events/session-file-ref.test.ts @@ -0,0 +1,83 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { SessionFileRef } from "../../../src/model/index"; + +describe("SessionFileRef", () => { + describe("construction", () => { + it("should create a new instance with defaults", () => { + const instance = new SessionFileRef(); + expect(instance).toBeDefined(); + }); + + it("should create a new instance with partial initialization", () => { + const instance = new SessionFileRef({}); + expect(instance).toBeDefined(); + }); + }); + + describe("JSON serialization", () => { + it("should load from JSON - example 1", () => { + const json = `{\n "sessionId": "sess_abc123",\n "path": "src/index.ts",\n "toolName": "view",\n "turnIndex": 2,\n "firstSeenAt": "2026-06-09T20:00:00Z"\n}`; + const instance = SessionFileRef.fromJson(json); + expect(instance).toBeDefined(); + expect(instance.sessionId).toEqual("sess_abc123"); + expect(instance.path).toEqual("src/index.ts"); + expect(instance.toolName).toEqual("view"); + expect(instance.turnIndex).toEqual(2); + expect(instance.firstSeenAt).toEqual("2026-06-09T20:00:00Z"); + }); + + it("should round-trip JSON - example 1", () => { + const json = `{\n "sessionId": "sess_abc123",\n "path": "src/index.ts",\n "toolName": "view",\n "turnIndex": 2,\n "firstSeenAt": "2026-06-09T20:00:00Z"\n}`; + const instance = SessionFileRef.fromJson(json); + const output = instance.toJson(); + const reloaded = SessionFileRef.fromJson(output); + expect(reloaded.sessionId).toEqual(instance.sessionId); + expect(reloaded.path).toEqual(instance.path); + expect(reloaded.toolName).toEqual(instance.toolName); + expect(reloaded.turnIndex).toEqual(instance.turnIndex); + expect(reloaded.firstSeenAt).toEqual(instance.firstSeenAt); + }); + }); + + describe("YAML serialization", () => { + it("should load from YAML - example 1", () => { + const yaml = `sessionId: sess_abc123\npath: src/index.ts\ntoolName: view\nturnIndex: 2\nfirstSeenAt: "2026-06-09T20:00:00Z"\n`; + const instance = SessionFileRef.fromYaml(yaml); + expect(instance).toBeDefined(); + expect(instance.sessionId).toEqual("sess_abc123"); + expect(instance.path).toEqual("src/index.ts"); + expect(instance.toolName).toEqual("view"); + expect(instance.turnIndex).toEqual(2); + expect(instance.firstSeenAt).toEqual("2026-06-09T20:00:00Z"); + }); + + it("should round-trip YAML - example 1", () => { + const yaml = `sessionId: sess_abc123\npath: src/index.ts\ntoolName: view\nturnIndex: 2\nfirstSeenAt: "2026-06-09T20:00:00Z"\n`; + const instance = SessionFileRef.fromYaml(yaml); + const output = instance.toYaml(); + const reloaded = SessionFileRef.fromYaml(output); + expect(reloaded.sessionId).toEqual(instance.sessionId); + expect(reloaded.path).toEqual(instance.path); + expect(reloaded.toolName).toEqual(instance.toolName); + expect(reloaded.turnIndex).toEqual(instance.turnIndex); + expect(reloaded.firstSeenAt).toEqual(instance.firstSeenAt); + }); + }); + + describe("load and save", () => { + it("should load from dictionary", () => { + const data: Record = {}; + const instance = SessionFileRef.load(data); + expect(instance).toBeDefined(); + }); + + it("should save to dictionary", () => { + const instance = new SessionFileRef(); + const data = instance.save(); + expect(data).toBeDefined(); + expect(typeof data).toBe("object"); + }); + }); +}); diff --git a/runtime/typescript/packages/core/tests/model/events/session-ref.test.ts b/runtime/typescript/packages/core/tests/model/events/session-ref.test.ts new file mode 100644 index 00000000..14950fbd --- /dev/null +++ b/runtime/typescript/packages/core/tests/model/events/session-ref.test.ts @@ -0,0 +1,83 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { SessionRef } from "../../../src/model/index"; + +describe("SessionRef", () => { + describe("construction", () => { + it("should create a new instance with defaults", () => { + const instance = new SessionRef(); + expect(instance).toBeDefined(); + }); + + it("should create a new instance with partial initialization", () => { + const instance = new SessionRef({}); + expect(instance).toBeDefined(); + }); + }); + + describe("JSON serialization", () => { + it("should load from JSON - example 1", () => { + const json = `{\n "sessionId": "sess_abc123",\n "refType": "issue",\n "refValue": "owner/repo#123",\n "turnIndex": 2,\n "createdAt": "2026-06-09T20:00:00Z"\n}`; + const instance = SessionRef.fromJson(json); + expect(instance).toBeDefined(); + expect(instance.sessionId).toEqual("sess_abc123"); + expect(instance.refType).toEqual("issue"); + expect(instance.refValue).toEqual("owner/repo#123"); + expect(instance.turnIndex).toEqual(2); + expect(instance.createdAt).toEqual("2026-06-09T20:00:00Z"); + }); + + it("should round-trip JSON - example 1", () => { + const json = `{\n "sessionId": "sess_abc123",\n "refType": "issue",\n "refValue": "owner/repo#123",\n "turnIndex": 2,\n "createdAt": "2026-06-09T20:00:00Z"\n}`; + const instance = SessionRef.fromJson(json); + const output = instance.toJson(); + const reloaded = SessionRef.fromJson(output); + expect(reloaded.sessionId).toEqual(instance.sessionId); + expect(reloaded.refType).toEqual(instance.refType); + expect(reloaded.refValue).toEqual(instance.refValue); + expect(reloaded.turnIndex).toEqual(instance.turnIndex); + expect(reloaded.createdAt).toEqual(instance.createdAt); + }); + }); + + describe("YAML serialization", () => { + it("should load from YAML - example 1", () => { + const yaml = `sessionId: sess_abc123\nrefType: issue\nrefValue: "owner/repo#123"\nturnIndex: 2\ncreatedAt: "2026-06-09T20:00:00Z"\n`; + const instance = SessionRef.fromYaml(yaml); + expect(instance).toBeDefined(); + expect(instance.sessionId).toEqual("sess_abc123"); + expect(instance.refType).toEqual("issue"); + expect(instance.refValue).toEqual("owner/repo#123"); + expect(instance.turnIndex).toEqual(2); + expect(instance.createdAt).toEqual("2026-06-09T20:00:00Z"); + }); + + it("should round-trip YAML - example 1", () => { + const yaml = `sessionId: sess_abc123\nrefType: issue\nrefValue: "owner/repo#123"\nturnIndex: 2\ncreatedAt: "2026-06-09T20:00:00Z"\n`; + const instance = SessionRef.fromYaml(yaml); + const output = instance.toYaml(); + const reloaded = SessionRef.fromYaml(output); + expect(reloaded.sessionId).toEqual(instance.sessionId); + expect(reloaded.refType).toEqual(instance.refType); + expect(reloaded.refValue).toEqual(instance.refValue); + expect(reloaded.turnIndex).toEqual(instance.turnIndex); + expect(reloaded.createdAt).toEqual(instance.createdAt); + }); + }); + + describe("load and save", () => { + it("should load from dictionary", () => { + const data: Record = {}; + const instance = SessionRef.load(data); + expect(instance).toBeDefined(); + }); + + it("should save to dictionary", () => { + const instance = new SessionRef(); + const data = instance.save(); + expect(data).toBeDefined(); + expect(typeof data).toBe("object"); + }); + }); +}); diff --git a/runtime/typescript/packages/core/tests/model/events/session-start-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/session-start-payload.test.ts new file mode 100644 index 00000000..551a7305 --- /dev/null +++ b/runtime/typescript/packages/core/tests/model/events/session-start-payload.test.ts @@ -0,0 +1,95 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { SessionStartPayload } from "../../../src/model/index"; + +describe("SessionStartPayload", () => { + describe("construction", () => { + it("should create a new instance with defaults", () => { + const instance = new SessionStartPayload(); + expect(instance).toBeDefined(); + }); + + it("should create a new instance with partial initialization", () => { + const instance = new SessionStartPayload({}); + expect(instance).toBeDefined(); + }); + }); + + describe("JSON serialization", () => { + it("should load from JSON - example 1", () => { + const json = `{\n "sessionId": "sess_abc123",\n "version": 1,\n "producer": "prompty-agent",\n "runtime": "typescript",\n "promptyVersion": "2.0.0",\n "startTime": "2026-06-09T20:00:00Z",\n "selectedModel": "gpt-4o-mini",\n "reasoningEffort": "medium"\n}`; + const instance = SessionStartPayload.fromJson(json); + expect(instance).toBeDefined(); + expect(instance.sessionId).toEqual("sess_abc123"); + expect(instance.version).toEqual(1); + expect(instance.producer).toEqual("prompty-agent"); + expect(instance.runtime).toEqual("typescript"); + expect(instance.promptyVersion).toEqual("2.0.0"); + expect(instance.startTime).toEqual("2026-06-09T20:00:00Z"); + expect(instance.selectedModel).toEqual("gpt-4o-mini"); + expect(instance.reasoningEffort).toEqual("medium"); + }); + + it("should round-trip JSON - example 1", () => { + const json = `{\n "sessionId": "sess_abc123",\n "version": 1,\n "producer": "prompty-agent",\n "runtime": "typescript",\n "promptyVersion": "2.0.0",\n "startTime": "2026-06-09T20:00:00Z",\n "selectedModel": "gpt-4o-mini",\n "reasoningEffort": "medium"\n}`; + const instance = SessionStartPayload.fromJson(json); + const output = instance.toJson(); + const reloaded = SessionStartPayload.fromJson(output); + expect(reloaded.sessionId).toEqual(instance.sessionId); + expect(reloaded.version).toEqual(instance.version); + expect(reloaded.producer).toEqual(instance.producer); + expect(reloaded.runtime).toEqual(instance.runtime); + expect(reloaded.promptyVersion).toEqual(instance.promptyVersion); + expect(reloaded.startTime).toEqual(instance.startTime); + expect(reloaded.selectedModel).toEqual(instance.selectedModel); + expect(reloaded.reasoningEffort).toEqual(instance.reasoningEffort); + }); + }); + + describe("YAML serialization", () => { + it("should load from YAML - example 1", () => { + const yaml = `sessionId: sess_abc123\nversion: 1\nproducer: prompty-agent\nruntime: typescript\npromptyVersion: 2.0.0\nstartTime: "2026-06-09T20:00:00Z"\nselectedModel: gpt-4o-mini\nreasoningEffort: medium\n`; + const instance = SessionStartPayload.fromYaml(yaml); + expect(instance).toBeDefined(); + expect(instance.sessionId).toEqual("sess_abc123"); + expect(instance.version).toEqual(1); + expect(instance.producer).toEqual("prompty-agent"); + expect(instance.runtime).toEqual("typescript"); + expect(instance.promptyVersion).toEqual("2.0.0"); + expect(instance.startTime).toEqual("2026-06-09T20:00:00Z"); + expect(instance.selectedModel).toEqual("gpt-4o-mini"); + expect(instance.reasoningEffort).toEqual("medium"); + }); + + it("should round-trip YAML - example 1", () => { + const yaml = `sessionId: sess_abc123\nversion: 1\nproducer: prompty-agent\nruntime: typescript\npromptyVersion: 2.0.0\nstartTime: "2026-06-09T20:00:00Z"\nselectedModel: gpt-4o-mini\nreasoningEffort: medium\n`; + const instance = SessionStartPayload.fromYaml(yaml); + const output = instance.toYaml(); + const reloaded = SessionStartPayload.fromYaml(output); + expect(reloaded.sessionId).toEqual(instance.sessionId); + expect(reloaded.version).toEqual(instance.version); + expect(reloaded.producer).toEqual(instance.producer); + expect(reloaded.runtime).toEqual(instance.runtime); + expect(reloaded.promptyVersion).toEqual(instance.promptyVersion); + expect(reloaded.startTime).toEqual(instance.startTime); + expect(reloaded.selectedModel).toEqual(instance.selectedModel); + expect(reloaded.reasoningEffort).toEqual(instance.reasoningEffort); + }); + }); + + describe("load and save", () => { + it("should load from dictionary", () => { + const data: Record = {}; + const instance = SessionStartPayload.load(data); + expect(instance).toBeDefined(); + }); + + it("should save to dictionary", () => { + const instance = new SessionStartPayload(); + const data = instance.save(); + expect(data).toBeDefined(); + expect(typeof data).toBe("object"); + }); + }); +}); diff --git a/runtime/typescript/packages/core/tests/model/events/session-summary.test.ts b/runtime/typescript/packages/core/tests/model/events/session-summary.test.ts new file mode 100644 index 00000000..140c686a --- /dev/null +++ b/runtime/typescript/packages/core/tests/model/events/session-summary.test.ts @@ -0,0 +1,83 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { SessionSummary } from "../../../src/model/index"; + +describe("SessionSummary", () => { + describe("construction", () => { + it("should create a new instance with defaults", () => { + const instance = new SessionSummary(); + expect(instance).toBeDefined(); + }); + + it("should create a new instance with partial initialization", () => { + const instance = new SessionSummary({}); + expect(instance).toBeDefined(); + }); + }); + + describe("JSON serialization", () => { + it("should load from JSON - example 1", () => { + const json = `{\n "sessionId": "sess_abc123",\n "status": "success",\n "turns": 5,\n "checkpoints": 2,\n "durationMs": 12500\n}`; + const instance = SessionSummary.fromJson(json); + expect(instance).toBeDefined(); + expect(instance.sessionId).toEqual("sess_abc123"); + expect(instance.status).toEqual("success"); + expect(instance.turns).toEqual(5); + expect(instance.checkpoints).toEqual(2); + expect(instance.durationMs).toEqual(12500); + }); + + it("should round-trip JSON - example 1", () => { + const json = `{\n "sessionId": "sess_abc123",\n "status": "success",\n "turns": 5,\n "checkpoints": 2,\n "durationMs": 12500\n}`; + const instance = SessionSummary.fromJson(json); + const output = instance.toJson(); + const reloaded = SessionSummary.fromJson(output); + expect(reloaded.sessionId).toEqual(instance.sessionId); + expect(reloaded.status).toEqual(instance.status); + expect(reloaded.turns).toEqual(instance.turns); + expect(reloaded.checkpoints).toEqual(instance.checkpoints); + expect(reloaded.durationMs).toEqual(instance.durationMs); + }); + }); + + describe("YAML serialization", () => { + it("should load from YAML - example 1", () => { + const yaml = `sessionId: sess_abc123\nstatus: success\nturns: 5\ncheckpoints: 2\ndurationMs: 12500\n`; + const instance = SessionSummary.fromYaml(yaml); + expect(instance).toBeDefined(); + expect(instance.sessionId).toEqual("sess_abc123"); + expect(instance.status).toEqual("success"); + expect(instance.turns).toEqual(5); + expect(instance.checkpoints).toEqual(2); + expect(instance.durationMs).toEqual(12500); + }); + + it("should round-trip YAML - example 1", () => { + const yaml = `sessionId: sess_abc123\nstatus: success\nturns: 5\ncheckpoints: 2\ndurationMs: 12500\n`; + const instance = SessionSummary.fromYaml(yaml); + const output = instance.toYaml(); + const reloaded = SessionSummary.fromYaml(output); + expect(reloaded.sessionId).toEqual(instance.sessionId); + expect(reloaded.status).toEqual(instance.status); + expect(reloaded.turns).toEqual(instance.turns); + expect(reloaded.checkpoints).toEqual(instance.checkpoints); + expect(reloaded.durationMs).toEqual(instance.durationMs); + }); + }); + + describe("load and save", () => { + it("should load from dictionary", () => { + const data: Record = {}; + const instance = SessionSummary.load(data); + expect(instance).toBeDefined(); + }); + + it("should save to dictionary", () => { + const instance = new SessionSummary(); + const data = instance.save(); + expect(data).toBeDefined(); + expect(typeof data).toBe("object"); + }); + }); +}); diff --git a/runtime/typescript/packages/core/tests/model/events/session-trace.test.ts b/runtime/typescript/packages/core/tests/model/events/session-trace.test.ts new file mode 100644 index 00000000..5fbc7867 --- /dev/null +++ b/runtime/typescript/packages/core/tests/model/events/session-trace.test.ts @@ -0,0 +1,79 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { SessionTrace } from "../../../src/model/index"; + +describe("SessionTrace", () => { + describe("construction", () => { + it("should create a new instance with defaults", () => { + const instance = new SessionTrace(); + expect(instance).toBeDefined(); + }); + + it("should create a new instance with partial initialization", () => { + const instance = new SessionTrace({}); + expect(instance).toBeDefined(); + }); + }); + + describe("JSON serialization", () => { + it("should load from JSON - example 1", () => { + const json = `{\n "version": "1",\n "runtime": "typescript",\n "promptyVersion": "2.0.0",\n "sessionId": "sess_abc123"\n}`; + const instance = SessionTrace.fromJson(json); + expect(instance).toBeDefined(); + expect(instance.version).toEqual("1"); + expect(instance.runtime).toEqual("typescript"); + expect(instance.promptyVersion).toEqual("2.0.0"); + expect(instance.sessionId).toEqual("sess_abc123"); + }); + + it("should round-trip JSON - example 1", () => { + const json = `{\n "version": "1",\n "runtime": "typescript",\n "promptyVersion": "2.0.0",\n "sessionId": "sess_abc123"\n}`; + const instance = SessionTrace.fromJson(json); + const output = instance.toJson(); + const reloaded = SessionTrace.fromJson(output); + expect(reloaded.version).toEqual(instance.version); + expect(reloaded.runtime).toEqual(instance.runtime); + expect(reloaded.promptyVersion).toEqual(instance.promptyVersion); + expect(reloaded.sessionId).toEqual(instance.sessionId); + }); + }); + + describe("YAML serialization", () => { + it("should load from YAML - example 1", () => { + const yaml = `version: "1"\nruntime: typescript\npromptyVersion: 2.0.0\nsessionId: sess_abc123\n`; + const instance = SessionTrace.fromYaml(yaml); + expect(instance).toBeDefined(); + expect(instance.version).toEqual("1"); + expect(instance.runtime).toEqual("typescript"); + expect(instance.promptyVersion).toEqual("2.0.0"); + expect(instance.sessionId).toEqual("sess_abc123"); + }); + + it("should round-trip YAML - example 1", () => { + const yaml = `version: "1"\nruntime: typescript\npromptyVersion: 2.0.0\nsessionId: sess_abc123\n`; + const instance = SessionTrace.fromYaml(yaml); + const output = instance.toYaml(); + const reloaded = SessionTrace.fromYaml(output); + expect(reloaded.version).toEqual(instance.version); + expect(reloaded.runtime).toEqual(instance.runtime); + expect(reloaded.promptyVersion).toEqual(instance.promptyVersion); + expect(reloaded.sessionId).toEqual(instance.sessionId); + }); + }); + + describe("load and save", () => { + it("should load from dictionary", () => { + const data: Record = {}; + const instance = SessionTrace.load(data); + expect(instance).toBeDefined(); + }); + + it("should save to dictionary", () => { + const instance = new SessionTrace(); + const data = instance.save(); + expect(data).toBeDefined(); + expect(typeof data).toBe("object"); + }); + }); +}); diff --git a/runtime/typescript/packages/core/tests/model/events/session-warning-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/session-warning-payload.test.ts new file mode 100644 index 00000000..4f206b18 --- /dev/null +++ b/runtime/typescript/packages/core/tests/model/events/session-warning-payload.test.ts @@ -0,0 +1,71 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { SessionWarningPayload } from "../../../src/model/index"; + +describe("SessionWarningPayload", () => { + describe("construction", () => { + it("should create a new instance with defaults", () => { + const instance = new SessionWarningPayload(); + expect(instance).toBeDefined(); + }); + + it("should create a new instance with partial initialization", () => { + const instance = new SessionWarningPayload({}); + expect(instance).toBeDefined(); + }); + }); + + describe("JSON serialization", () => { + it("should load from JSON - example 1", () => { + const json = `{\n "warningType": "remote",\n "message": "Remote session disabled"\n}`; + const instance = SessionWarningPayload.fromJson(json); + expect(instance).toBeDefined(); + expect(instance.warningType).toEqual("remote"); + expect(instance.message).toEqual("Remote session disabled"); + }); + + it("should round-trip JSON - example 1", () => { + const json = `{\n "warningType": "remote",\n "message": "Remote session disabled"\n}`; + const instance = SessionWarningPayload.fromJson(json); + const output = instance.toJson(); + const reloaded = SessionWarningPayload.fromJson(output); + expect(reloaded.warningType).toEqual(instance.warningType); + expect(reloaded.message).toEqual(instance.message); + }); + }); + + describe("YAML serialization", () => { + it("should load from YAML - example 1", () => { + const yaml = `warningType: remote\nmessage: Remote session disabled\n`; + const instance = SessionWarningPayload.fromYaml(yaml); + expect(instance).toBeDefined(); + expect(instance.warningType).toEqual("remote"); + expect(instance.message).toEqual("Remote session disabled"); + }); + + it("should round-trip YAML - example 1", () => { + const yaml = `warningType: remote\nmessage: Remote session disabled\n`; + const instance = SessionWarningPayload.fromYaml(yaml); + const output = instance.toYaml(); + const reloaded = SessionWarningPayload.fromYaml(output); + expect(reloaded.warningType).toEqual(instance.warningType); + expect(reloaded.message).toEqual(instance.message); + }); + }); + + describe("load and save", () => { + it("should load from dictionary", () => { + const data: Record = {}; + const instance = SessionWarningPayload.load(data); + expect(instance).toBeDefined(); + }); + + it("should save to dictionary", () => { + const instance = new SessionWarningPayload(); + const data = instance.save(); + expect(data).toBeDefined(); + expect(typeof data).toBe("object"); + }); + }); +}); diff --git a/runtime/typescript/packages/core/tests/model/events/tool-execution-complete-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/tool-execution-complete-payload.test.ts new file mode 100644 index 00000000..a76db616 --- /dev/null +++ b/runtime/typescript/packages/core/tests/model/events/tool-execution-complete-payload.test.ts @@ -0,0 +1,91 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { ToolExecutionCompletePayload } from "../../../src/model/index"; + +describe("ToolExecutionCompletePayload", () => { + describe("construction", () => { + it("should create a new instance with defaults", () => { + const instance = new ToolExecutionCompletePayload(); + expect(instance).toBeDefined(); + }); + + it("should create a new instance with partial initialization", () => { + const instance = new ToolExecutionCompletePayload({}); + expect(instance).toBeDefined(); + }); + }); + + describe("JSON serialization", () => { + it("should load from JSON - example 1", () => { + const json = `{\n "requestId": "exec_abc123",\n "toolCallId": "call_abc123",\n "toolName": "powershell",\n "success": true,\n "exitCode": 0,\n "durationMs": 250,\n "errorKind": "timeout"\n}`; + const instance = ToolExecutionCompletePayload.fromJson(json); + expect(instance).toBeDefined(); + expect(instance.requestId).toEqual("exec_abc123"); + expect(instance.toolCallId).toEqual("call_abc123"); + expect(instance.toolName).toEqual("powershell"); + expect(instance.success).toEqual(true); + expect(instance.exitCode).toEqual(0); + expect(instance.durationMs).toEqual(250); + expect(instance.errorKind).toEqual("timeout"); + }); + + it("should round-trip JSON - example 1", () => { + const json = `{\n "requestId": "exec_abc123",\n "toolCallId": "call_abc123",\n "toolName": "powershell",\n "success": true,\n "exitCode": 0,\n "durationMs": 250,\n "errorKind": "timeout"\n}`; + const instance = ToolExecutionCompletePayload.fromJson(json); + const output = instance.toJson(); + const reloaded = ToolExecutionCompletePayload.fromJson(output); + expect(reloaded.requestId).toEqual(instance.requestId); + expect(reloaded.toolCallId).toEqual(instance.toolCallId); + expect(reloaded.toolName).toEqual(instance.toolName); + expect(reloaded.success).toEqual(instance.success); + expect(reloaded.exitCode).toEqual(instance.exitCode); + expect(reloaded.durationMs).toEqual(instance.durationMs); + expect(reloaded.errorKind).toEqual(instance.errorKind); + }); + }); + + describe("YAML serialization", () => { + it("should load from YAML - example 1", () => { + const yaml = `requestId: exec_abc123\ntoolCallId: call_abc123\ntoolName: powershell\nsuccess: true\nexitCode: 0\ndurationMs: 250\nerrorKind: timeout\n`; + const instance = ToolExecutionCompletePayload.fromYaml(yaml); + expect(instance).toBeDefined(); + expect(instance.requestId).toEqual("exec_abc123"); + expect(instance.toolCallId).toEqual("call_abc123"); + expect(instance.toolName).toEqual("powershell"); + expect(instance.success).toEqual(true); + expect(instance.exitCode).toEqual(0); + expect(instance.durationMs).toEqual(250); + expect(instance.errorKind).toEqual("timeout"); + }); + + it("should round-trip YAML - example 1", () => { + const yaml = `requestId: exec_abc123\ntoolCallId: call_abc123\ntoolName: powershell\nsuccess: true\nexitCode: 0\ndurationMs: 250\nerrorKind: timeout\n`; + const instance = ToolExecutionCompletePayload.fromYaml(yaml); + const output = instance.toYaml(); + const reloaded = ToolExecutionCompletePayload.fromYaml(output); + expect(reloaded.requestId).toEqual(instance.requestId); + expect(reloaded.toolCallId).toEqual(instance.toolCallId); + expect(reloaded.toolName).toEqual(instance.toolName); + expect(reloaded.success).toEqual(instance.success); + expect(reloaded.exitCode).toEqual(instance.exitCode); + expect(reloaded.durationMs).toEqual(instance.durationMs); + expect(reloaded.errorKind).toEqual(instance.errorKind); + }); + }); + + describe("load and save", () => { + it("should load from dictionary", () => { + const data: Record = {}; + const instance = ToolExecutionCompletePayload.load(data); + expect(instance).toBeDefined(); + }); + + it("should save to dictionary", () => { + const instance = new ToolExecutionCompletePayload(); + const data = instance.save(); + expect(data).toBeDefined(); + expect(typeof data).toBe("object"); + }); + }); +}); diff --git a/runtime/typescript/packages/core/tests/model/events/tool-execution-start-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/tool-execution-start-payload.test.ts new file mode 100644 index 00000000..e14add42 --- /dev/null +++ b/runtime/typescript/packages/core/tests/model/events/tool-execution-start-payload.test.ts @@ -0,0 +1,79 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { ToolExecutionStartPayload } from "../../../src/model/index"; + +describe("ToolExecutionStartPayload", () => { + describe("construction", () => { + it("should create a new instance with defaults", () => { + const instance = new ToolExecutionStartPayload(); + expect(instance).toBeDefined(); + }); + + it("should create a new instance with partial initialization", () => { + const instance = new ToolExecutionStartPayload({}); + expect(instance).toBeDefined(); + }); + }); + + describe("JSON serialization", () => { + it("should load from JSON - example 1", () => { + const json = `{\n "requestId": "exec_abc123",\n "toolCallId": "call_abc123",\n "toolName": "powershell",\n "workingDirectory": "/workspace/project"\n}`; + const instance = ToolExecutionStartPayload.fromJson(json); + expect(instance).toBeDefined(); + expect(instance.requestId).toEqual("exec_abc123"); + expect(instance.toolCallId).toEqual("call_abc123"); + expect(instance.toolName).toEqual("powershell"); + expect(instance.workingDirectory).toEqual("/workspace/project"); + }); + + it("should round-trip JSON - example 1", () => { + const json = `{\n "requestId": "exec_abc123",\n "toolCallId": "call_abc123",\n "toolName": "powershell",\n "workingDirectory": "/workspace/project"\n}`; + const instance = ToolExecutionStartPayload.fromJson(json); + const output = instance.toJson(); + const reloaded = ToolExecutionStartPayload.fromJson(output); + expect(reloaded.requestId).toEqual(instance.requestId); + expect(reloaded.toolCallId).toEqual(instance.toolCallId); + expect(reloaded.toolName).toEqual(instance.toolName); + expect(reloaded.workingDirectory).toEqual(instance.workingDirectory); + }); + }); + + describe("YAML serialization", () => { + it("should load from YAML - example 1", () => { + const yaml = `requestId: exec_abc123\ntoolCallId: call_abc123\ntoolName: powershell\nworkingDirectory: /workspace/project\n`; + const instance = ToolExecutionStartPayload.fromYaml(yaml); + expect(instance).toBeDefined(); + expect(instance.requestId).toEqual("exec_abc123"); + expect(instance.toolCallId).toEqual("call_abc123"); + expect(instance.toolName).toEqual("powershell"); + expect(instance.workingDirectory).toEqual("/workspace/project"); + }); + + it("should round-trip YAML - example 1", () => { + const yaml = `requestId: exec_abc123\ntoolCallId: call_abc123\ntoolName: powershell\nworkingDirectory: /workspace/project\n`; + const instance = ToolExecutionStartPayload.fromYaml(yaml); + const output = instance.toYaml(); + const reloaded = ToolExecutionStartPayload.fromYaml(output); + expect(reloaded.requestId).toEqual(instance.requestId); + expect(reloaded.toolCallId).toEqual(instance.toolCallId); + expect(reloaded.toolName).toEqual(instance.toolName); + expect(reloaded.workingDirectory).toEqual(instance.workingDirectory); + }); + }); + + describe("load and save", () => { + it("should load from dictionary", () => { + const data: Record = {}; + const instance = ToolExecutionStartPayload.load(data); + expect(instance).toBeDefined(); + }); + + it("should save to dictionary", () => { + const instance = new ToolExecutionStartPayload(); + const data = instance.save(); + expect(data).toBeDefined(); + expect(typeof data).toBe("object"); + }); + }); +}); diff --git a/runtime/typescript/packages/core/tests/model/events/trajectory-event.test.ts b/runtime/typescript/packages/core/tests/model/events/trajectory-event.test.ts new file mode 100644 index 00000000..e17f52e0 --- /dev/null +++ b/runtime/typescript/packages/core/tests/model/events/trajectory-event.test.ts @@ -0,0 +1,91 @@ +// Copyright (c) Microsoft. All rights reserved. +// WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. + +import { TrajectoryEvent } from "../../../src/model/index"; + +describe("TrajectoryEvent", () => { + describe("construction", () => { + it("should create a new instance with defaults", () => { + const instance = new TrajectoryEvent(); + expect(instance).toBeDefined(); + }); + + it("should create a new instance with partial initialization", () => { + const instance = new TrajectoryEvent({}); + expect(instance).toBeDefined(); + }); + }); + + describe("JSON serialization", () => { + it("should load from JSON - example 1", () => { + const json = `{\n "id": "traj_abc123",\n "sessionId": "sess_abc123",\n "turnId": "turn_001",\n "toolCallId": "call_abc123",\n "turnIndex": 4,\n "eventType": "command",\n "createdAt": "2026-06-09T20:00:00Z"\n}`; + const instance = TrajectoryEvent.fromJson(json); + expect(instance).toBeDefined(); + expect(instance.id).toEqual("traj_abc123"); + expect(instance.sessionId).toEqual("sess_abc123"); + expect(instance.turnId).toEqual("turn_001"); + expect(instance.toolCallId).toEqual("call_abc123"); + expect(instance.turnIndex).toEqual(4); + expect(instance.eventType).toEqual("command"); + expect(instance.createdAt).toEqual("2026-06-09T20:00:00Z"); + }); + + it("should round-trip JSON - example 1", () => { + const json = `{\n "id": "traj_abc123",\n "sessionId": "sess_abc123",\n "turnId": "turn_001",\n "toolCallId": "call_abc123",\n "turnIndex": 4,\n "eventType": "command",\n "createdAt": "2026-06-09T20:00:00Z"\n}`; + const instance = TrajectoryEvent.fromJson(json); + const output = instance.toJson(); + const reloaded = TrajectoryEvent.fromJson(output); + expect(reloaded.id).toEqual(instance.id); + expect(reloaded.sessionId).toEqual(instance.sessionId); + expect(reloaded.turnId).toEqual(instance.turnId); + expect(reloaded.toolCallId).toEqual(instance.toolCallId); + expect(reloaded.turnIndex).toEqual(instance.turnIndex); + expect(reloaded.eventType).toEqual(instance.eventType); + expect(reloaded.createdAt).toEqual(instance.createdAt); + }); + }); + + describe("YAML serialization", () => { + it("should load from YAML - example 1", () => { + const yaml = `id: traj_abc123\nsessionId: sess_abc123\nturnId: turn_001\ntoolCallId: call_abc123\nturnIndex: 4\neventType: command\ncreatedAt: "2026-06-09T20:00:00Z"\n`; + const instance = TrajectoryEvent.fromYaml(yaml); + expect(instance).toBeDefined(); + expect(instance.id).toEqual("traj_abc123"); + expect(instance.sessionId).toEqual("sess_abc123"); + expect(instance.turnId).toEqual("turn_001"); + expect(instance.toolCallId).toEqual("call_abc123"); + expect(instance.turnIndex).toEqual(4); + expect(instance.eventType).toEqual("command"); + expect(instance.createdAt).toEqual("2026-06-09T20:00:00Z"); + }); + + it("should round-trip YAML - example 1", () => { + const yaml = `id: traj_abc123\nsessionId: sess_abc123\nturnId: turn_001\ntoolCallId: call_abc123\nturnIndex: 4\neventType: command\ncreatedAt: "2026-06-09T20:00:00Z"\n`; + const instance = TrajectoryEvent.fromYaml(yaml); + const output = instance.toYaml(); + const reloaded = TrajectoryEvent.fromYaml(output); + expect(reloaded.id).toEqual(instance.id); + expect(reloaded.sessionId).toEqual(instance.sessionId); + expect(reloaded.turnId).toEqual(instance.turnId); + expect(reloaded.toolCallId).toEqual(instance.toolCallId); + expect(reloaded.turnIndex).toEqual(instance.turnIndex); + expect(reloaded.eventType).toEqual(instance.eventType); + expect(reloaded.createdAt).toEqual(instance.createdAt); + }); + }); + + describe("load and save", () => { + it("should load from dictionary", () => { + const data: Record = {}; + const instance = TrajectoryEvent.load(data); + expect(instance).toBeDefined(); + }); + + it("should save to dictionary", () => { + const instance = new TrajectoryEvent(); + const data = instance.save(); + expect(data).toBeDefined(); + expect(typeof data).toBe("object"); + }); + }); +}); diff --git a/schema/model/events/payloads.tsp b/schema/model/events/payloads.tsp index 80774812..9a68f801 100644 --- a/schema/model/events/payloads.tsp +++ b/schema/model/events/payloads.tsp @@ -22,7 +22,11 @@ alias TurnEventType = | "thinking" | "tool_call_start" | "tool_call_complete" + | "tool_execution_start" + | "tool_execution_complete" | "tool_result" + | "hook_start" + | "hook_end" | "status" | "messages_updated" | "done" @@ -179,6 +183,14 @@ model RetryPayload { * Payload for permission request events — a host is asked to approve an action. */ model PermissionRequestedPayload { + @doc("Stable permission request identifier") + @sample(#{ requestId: "perm_abc123" }) + requestId?: string; + + @doc("Associated tool call identifier, when the permission gates a tool call") + @sample(#{ toolCallId: "call_abc123" }) + toolCallId?: string; + @doc("Permission/action name being requested") @sample(#{ permission: "tool.execute" }) permission: string; @@ -189,12 +201,90 @@ model PermissionRequestedPayload { @doc("Additional host-specific permission details") details?: Record; + + @doc("Human-readable prompt or rationale that can be shown to an approval UI") + @sample(#{ promptRequest: "Allow shell to run tests?" }) + promptRequest?: string; + + @doc("Policy metadata used to evaluate or explain the permission request") + policy?: Record; + + @doc("Redaction state for sensitive request fields") + redaction?: RedactionMetadata; } /** * Payload for permission completion events — an approval decision was made. */ model PermissionCompletedPayload { + @doc("Stable permission request identifier") + @sample(#{ requestId: "perm_abc123" }) + requestId?: string; + + @doc("Associated tool call identifier, when the permission gated a tool call") + @sample(#{ toolCallId: "call_abc123" }) + toolCallId?: string; + + @doc("Permission/action name that was decided") + @sample(#{ permission: "tool.execute" }) + permission: string; + + @doc("Whether the requested permission was approved") + @sample(#{ approved: true }) + approved: boolean; + + @doc("Decision reason, if available") + @sample(#{ reason: "user_approved" }) + reason?: string; + + @doc("Host-specific decision result, such as a durable approval token or denial details") + result?: Record; +} + +/** + * Request passed to a permission resolver. This is the live protocol shape; the + * event payloads above can include trace-only metadata such as redaction state. + */ +model PermissionRequest { + @doc("Stable permission request identifier") + @sample(#{ requestId: "perm_abc123" }) + requestId?: string; + + @doc("Associated tool call identifier, when the permission gates a tool call") + @sample(#{ toolCallId: "call_abc123" }) + toolCallId?: string; + + @doc("Permission/action name being requested") + @sample(#{ permission: "tool.execute" }) + permission: string; + + @doc("Resource or tool the permission applies to") + @sample(#{ target: "shell" }) + target?: string; + + @doc("Additional host-specific permission details") + details?: Record; + + @doc("Human-readable prompt or rationale that can be shown to an approval UI") + @sample(#{ promptRequest: "Allow shell to run tests?" }) + promptRequest?: string; + + @doc("Policy metadata used to evaluate or explain the permission request") + policy?: Record; +} + +/** + * Decision returned by a permission resolver. + */ +model PermissionDecision { + @doc("Stable permission request identifier") + @sample(#{ requestId: "perm_abc123" }) + requestId?: string; + + @doc("Associated tool call identifier, when the permission gated a tool call") + @sample(#{ toolCallId: "call_abc123" }) + toolCallId?: string; + @doc("Permission/action name that was decided") @sample(#{ permission: "tool.execute" }) permission: string; @@ -206,6 +296,9 @@ model PermissionCompletedPayload { @doc("Decision reason, if available") @sample(#{ reason: "user_approved" }) reason?: string; + + @doc("Host-specific decision result, such as a durable approval token or denial details") + result?: Record; } /** @@ -271,6 +364,191 @@ model ToolCallCompletePayload { errorKind?: string; } +/** + * Payload for "tool_execution_start" events — the host is about to execute a concrete tool request. + * + * This is distinct from "tool_call_start", which records the model requesting a tool. + * Tool execution events capture the harness-side action after policy and permission checks. + */ +model ToolExecutionStartPayload { + @doc("Stable host execution request identifier") + @sample(#{ requestId: "exec_abc123" }) + requestId?: string; + + @doc("Associated model tool call identifier, when available") + @sample(#{ toolCallId: "call_abc123" }) + toolCallId?: string; + + @doc("Name of the host tool being executed") + @sample(#{ toolName: "powershell" }) + toolName: string; + + @doc("Tool arguments after host-side sanitization") + arguments?: Record; + + @doc("Working directory or execution scope for the tool") + @sample(#{ workingDirectory: "/workspace/project" }) + workingDirectory?: string; + + @doc("Redaction state for sensitive argument fields") + redaction?: RedactionMetadata; +} + +/** + * Payload for "tool_execution_complete" events — a concrete host tool execution finished. + */ +model ToolExecutionCompletePayload { + @doc("Stable host execution request identifier") + @sample(#{ requestId: "exec_abc123" }) + requestId?: string; + + @doc("Associated model tool call identifier, when available") + @sample(#{ toolCallId: "call_abc123" }) + toolCallId?: string; + + @doc("Name of the host tool that executed") + @sample(#{ toolName: "powershell" }) + toolName: string; + + @doc("Whether the host execution completed successfully") + @sample(#{ success: true }) + success: boolean; + + @doc("Host-normalized execution result") + result?: unknown; + + @doc("Process or host exit code, when applicable") + @sample(#{ exitCode: 0 }) + exitCode?: int32; + + @doc("Tool execution duration in milliseconds") + @sample(#{ durationMs: 250 }) + durationMs?: float64; + + @doc("Machine-readable error category when success is false") + @sample(#{ errorKind: "timeout" }) + errorKind?: string; + + @doc("Host-specific telemetry for the execution") + telemetry?: Record; + + @doc("Redaction state for sensitive result fields") + redaction?: RedactionMetadata; +} + +/** + * Request passed to a host tool executor after policy and permission checks. + */ +model HostToolRequest { + @doc("Stable host execution request identifier") + @sample(#{ requestId: "exec_abc123" }) + requestId?: string; + + @doc("Associated model tool call identifier, when available") + @sample(#{ toolCallId: "call_abc123" }) + toolCallId?: string; + + @doc("Name of the host tool being executed") + @sample(#{ toolName: "powershell" }) + toolName: string; + + @doc("Tool arguments after host-side sanitization") + arguments?: Record; + + @doc("Working directory or execution scope for the tool") + @sample(#{ workingDirectory: "/workspace/project" }) + workingDirectory?: string; +} + +/** + * Result returned by a host tool executor. + */ +model HostToolResult { + @doc("Stable host execution request identifier") + @sample(#{ requestId: "exec_abc123" }) + requestId?: string; + + @doc("Associated model tool call identifier, when available") + @sample(#{ toolCallId: "call_abc123" }) + toolCallId?: string; + + @doc("Name of the host tool that executed") + @sample(#{ toolName: "powershell" }) + toolName: string; + + @doc("Whether the host execution completed successfully") + @sample(#{ success: true }) + success: boolean; + + @doc("Host-normalized execution result") + result?: unknown; + + @doc("Process or host exit code, when applicable") + @sample(#{ exitCode: 0 }) + exitCode?: int32; + + @doc("Tool execution duration in milliseconds") + @sample(#{ durationMs: 250 }) + durationMs?: float64; + + @doc("Machine-readable error category when success is false") + @sample(#{ errorKind: "timeout" }) + errorKind?: string; + + @doc("Host-specific telemetry for the execution") + telemetry?: Record; +} + +/** + * Payload for "hook_start" events — a host lifecycle hook is beginning. + */ +model HookStartPayload { + @doc("Stable hook invocation identifier") + @sample(#{ hookInvocationId: "hook_abc123" }) + hookInvocationId: string; + + @doc("Host-defined hook type") + @sample(#{ hookType: "preToolUse" }) + hookType: string; + + @doc("Hook input after host-side sanitization") + input?: Record; + + @doc("Redaction state for sensitive hook input fields") + redaction?: RedactionMetadata; +} + +/** + * Payload for "hook_end" events — a host lifecycle hook finished. + */ +model HookEndPayload { + @doc("Stable hook invocation identifier") + @sample(#{ hookInvocationId: "hook_abc123" }) + hookInvocationId: string; + + @doc("Host-defined hook type") + @sample(#{ hookType: "preToolUse" }) + hookType: string; + + @doc("Whether the hook completed successfully") + @sample(#{ success: true }) + success: boolean; + + @doc("Hook output after host-side sanitization") + output?: Record; + + @doc("Hook execution duration in milliseconds") + @sample(#{ durationMs: 12 }) + durationMs?: float64; + + @doc("Human-readable error when success is false") + @sample(#{ error: "hook failed" }) + error?: string; + + @doc("Redaction state for sensitive hook output fields") + redaction?: RedactionMetadata; +} + /** * Payload for "tool_result" events — a tool has returned its result. */ @@ -435,3 +713,41 @@ model TurnTrace { @doc("Optional summary computed from the event stream") summary?: TurnSummary; } + +/** + * How a sensitive field was handled before persistence or emission. + */ +alias RedactionMode = "none" | "redacted" | "hashed" | "summary" | "reference"; + +/** + * Redaction handling for one JSON-shaped field path. + */ +model RedactedField { + @doc("JSONPath-like field path, relative to the containing payload") + @sample(#{ path: "$.arguments.apiKey" }) + path: string; + + @doc("How the field was represented") + @sample(#{ mode: "redacted" }) + mode: RedactionMode; + + @doc("Human-readable reason or policy that caused this handling") + @sample(#{ reason: "secret" }) + reason?: string; +} + +/** + * Metadata describing whether and how a payload was sanitized. + */ +model RedactionMetadata { + @doc("Whether the payload has been sanitized for persistence or external display") + @sample(#{ sanitized: true }) + sanitized?: boolean = false; + + @doc("Field-level redaction details") + fields?: RedactedField[]; + + @doc("Host policy or sanitizer version that produced this metadata") + @sample(#{ policy: "default-v1" }) + policy?: string; +} diff --git a/schema/model/events/session.tsp b/schema/model/events/session.tsp new file mode 100644 index 00000000..37fac077 --- /dev/null +++ b/schema/model/events/session.tsp @@ -0,0 +1,368 @@ +import "prompty-emitter"; +import "../model/usage.tsp"; +import "./payloads.tsp"; + +namespace Prompty; + +/** + * The type of event emitted by an outer agent harness session. Session events + * capture lifecycle and persistence concerns that sit below any particular UI + * but above a single model turn. + */ +alias SessionEventType = + | "session_start" + | "session_end" + | "session_warning" + | "session_hook_start" + | "session_hook_end" + | "checkpoint_created" + | "trajectory_event"; + +/** + * Final semantic status for an outer harness session end event. + */ +alias SessionEndStatus = "success" | "error" | "cancelled" | "interrupted"; + +/** + * Final semantic status for a summarized harness session. + * + * This intentionally mirrors SessionEndStatus but remains a distinct alias + * because some language generators emit enum aliases in each model file. + */ +alias SessionSummaryStatus = "success" | "error" | "cancelled" | "interrupted"; + +/** + * Execution context associated with a harness session. Host-specific + * environments can store detailed profiles in metadata without making the core + * contract depend on one source-control provider or workspace shape. + */ +model HarnessContext { + @doc("Current working directory for the harness") + @sample(#{ cwd: "/workspace/project" }) + cwd?: string; + + @doc("Git repository root, when known") + @sample(#{ gitRoot: "/workspace/project" }) + gitRoot?: string; + + @doc("Host-defined context metadata, such as source-control or sandbox details") + metadata?: Record; +} + +/** + * Payload for "session_start" events. + */ +model SessionStartPayload { + @doc("Stable session identifier") + @sample(#{ sessionId: "sess_abc123" }) + sessionId: string; + + @doc("Session event schema version") + @sample(#{ version: 1 }) + version?: int32 = 1; + + @doc("Producer that started the session") + @sample(#{ producer: "prompty-agent" }) + producer?: string; + + @doc("Runtime that produced the session") + @sample(#{ runtime: "typescript" }) + runtime?: string; + + @doc("Prompty library version") + @sample(#{ promptyVersion: "2.0.0" }) + promptyVersion?: string; + + @doc("ISO 8601 UTC timestamp when the session started") + @sample(#{ startTime: "2026-06-09T20:00:00Z" }) + startTime?: string; + + @doc("Selected model identifier, when known") + @sample(#{ selectedModel: "gpt-4o-mini" }) + selectedModel?: string; + + @doc("Selected reasoning effort or equivalent model setting, when known") + @sample(#{ reasoningEffort: "medium" }) + reasoningEffort?: string; + + @doc("Repository and execution context") + context?: HarnessContext; +} + +/** + * Payload for "session_end" events. + */ +model SessionEndPayload { + @doc("Stable session identifier") + @sample(#{ sessionId: "sess_abc123" }) + sessionId?: string; + + @doc("Final session status") + @sample(#{ status: "success" }) + status?: SessionEndStatus; + + @doc("Host-specific reason the session ended") + @sample(#{ reason: "complete" }) + reason?: string; + + @doc("Total elapsed session duration in milliseconds") + @sample(#{ durationMs: 12500 }) + durationMs?: float64; +} + +/** + * Payload for "session_warning" events. + */ +model SessionWarningPayload { + @doc("Stable machine-readable warning category") + @sample(#{ warningType: "remote" }) + warningType: string; + + @doc("Human-readable warning message") + @sample(#{ message: "Remote session disabled" }) + message: string; + + @doc("Additional host-specific warning details") + details?: Record; +} + +/** + * A canonical event envelope emitted by an outer harness session. + */ +model SessionEvent { + @doc("Unique identifier for this event") + @sample(#{ id: "evt_abc123" }) + id: string; + + @doc("Event type discriminator") + type: SessionEventType; + + @doc("ISO 8601 UTC timestamp when the event was emitted") + @sample(#{ timestamp: "2026-06-09T20:00:00Z" }) + timestamp: string; + + @doc("Stable identifier for the outer session") + @sample(#{ sessionId: "sess_abc123" }) + sessionId?: string; + + @doc("Associated turn identifier, when this session event is linked to a turn") + @sample(#{ turnId: "turn_001" }) + turnId?: string; + + @doc("Parent event or span identifier for reconstructing event hierarchy") + @sample(#{ parentId: "evt_parent" }) + parentId?: string; + + @doc("Trace span identifier associated with this event") + @sample(#{ spanId: "span_hook_001" }) + spanId?: string; + + @doc("Event-specific payload. Use the typed payload model matching 'type'.") + payload: Record = #{}; + + @doc("Redaction state for sensitive payload fields") + redaction?: RedactionMetadata; +} + +/** + * A persisted handoff point for a harness session. + */ +model Checkpoint { + @doc("Stable checkpoint identifier") + @sample(#{ id: "chk_abc123" }) + id?: string; + + @doc("Stable session identifier") + @sample(#{ sessionId: "sess_abc123" }) + sessionId?: string; + + @doc("Associated turn identifier, when the checkpoint was created inside a turn") + @sample(#{ turnId: "turn_001" }) + turnId?: string; + + @doc("Monotonic checkpoint number within the session") + @sample(#{ checkpointNumber: 3 }) + checkpointNumber?: int32; + + @doc("Short checkpoint title") + @sample(#{ title: "Added harness contracts" }) + title: string; + + @doc("Short human-readable overview") + overview?: string; + + @doc("Portable checkpoint state needed to resume or hand off the session") + state?: Record; + + @doc("Optional host-authored summary or handoff note") + summary?: string; + + @doc("Host-defined checkpoint metadata") + metadata?: Record; + + @doc("ISO 8601 UTC timestamp when the checkpoint was created") + @sample(#{ createdAt: "2026-06-09T20:00:00Z" }) + createdAt?: string; + + @doc("Redaction state for sensitive checkpoint fields") + redaction?: RedactionMetadata; +} + +/** + * A compact, replay-oriented record of one harness-side action or observation. + */ +model TrajectoryEvent { + @doc("Stable trajectory event identifier") + @sample(#{ id: "traj_abc123" }) + id?: string; + + @doc("Stable session identifier") + @sample(#{ sessionId: "sess_abc123" }) + sessionId?: string; + + @doc("Associated turn identifier, when available") + @sample(#{ turnId: "turn_001" }) + turnId?: string; + + @doc("Associated tool call identifier, when available") + @sample(#{ toolCallId: "call_abc123" }) + toolCallId?: string; + + @doc("Zero-based turn index in the session") + @sample(#{ turnIndex: 4 }) + turnIndex?: int32; + + @doc("Host-defined trajectory event category") + @sample(#{ eventType: "command" }) + eventType: string; + + @doc("Sanitized event data") + data?: Record; + + @doc("ISO 8601 UTC timestamp when the trajectory event was recorded") + @sample(#{ createdAt: "2026-06-09T20:00:00Z" }) + createdAt?: string; + + @doc("Redaction state for sensitive trajectory fields") + redaction?: RedactionMetadata; +} + +/** + * A file observed or touched by a harness session. + */ +model SessionFileRef { + @doc("Stable session identifier") + @sample(#{ sessionId: "sess_abc123" }) + sessionId?: string; + + @doc("File path, relative to the harness workspace when possible") + @sample(#{ path: "src/index.ts" }) + path: string; + + @doc("Tool that first observed the file, when known") + @sample(#{ toolName: "view" }) + toolName?: string; + + @doc("Zero-based turn index where the file was first observed") + @sample(#{ turnIndex: 2 }) + turnIndex?: int32; + + @doc("ISO 8601 UTC timestamp when the file was first observed") + @sample(#{ firstSeenAt: "2026-06-09T20:00:00Z" }) + firstSeenAt?: string; +} + +/** + * A non-file reference observed by a harness session. + */ +model SessionRef { + @doc("Stable session identifier") + @sample(#{ sessionId: "sess_abc123" }) + sessionId?: string; + + @doc("Reference category") + @sample(#{ refType: "issue" }) + refType: string; + + @doc("Reference value") + @sample(#{ refValue: "owner/repo#123" }) + refValue: string; + + @doc("Zero-based turn index where the reference was first observed") + @sample(#{ turnIndex: 2 }) + turnIndex?: int32; + + @doc("ISO 8601 UTC timestamp when the reference was recorded") + @sample(#{ createdAt: "2026-06-09T20:00:00Z" }) + createdAt?: string; +} + +/** + * Summary statistics for a completed session trace. + */ +model SessionSummary { + @doc("Stable session identifier") + @sample(#{ sessionId: "sess_abc123" }) + sessionId: string; + + @doc("Final session status") + @sample(#{ status: "success" }) + status?: SessionSummaryStatus; + + @doc("Number of user/assistant turns in the session") + @sample(#{ turns: 5 }) + turns?: int32; + + @doc("Number of checkpoints created") + @sample(#{ checkpoints: 2 }) + checkpoints?: int32; + + @doc("Aggregated token usage for the session") + usage?: TokenUsage; + + @doc("Total elapsed session duration in milliseconds") + @sample(#{ durationMs: 12500 }) + durationMs?: float64; +} + +/** + * Portable replay container for an outer harness session. + */ +model SessionTrace { + @doc("Trace schema version") + @sample(#{ version: "1" }) + version: string = "1"; + + @doc("Runtime name that produced the trace") + @sample(#{ runtime: "typescript" }) + runtime?: string; + + @doc("Prompty library version that produced the trace") + @sample(#{ promptyVersion: "2.0.0" }) + promptyVersion?: string; + + @doc("Stable session identifier") + @sample(#{ sessionId: "sess_abc123" }) + sessionId?: string; + + @doc("Recorded session events in emission order") + events: SessionEvent[]; + + @doc("Recorded turn traces associated with the session") + turns?: TurnTrace[]; + + @doc("Checkpoints created during the session") + checkpoints?: Checkpoint[]; + + @doc("Compact trajectory records associated with the session") + trajectory?: TrajectoryEvent[]; + + @doc("Files observed or touched during the session") + files?: SessionFileRef[]; + + @doc("Non-file references observed during the session") + refs?: SessionRef[]; + + @doc("Optional summary computed from the event stream") + summary?: SessionSummary; +} diff --git a/schema/model/main.tsp b/schema/model/main.tsp index a10c6ec5..ef2cfefa 100644 --- a/schema/model/main.tsp +++ b/schema/model/main.tsp @@ -24,10 +24,12 @@ import "./pipeline/renderer.tsp"; import "./pipeline/parser.tsp"; import "./pipeline/executor.tsp"; import "./pipeline/processor.tsp"; +import "./pipeline/harness.tsp"; // Events import "./events/payloads.tsp"; import "./events/stream-chunks.tsp"; +import "./events/session.tsp"; // Streaming import "./streaming/stream.tsp"; diff --git a/schema/model/pipeline/harness.tsp b/schema/model/pipeline/harness.tsp new file mode 100644 index 00000000..e33fe0b2 --- /dev/null +++ b/schema/model/pipeline/harness.tsp @@ -0,0 +1,100 @@ +import "prompty-emitter"; +import "../events/payloads.tsp"; +import "../events/session.tsp"; + +namespace Prompty; + +@@protocol(EventSink); +@@method(EventSink, + "emitTurn", + "boolean", + "Emit a typed turn event to a host sink", + #{ turnEvent: "TurnEvent" }, + false, + true +); +@@method(EventSink, + "emitSession", + "boolean", + "Emit a typed session event to a host sink", + #{ sessionEvent: "SessionEvent" }, + false, + true +); + +/** Receives typed turn and session events from a harness. */ +model EventSink {} + +@@protocol(TraceWriter); +@@method(TraceWriter, + "appendTurn", + "boolean", + "Append a turn event to a replayable trace", + #{ turnEvent: "TurnEvent" }, + false, + true +); +@@method(TraceWriter, + "appendSession", + "boolean", + "Append a session event to a replayable trace", + #{ sessionEvent: "SessionEvent" }, + false, + true +); +@@method(TraceWriter, + "close", + "boolean", + "Finalize the trace with an optional session summary", + #{ summary: "SessionSummary?" }, + false, + true +); + +/** Persists typed events to a replayable trace. */ +model TraceWriter {} + +@@protocol(PermissionResolver); +@@method(PermissionResolver, + "request", + "PermissionDecision", + "Resolve a host permission request", + #{ request: "PermissionRequest" } +); + +/** Resolves host permission requests for potentially sensitive actions. */ +model PermissionResolver {} + +@@protocol(CheckpointStore); +@@method(CheckpointStore, + "save", + "Checkpoint", + "Persist a session checkpoint and return the stored checkpoint", + #{ checkpoint: "Checkpoint" } +); +@@method(CheckpointStore, + "load", + "Checkpoint?", + "Load a checkpoint by session and checkpoint identifier", + #{ sessionId: "string", checkpointId: "string" } +); +@@method(CheckpointStore, + "listCheckpoints", + "Checkpoint[]", + "List checkpoints for a session", + #{ sessionId: "string" } +); + +/** Stores and retrieves resumable session checkpoints. */ +model CheckpointStore {} + +@@protocol(HostToolExecutor); +@@method(HostToolExecutor, + "execute", + "HostToolResult", + "Execute a concrete host tool request and return its completion payload", + #{ request: "HostToolRequest" } +); + +/** Executes host tools after policy and permission checks. */ +model HostToolExecutor {} diff --git a/vscode/prompty/schemas/Checkpoint.yaml b/vscode/prompty/schemas/Checkpoint.yaml new file mode 100644 index 00000000..41d257f5 --- /dev/null +++ b/vscode/prompty/schemas/Checkpoint.yaml @@ -0,0 +1,42 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: Checkpoint.yaml +type: object +properties: + id: + type: string + description: Stable checkpoint identifier + sessionId: + type: string + description: Stable session identifier + turnId: + type: string + description: Associated turn identifier, when the checkpoint was created inside a turn + checkpointNumber: + type: integer + minimum: -2147483648 + maximum: 2147483647 + description: Monotonic checkpoint number within the session + title: + type: string + description: Short checkpoint title + overview: + type: string + description: Short human-readable overview + state: + $ref: RecordUnknown.yaml + description: Portable checkpoint state needed to resume or hand off the session + summary: + type: string + description: Optional host-authored summary or handoff note + metadata: + $ref: RecordUnknown.yaml + description: Host-defined checkpoint metadata + createdAt: + type: string + description: ISO 8601 UTC timestamp when the checkpoint was created + redaction: + $ref: RedactionMetadata.yaml + description: Redaction state for sensitive checkpoint fields +required: + - title +description: A persisted handoff point for a harness session. diff --git a/vscode/prompty/schemas/CheckpointStore.yaml b/vscode/prompty/schemas/CheckpointStore.yaml new file mode 100644 index 00000000..6e6b4f50 --- /dev/null +++ b/vscode/prompty/schemas/CheckpointStore.yaml @@ -0,0 +1,5 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: CheckpointStore.yaml +type: object +properties: {} +description: Stores and retrieves resumable session checkpoints. diff --git a/vscode/prompty/schemas/EventSink.yaml b/vscode/prompty/schemas/EventSink.yaml new file mode 100644 index 00000000..0f3c184e --- /dev/null +++ b/vscode/prompty/schemas/EventSink.yaml @@ -0,0 +1,5 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: EventSink.yaml +type: object +properties: {} +description: Receives typed turn and session events from a harness. diff --git a/vscode/prompty/schemas/HarnessContext.yaml b/vscode/prompty/schemas/HarnessContext.yaml new file mode 100644 index 00000000..61b8cb0e --- /dev/null +++ b/vscode/prompty/schemas/HarnessContext.yaml @@ -0,0 +1,17 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: HarnessContext.yaml +type: object +properties: + cwd: + type: string + description: Current working directory for the harness + gitRoot: + type: string + description: Git repository root, when known + metadata: + $ref: RecordUnknown.yaml + description: Host-defined context metadata, such as source-control or sandbox details +description: |- + Execution context associated with a harness session. Host-specific + environments can store detailed profiles in metadata without making the core + contract depend on one source-control provider or workspace shape. diff --git a/vscode/prompty/schemas/HookEndPayload.yaml b/vscode/prompty/schemas/HookEndPayload.yaml new file mode 100644 index 00000000..f68b7242 --- /dev/null +++ b/vscode/prompty/schemas/HookEndPayload.yaml @@ -0,0 +1,30 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: HookEndPayload.yaml +type: object +properties: + hookInvocationId: + type: string + description: Stable hook invocation identifier + hookType: + type: string + description: Host-defined hook type + success: + type: boolean + description: Whether the hook completed successfully + output: + $ref: RecordUnknown.yaml + description: Hook output after host-side sanitization + durationMs: + type: number + description: Hook execution duration in milliseconds + error: + type: string + description: Human-readable error when success is false + redaction: + $ref: RedactionMetadata.yaml + description: Redaction state for sensitive hook output fields +required: + - hookInvocationId + - hookType + - success +description: Payload for "hook_end" events — a host lifecycle hook finished. diff --git a/vscode/prompty/schemas/HookStartPayload.yaml b/vscode/prompty/schemas/HookStartPayload.yaml new file mode 100644 index 00000000..6505ae59 --- /dev/null +++ b/vscode/prompty/schemas/HookStartPayload.yaml @@ -0,0 +1,20 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: HookStartPayload.yaml +type: object +properties: + hookInvocationId: + type: string + description: Stable hook invocation identifier + hookType: + type: string + description: Host-defined hook type + input: + $ref: RecordUnknown.yaml + description: Hook input after host-side sanitization + redaction: + $ref: RedactionMetadata.yaml + description: Redaction state for sensitive hook input fields +required: + - hookInvocationId + - hookType +description: Payload for "hook_start" events — a host lifecycle hook is beginning. diff --git a/vscode/prompty/schemas/HostToolExecutor.yaml b/vscode/prompty/schemas/HostToolExecutor.yaml new file mode 100644 index 00000000..63f870c5 --- /dev/null +++ b/vscode/prompty/schemas/HostToolExecutor.yaml @@ -0,0 +1,5 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: HostToolExecutor.yaml +type: object +properties: {} +description: Executes host tools after policy and permission checks. diff --git a/vscode/prompty/schemas/HostToolRequest.yaml b/vscode/prompty/schemas/HostToolRequest.yaml new file mode 100644 index 00000000..5ddd117d --- /dev/null +++ b/vscode/prompty/schemas/HostToolRequest.yaml @@ -0,0 +1,22 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: HostToolRequest.yaml +type: object +properties: + requestId: + type: string + description: Stable host execution request identifier + toolCallId: + type: string + description: Associated model tool call identifier, when available + toolName: + type: string + description: Name of the host tool being executed + arguments: + $ref: RecordUnknown.yaml + description: Tool arguments after host-side sanitization + workingDirectory: + type: string + description: Working directory or execution scope for the tool +required: + - toolName +description: Request passed to a host tool executor after policy and permission checks. diff --git a/vscode/prompty/schemas/HostToolResult.yaml b/vscode/prompty/schemas/HostToolResult.yaml new file mode 100644 index 00000000..07f86d34 --- /dev/null +++ b/vscode/prompty/schemas/HostToolResult.yaml @@ -0,0 +1,36 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: HostToolResult.yaml +type: object +properties: + requestId: + type: string + description: Stable host execution request identifier + toolCallId: + type: string + description: Associated model tool call identifier, when available + toolName: + type: string + description: Name of the host tool that executed + success: + type: boolean + description: Whether the host execution completed successfully + result: + description: Host-normalized execution result + exitCode: + type: integer + minimum: -2147483648 + maximum: 2147483647 + description: Process or host exit code, when applicable + durationMs: + type: number + description: Tool execution duration in milliseconds + errorKind: + type: string + description: Machine-readable error category when success is false + telemetry: + $ref: RecordUnknown.yaml + description: Host-specific telemetry for the execution +required: + - toolName + - success +description: Result returned by a host tool executor. diff --git a/vscode/prompty/schemas/PermissionCompletedPayload.yaml b/vscode/prompty/schemas/PermissionCompletedPayload.yaml index 569c70e8..d6873573 100644 --- a/vscode/prompty/schemas/PermissionCompletedPayload.yaml +++ b/vscode/prompty/schemas/PermissionCompletedPayload.yaml @@ -2,6 +2,12 @@ $schema: https://json-schema.org/draft/2020-12/schema $id: PermissionCompletedPayload.yaml type: object properties: + requestId: + type: string + description: Stable permission request identifier + toolCallId: + type: string + description: Associated tool call identifier, when the permission gated a tool call permission: type: string description: Permission/action name that was decided @@ -11,6 +17,9 @@ properties: reason: type: string description: Decision reason, if available + result: + $ref: RecordUnknown.yaml + description: Host-specific decision result, such as a durable approval token or denial details required: - permission - approved diff --git a/vscode/prompty/schemas/PermissionDecision.yaml b/vscode/prompty/schemas/PermissionDecision.yaml new file mode 100644 index 00000000..55b25174 --- /dev/null +++ b/vscode/prompty/schemas/PermissionDecision.yaml @@ -0,0 +1,26 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: PermissionDecision.yaml +type: object +properties: + requestId: + type: string + description: Stable permission request identifier + toolCallId: + type: string + description: Associated tool call identifier, when the permission gated a tool call + permission: + type: string + description: Permission/action name that was decided + approved: + type: boolean + description: Whether the requested permission was approved + reason: + type: string + description: Decision reason, if available + result: + $ref: RecordUnknown.yaml + description: Host-specific decision result, such as a durable approval token or denial details +required: + - permission + - approved +description: Decision returned by a permission resolver. diff --git a/vscode/prompty/schemas/PermissionRequest.yaml b/vscode/prompty/schemas/PermissionRequest.yaml new file mode 100644 index 00000000..4239ae8e --- /dev/null +++ b/vscode/prompty/schemas/PermissionRequest.yaml @@ -0,0 +1,30 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: PermissionRequest.yaml +type: object +properties: + requestId: + type: string + description: Stable permission request identifier + toolCallId: + type: string + description: Associated tool call identifier, when the permission gates a tool call + permission: + type: string + description: Permission/action name being requested + target: + type: string + description: Resource or tool the permission applies to + details: + $ref: RecordUnknown.yaml + description: Additional host-specific permission details + promptRequest: + type: string + description: Human-readable prompt or rationale that can be shown to an approval UI + policy: + $ref: RecordUnknown.yaml + description: Policy metadata used to evaluate or explain the permission request +required: + - permission +description: |- + Request passed to a permission resolver. This is the live protocol shape; the + event payloads above can include trace-only metadata such as redaction state. diff --git a/vscode/prompty/schemas/PermissionRequestedPayload.yaml b/vscode/prompty/schemas/PermissionRequestedPayload.yaml index b29983af..a96bef7e 100644 --- a/vscode/prompty/schemas/PermissionRequestedPayload.yaml +++ b/vscode/prompty/schemas/PermissionRequestedPayload.yaml @@ -2,6 +2,12 @@ $schema: https://json-schema.org/draft/2020-12/schema $id: PermissionRequestedPayload.yaml type: object properties: + requestId: + type: string + description: Stable permission request identifier + toolCallId: + type: string + description: Associated tool call identifier, when the permission gates a tool call permission: type: string description: Permission/action name being requested @@ -11,6 +17,15 @@ properties: details: $ref: RecordUnknown.yaml description: Additional host-specific permission details + promptRequest: + type: string + description: Human-readable prompt or rationale that can be shown to an approval UI + policy: + $ref: RecordUnknown.yaml + description: Policy metadata used to evaluate or explain the permission request + redaction: + $ref: RedactionMetadata.yaml + description: Redaction state for sensitive request fields required: - permission description: Payload for permission request events — a host is asked to approve an action. diff --git a/vscode/prompty/schemas/PermissionResolver.yaml b/vscode/prompty/schemas/PermissionResolver.yaml new file mode 100644 index 00000000..7bc3d895 --- /dev/null +++ b/vscode/prompty/schemas/PermissionResolver.yaml @@ -0,0 +1,5 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: PermissionResolver.yaml +type: object +properties: {} +description: Resolves host permission requests for potentially sensitive actions. diff --git a/vscode/prompty/schemas/RedactedField.yaml b/vscode/prompty/schemas/RedactedField.yaml new file mode 100644 index 00000000..53887a45 --- /dev/null +++ b/vscode/prompty/schemas/RedactedField.yaml @@ -0,0 +1,27 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: RedactedField.yaml +type: object +properties: + path: + type: string + description: JSONPath-like field path, relative to the containing payload + mode: + anyOf: + - type: string + const: none + - type: string + const: redacted + - type: string + const: hashed + - type: string + const: summary + - type: string + const: reference + description: How the field was represented + reason: + type: string + description: Human-readable reason or policy that caused this handling +required: + - path + - mode +description: Redaction handling for one JSON-shaped field path. diff --git a/vscode/prompty/schemas/RedactionMetadata.yaml b/vscode/prompty/schemas/RedactionMetadata.yaml new file mode 100644 index 00000000..6a398f3e --- /dev/null +++ b/vscode/prompty/schemas/RedactionMetadata.yaml @@ -0,0 +1,17 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: RedactionMetadata.yaml +type: object +properties: + sanitized: + type: boolean + default: false + description: Whether the payload has been sanitized for persistence or external display + fields: + type: array + items: + $ref: RedactedField.yaml + description: Field-level redaction details + policy: + type: string + description: Host policy or sanitizer version that produced this metadata +description: Metadata describing whether and how a payload was sanitized. diff --git a/vscode/prompty/schemas/SessionEndPayload.yaml b/vscode/prompty/schemas/SessionEndPayload.yaml new file mode 100644 index 00000000..33ca32ac --- /dev/null +++ b/vscode/prompty/schemas/SessionEndPayload.yaml @@ -0,0 +1,25 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: SessionEndPayload.yaml +type: object +properties: + sessionId: + type: string + description: Stable session identifier + status: + anyOf: + - type: string + const: success + - type: string + const: error + - type: string + const: cancelled + - type: string + const: interrupted + description: Final session status + reason: + type: string + description: Host-specific reason the session ended + durationMs: + type: number + description: Total elapsed session duration in milliseconds +description: Payload for "session_end" events. diff --git a/vscode/prompty/schemas/SessionEvent.yaml b/vscode/prompty/schemas/SessionEvent.yaml new file mode 100644 index 00000000..c1af6a3c --- /dev/null +++ b/vscode/prompty/schemas/SessionEvent.yaml @@ -0,0 +1,52 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: SessionEvent.yaml +type: object +properties: + id: + type: string + description: Unique identifier for this event + type: + anyOf: + - type: string + const: session_start + - type: string + const: session_end + - type: string + const: session_warning + - type: string + const: session_hook_start + - type: string + const: session_hook_end + - type: string + const: checkpoint_created + - type: string + const: trajectory_event + description: Event type discriminator + timestamp: + type: string + description: ISO 8601 UTC timestamp when the event was emitted + sessionId: + type: string + description: Stable identifier for the outer session + turnId: + type: string + description: Associated turn identifier, when this session event is linked to a turn + parentId: + type: string + description: Parent event or span identifier for reconstructing event hierarchy + spanId: + type: string + description: Trace span identifier associated with this event + payload: + $ref: RecordUnknown.yaml + default: {} + description: Event-specific payload. Use the typed payload model matching 'type'. + redaction: + $ref: RedactionMetadata.yaml + description: Redaction state for sensitive payload fields +required: + - id + - type + - timestamp + - payload +description: A canonical event envelope emitted by an outer harness session. diff --git a/vscode/prompty/schemas/SessionFileRef.yaml b/vscode/prompty/schemas/SessionFileRef.yaml new file mode 100644 index 00000000..1d79ae62 --- /dev/null +++ b/vscode/prompty/schemas/SessionFileRef.yaml @@ -0,0 +1,24 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: SessionFileRef.yaml +type: object +properties: + sessionId: + type: string + description: Stable session identifier + path: + type: string + description: File path, relative to the harness workspace when possible + toolName: + type: string + description: Tool that first observed the file, when known + turnIndex: + type: integer + minimum: -2147483648 + maximum: 2147483647 + description: Zero-based turn index where the file was first observed + firstSeenAt: + type: string + description: ISO 8601 UTC timestamp when the file was first observed +required: + - path +description: A file observed or touched by a harness session. diff --git a/vscode/prompty/schemas/SessionRef.yaml b/vscode/prompty/schemas/SessionRef.yaml new file mode 100644 index 00000000..18c1fce3 --- /dev/null +++ b/vscode/prompty/schemas/SessionRef.yaml @@ -0,0 +1,25 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: SessionRef.yaml +type: object +properties: + sessionId: + type: string + description: Stable session identifier + refType: + type: string + description: Reference category + refValue: + type: string + description: Reference value + turnIndex: + type: integer + minimum: -2147483648 + maximum: 2147483647 + description: Zero-based turn index where the reference was first observed + createdAt: + type: string + description: ISO 8601 UTC timestamp when the reference was recorded +required: + - refType + - refValue +description: A non-file reference observed by a harness session. diff --git a/vscode/prompty/schemas/SessionStartPayload.yaml b/vscode/prompty/schemas/SessionStartPayload.yaml new file mode 100644 index 00000000..a12a41ec --- /dev/null +++ b/vscode/prompty/schemas/SessionStartPayload.yaml @@ -0,0 +1,37 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: SessionStartPayload.yaml +type: object +properties: + sessionId: + type: string + description: Stable session identifier + version: + type: integer + minimum: -2147483648 + maximum: 2147483647 + default: 1 + description: Session event schema version + producer: + type: string + description: Producer that started the session + runtime: + type: string + description: Runtime that produced the session + promptyVersion: + type: string + description: Prompty library version + startTime: + type: string + description: ISO 8601 UTC timestamp when the session started + selectedModel: + type: string + description: Selected model identifier, when known + reasoningEffort: + type: string + description: Selected reasoning effort or equivalent model setting, when known + context: + $ref: HarnessContext.yaml + description: Repository and execution context +required: + - sessionId +description: Payload for "session_start" events. diff --git a/vscode/prompty/schemas/SessionSummary.yaml b/vscode/prompty/schemas/SessionSummary.yaml new file mode 100644 index 00000000..d2e1d3c3 --- /dev/null +++ b/vscode/prompty/schemas/SessionSummary.yaml @@ -0,0 +1,37 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: SessionSummary.yaml +type: object +properties: + sessionId: + type: string + description: Stable session identifier + status: + anyOf: + - type: string + const: success + - type: string + const: error + - type: string + const: cancelled + - type: string + const: interrupted + description: Final session status + turns: + type: integer + minimum: -2147483648 + maximum: 2147483647 + description: Number of user/assistant turns in the session + checkpoints: + type: integer + minimum: -2147483648 + maximum: 2147483647 + description: Number of checkpoints created + usage: + $ref: TokenUsage.yaml + description: Aggregated token usage for the session + durationMs: + type: number + description: Total elapsed session duration in milliseconds +required: + - sessionId +description: Summary statistics for a completed session trace. diff --git a/vscode/prompty/schemas/SessionTrace.yaml b/vscode/prompty/schemas/SessionTrace.yaml new file mode 100644 index 00000000..1a3af4b9 --- /dev/null +++ b/vscode/prompty/schemas/SessionTrace.yaml @@ -0,0 +1,54 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: SessionTrace.yaml +type: object +properties: + version: + type: string + default: "1" + description: Trace schema version + runtime: + type: string + description: Runtime name that produced the trace + promptyVersion: + type: string + description: Prompty library version that produced the trace + sessionId: + type: string + description: Stable session identifier + events: + type: array + items: + $ref: SessionEvent.yaml + description: Recorded session events in emission order + turns: + type: array + items: + $ref: TurnTrace.yaml + description: Recorded turn traces associated with the session + checkpoints: + type: array + items: + $ref: Checkpoint.yaml + description: Checkpoints created during the session + trajectory: + type: array + items: + $ref: TrajectoryEvent.yaml + description: Compact trajectory records associated with the session + files: + type: array + items: + $ref: SessionFileRef.yaml + description: Files observed or touched during the session + refs: + type: array + items: + $ref: SessionRef.yaml + description: Non-file references observed during the session + summary: + $ref: SessionSummary.yaml + description: Optional summary computed from the event stream +required: + - version + - events +description: Portable replay container for an outer harness session. diff --git a/vscode/prompty/schemas/SessionWarningPayload.yaml b/vscode/prompty/schemas/SessionWarningPayload.yaml new file mode 100644 index 00000000..faa3c038 --- /dev/null +++ b/vscode/prompty/schemas/SessionWarningPayload.yaml @@ -0,0 +1,17 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: SessionWarningPayload.yaml +type: object +properties: + warningType: + type: string + description: Stable machine-readable warning category + message: + type: string + description: Human-readable warning message + details: + $ref: RecordUnknown.yaml + description: Additional host-specific warning details +required: + - warningType + - message +description: Payload for "session_warning" events. diff --git a/vscode/prompty/schemas/ToolExecutionCompletePayload.yaml b/vscode/prompty/schemas/ToolExecutionCompletePayload.yaml new file mode 100644 index 00000000..7fa7e9da --- /dev/null +++ b/vscode/prompty/schemas/ToolExecutionCompletePayload.yaml @@ -0,0 +1,39 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: ToolExecutionCompletePayload.yaml +type: object +properties: + requestId: + type: string + description: Stable host execution request identifier + toolCallId: + type: string + description: Associated model tool call identifier, when available + toolName: + type: string + description: Name of the host tool that executed + success: + type: boolean + description: Whether the host execution completed successfully + result: + description: Host-normalized execution result + exitCode: + type: integer + minimum: -2147483648 + maximum: 2147483647 + description: Process or host exit code, when applicable + durationMs: + type: number + description: Tool execution duration in milliseconds + errorKind: + type: string + description: Machine-readable error category when success is false + telemetry: + $ref: RecordUnknown.yaml + description: Host-specific telemetry for the execution + redaction: + $ref: RedactionMetadata.yaml + description: Redaction state for sensitive result fields +required: + - toolName + - success +description: Payload for "tool_execution_complete" events — a concrete host tool execution finished. diff --git a/vscode/prompty/schemas/ToolExecutionStartPayload.yaml b/vscode/prompty/schemas/ToolExecutionStartPayload.yaml new file mode 100644 index 00000000..3d2a117b --- /dev/null +++ b/vscode/prompty/schemas/ToolExecutionStartPayload.yaml @@ -0,0 +1,29 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: ToolExecutionStartPayload.yaml +type: object +properties: + requestId: + type: string + description: Stable host execution request identifier + toolCallId: + type: string + description: Associated model tool call identifier, when available + toolName: + type: string + description: Name of the host tool being executed + arguments: + $ref: RecordUnknown.yaml + description: Tool arguments after host-side sanitization + workingDirectory: + type: string + description: Working directory or execution scope for the tool + redaction: + $ref: RedactionMetadata.yaml + description: Redaction state for sensitive argument fields +required: + - toolName +description: |- + Payload for "tool_execution_start" events — the host is about to execute a concrete tool request. + + This is distinct from "tool_call_start", which records the model requesting a tool. + Tool execution events capture the harness-side action after policy and permission checks. diff --git a/vscode/prompty/schemas/TraceWriter.yaml b/vscode/prompty/schemas/TraceWriter.yaml new file mode 100644 index 00000000..79156617 --- /dev/null +++ b/vscode/prompty/schemas/TraceWriter.yaml @@ -0,0 +1,5 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: TraceWriter.yaml +type: object +properties: {} +description: Persists typed events to a replayable trace. diff --git a/vscode/prompty/schemas/TrajectoryEvent.yaml b/vscode/prompty/schemas/TrajectoryEvent.yaml new file mode 100644 index 00000000..6fdcbbdc --- /dev/null +++ b/vscode/prompty/schemas/TrajectoryEvent.yaml @@ -0,0 +1,36 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: TrajectoryEvent.yaml +type: object +properties: + id: + type: string + description: Stable trajectory event identifier + sessionId: + type: string + description: Stable session identifier + turnId: + type: string + description: Associated turn identifier, when available + toolCallId: + type: string + description: Associated tool call identifier, when available + turnIndex: + type: integer + minimum: -2147483648 + maximum: 2147483647 + description: Zero-based turn index in the session + eventType: + type: string + description: Host-defined trajectory event category + data: + $ref: RecordUnknown.yaml + description: Sanitized event data + createdAt: + type: string + description: ISO 8601 UTC timestamp when the trajectory event was recorded + redaction: + $ref: RedactionMetadata.yaml + description: Redaction state for sensitive trajectory fields +required: + - eventType +description: A compact, replay-oriented record of one harness-side action or observation. diff --git a/vscode/prompty/schemas/TurnEvent.yaml b/vscode/prompty/schemas/TurnEvent.yaml index 336ca438..6551bac3 100644 --- a/vscode/prompty/schemas/TurnEvent.yaml +++ b/vscode/prompty/schemas/TurnEvent.yaml @@ -29,8 +29,16 @@ properties: const: tool_call_start - type: string const: tool_call_complete + - type: string + const: tool_execution_start + - type: string + const: tool_execution_complete - type: string const: tool_result + - type: string + const: hook_start + - type: string + const: hook_end - type: string const: status - type: string diff --git a/web/src/content/docs/reference/Checkpoint.md b/web/src/content/docs/reference/Checkpoint.md new file mode 100644 index 00000000..e0fbb7e3 --- /dev/null +++ b/web/src/content/docs/reference/Checkpoint.md @@ -0,0 +1,73 @@ +--- +title: "Checkpoint" +description: "Documentation for the Checkpoint type." +slug: "reference/checkpoint" +--- + +A persisted handoff point for a harness session. + +## Class Diagram + +```mermaid +--- +title: Checkpoint +config: + look: handDrawn + theme: colorful + class: + hideEmptyMembersBox: true +--- +classDiagram + class Checkpoint { + +string id + +string sessionId + +string turnId + +int32 checkpointNumber + +string title + +string overview + +dictionary state + +string summary + +dictionary metadata + +string createdAt + +RedactionMetadata redaction + } + class RedactionMetadata { + +boolean sanitized + +RedactedField[] fields + +string policy + } + Checkpoint *-- RedactionMetadata +``` + +## Yaml Example + +```yaml +id: chk_abc123 +sessionId: sess_abc123 +turnId: turn_001 +checkpointNumber: 3 +title: Added harness contracts +createdAt: 2026-06-09T20:00:00Z +``` + +## Properties + +| Name | Type | Description | +| ---- | ---- | ----------- | +| id | string | Stable checkpoint identifier | +| sessionId | string | Stable session identifier | +| turnId | string | Associated turn identifier, when the checkpoint was created inside a turn | +| checkpointNumber | int32 | Monotonic checkpoint number within the session | +| title | string | Short checkpoint title | +| overview | string | Short human-readable overview | +| state | dictionary | Portable checkpoint state needed to resume or hand off the session | +| summary | string | Optional host-authored summary or handoff note | +| metadata | dictionary | Host-defined checkpoint metadata | +| createdAt | string | ISO 8601 UTC timestamp when the checkpoint was created | +| redaction | [RedactionMetadata](../redactionmetadata/) | Redaction state for sensitive checkpoint fields | + +## Composed Types + +The following types are composed within `Checkpoint`: + +- [RedactionMetadata](../redactionmetadata/) diff --git a/web/src/content/docs/reference/CheckpointStore.md b/web/src/content/docs/reference/CheckpointStore.md new file mode 100644 index 00000000..a181e6a5 --- /dev/null +++ b/web/src/content/docs/reference/CheckpointStore.md @@ -0,0 +1,37 @@ +--- +title: "CheckpointStore" +description: "Documentation for the CheckpointStore type." +slug: "reference/checkpointstore" +--- + +Stores and retrieves resumable session checkpoints. + +## Class Diagram + +```mermaid +--- +title: CheckpointStore +config: + look: handDrawn + theme: colorful + class: + hideEmptyMembersBox: true +--- +classDiagram + class CheckpointStore { + <> + +save(checkpoint: Checkpoint) Checkpoint [async-capable] + +load(sessionId: string, checkpointId: string) Checkpoint? [async-capable] + +listCheckpoints(sessionId: string) Checkpoint[] [async-capable] + } +``` + +## Helper Methods + +The following helper methods are declared via `@method` and must be implemented by every runtime. The schema declares the logical protocol contract; each runtime maps async-capable methods to idiomatic sync/async shapes for that language. + +| Name | Signature | Runtime shape | Description | +| ---- | --------- | ------------- | ----------- | +| `save` | `save(checkpoint: Checkpoint) -> Checkpoint` | async-capable | Persist a session checkpoint and return the stored checkpoint | +| `load` | `load(sessionId: string, checkpointId: string) -> Checkpoint?` | async-capable | Load a checkpoint by session and checkpoint identifier | +| `listCheckpoints` | `listCheckpoints(sessionId: string) -> Checkpoint[]` | async-capable | List checkpoints for a session | diff --git a/web/src/content/docs/reference/EventSink.md b/web/src/content/docs/reference/EventSink.md new file mode 100644 index 00000000..21aa8994 --- /dev/null +++ b/web/src/content/docs/reference/EventSink.md @@ -0,0 +1,35 @@ +--- +title: "EventSink" +description: "Documentation for the EventSink type." +slug: "reference/eventsink" +--- + +Receives typed turn and session events from a harness. + +## Class Diagram + +```mermaid +--- +title: EventSink +config: + look: handDrawn + theme: colorful + class: + hideEmptyMembersBox: true +--- +classDiagram + class EventSink { + <> + +emitTurn(turnEvent: TurnEvent) boolean [sync] + +emitSession(sessionEvent: SessionEvent) boolean [sync] + } +``` + +## Helper Methods + +The following helper methods are declared via `@method` and must be implemented by every runtime. The schema declares the logical protocol contract; each runtime maps async-capable methods to idiomatic sync/async shapes for that language. + +| Name | Signature | Runtime shape | Description | +| ---- | --------- | ------------- | ----------- | +| `emitTurn` | `emitTurn(turnEvent: TurnEvent) -> boolean` | sync | Emit a typed turn event to a host sink | +| `emitSession` | `emitSession(sessionEvent: SessionEvent) -> boolean` | sync | Emit a typed session event to a host sink | diff --git a/web/src/content/docs/reference/HarnessContext.md b/web/src/content/docs/reference/HarnessContext.md new file mode 100644 index 00000000..707a1dea --- /dev/null +++ b/web/src/content/docs/reference/HarnessContext.md @@ -0,0 +1,43 @@ +--- +title: "HarnessContext" +description: "Documentation for the HarnessContext type." +slug: "reference/harnesscontext" +--- + +Execution context associated with a harness session. Host-specific +environments can store detailed profiles in metadata without making the core +contract depend on one source-control provider or workspace shape. + +## Class Diagram + +```mermaid +--- +title: HarnessContext +config: + look: handDrawn + theme: colorful + class: + hideEmptyMembersBox: true +--- +classDiagram + class HarnessContext { + +string cwd + +string gitRoot + +dictionary metadata + } +``` + +## Yaml Example + +```yaml +cwd: /workspace/project +gitRoot: /workspace/project +``` + +## Properties + +| Name | Type | Description | +| ---- | ---- | ----------- | +| cwd | string | Current working directory for the harness | +| gitRoot | string | Git repository root, when known | +| metadata | dictionary | Host-defined context metadata, such as source-control or sandbox details | diff --git a/web/src/content/docs/reference/HookEndPayload.md b/web/src/content/docs/reference/HookEndPayload.md new file mode 100644 index 00000000..6f9a3486 --- /dev/null +++ b/web/src/content/docs/reference/HookEndPayload.md @@ -0,0 +1,64 @@ +--- +title: "HookEndPayload" +description: "Documentation for the HookEndPayload type." +slug: "reference/hookendpayload" +--- + +Payload for "hook_end" events — a host lifecycle hook finished. + +## Class Diagram + +```mermaid +--- +title: HookEndPayload +config: + look: handDrawn + theme: colorful + class: + hideEmptyMembersBox: true +--- +classDiagram + class HookEndPayload { + +string hookInvocationId + +string hookType + +boolean success + +dictionary output + +float64 durationMs + +string error + +RedactionMetadata redaction + } + class RedactionMetadata { + +boolean sanitized + +RedactedField[] fields + +string policy + } + HookEndPayload *-- RedactionMetadata +``` + +## Yaml Example + +```yaml +hookInvocationId: hook_abc123 +hookType: preToolUse +success: true +durationMs: 12 +error: hook failed +``` + +## Properties + +| Name | Type | Description | +| ---- | ---- | ----------- | +| hookInvocationId | string | Stable hook invocation identifier | +| hookType | string | Host-defined hook type | +| success | boolean | Whether the hook completed successfully | +| output | dictionary | Hook output after host-side sanitization | +| durationMs | float64 | Hook execution duration in milliseconds | +| error | string | Human-readable error when success is false | +| redaction | [RedactionMetadata](../redactionmetadata/) | Redaction state for sensitive hook output fields | + +## Composed Types + +The following types are composed within `HookEndPayload`: + +- [RedactionMetadata](../redactionmetadata/) diff --git a/web/src/content/docs/reference/HookStartPayload.md b/web/src/content/docs/reference/HookStartPayload.md new file mode 100644 index 00000000..9d72d5e7 --- /dev/null +++ b/web/src/content/docs/reference/HookStartPayload.md @@ -0,0 +1,55 @@ +--- +title: "HookStartPayload" +description: "Documentation for the HookStartPayload type." +slug: "reference/hookstartpayload" +--- + +Payload for "hook_start" events — a host lifecycle hook is beginning. + +## Class Diagram + +```mermaid +--- +title: HookStartPayload +config: + look: handDrawn + theme: colorful + class: + hideEmptyMembersBox: true +--- +classDiagram + class HookStartPayload { + +string hookInvocationId + +string hookType + +dictionary input + +RedactionMetadata redaction + } + class RedactionMetadata { + +boolean sanitized + +RedactedField[] fields + +string policy + } + HookStartPayload *-- RedactionMetadata +``` + +## Yaml Example + +```yaml +hookInvocationId: hook_abc123 +hookType: preToolUse +``` + +## Properties + +| Name | Type | Description | +| ---- | ---- | ----------- | +| hookInvocationId | string | Stable hook invocation identifier | +| hookType | string | Host-defined hook type | +| input | dictionary | Hook input after host-side sanitization | +| redaction | [RedactionMetadata](../redactionmetadata/) | Redaction state for sensitive hook input fields | + +## Composed Types + +The following types are composed within `HookStartPayload`: + +- [RedactionMetadata](../redactionmetadata/) diff --git a/web/src/content/docs/reference/HostToolExecutor.md b/web/src/content/docs/reference/HostToolExecutor.md new file mode 100644 index 00000000..08661ed8 --- /dev/null +++ b/web/src/content/docs/reference/HostToolExecutor.md @@ -0,0 +1,33 @@ +--- +title: "HostToolExecutor" +description: "Documentation for the HostToolExecutor type." +slug: "reference/hosttoolexecutor" +--- + +Executes host tools after policy and permission checks. + +## Class Diagram + +```mermaid +--- +title: HostToolExecutor +config: + look: handDrawn + theme: colorful + class: + hideEmptyMembersBox: true +--- +classDiagram + class HostToolExecutor { + <> + +execute(request: HostToolRequest) HostToolResult [async-capable] + } +``` + +## Helper Methods + +The following helper methods are declared via `@method` and must be implemented by every runtime. The schema declares the logical protocol contract; each runtime maps async-capable methods to idiomatic sync/async shapes for that language. + +| Name | Signature | Runtime shape | Description | +| ---- | --------- | ------------- | ----------- | +| `execute` | `execute(request: HostToolRequest) -> HostToolResult` | async-capable | Execute a concrete host tool request and return its completion payload | diff --git a/web/src/content/docs/reference/HostToolRequest.md b/web/src/content/docs/reference/HostToolRequest.md new file mode 100644 index 00000000..f12784ec --- /dev/null +++ b/web/src/content/docs/reference/HostToolRequest.md @@ -0,0 +1,47 @@ +--- +title: "HostToolRequest" +description: "Documentation for the HostToolRequest type." +slug: "reference/hosttoolrequest" +--- + +Request passed to a host tool executor after policy and permission checks. + +## Class Diagram + +```mermaid +--- +title: HostToolRequest +config: + look: handDrawn + theme: colorful + class: + hideEmptyMembersBox: true +--- +classDiagram + class HostToolRequest { + +string requestId + +string toolCallId + +string toolName + +dictionary arguments + +string workingDirectory + } +``` + +## Yaml Example + +```yaml +requestId: exec_abc123 +toolCallId: call_abc123 +toolName: powershell +workingDirectory: /workspace/project +``` + +## Properties + +| Name | Type | Description | +| ---- | ---- | ----------- | +| requestId | string | Stable host execution request identifier | +| toolCallId | string | Associated model tool call identifier, when available | +| toolName | string | Name of the host tool being executed | +| arguments | dictionary | Tool arguments after host-side sanitization | +| workingDirectory | string | Working directory or execution scope for the tool | diff --git a/web/src/content/docs/reference/HostToolResult.md b/web/src/content/docs/reference/HostToolResult.md new file mode 100644 index 00000000..7cdf5e01 --- /dev/null +++ b/web/src/content/docs/reference/HostToolResult.md @@ -0,0 +1,58 @@ +--- +title: "HostToolResult" +description: "Documentation for the HostToolResult type." +slug: "reference/hosttoolresult" +--- + +Result returned by a host tool executor. + +## Class Diagram + +```mermaid +--- +title: HostToolResult +config: + look: handDrawn + theme: colorful + class: + hideEmptyMembersBox: true +--- +classDiagram + class HostToolResult { + +string requestId + +string toolCallId + +string toolName + +boolean success + +unknown result + +int32 exitCode + +float64 durationMs + +string errorKind + +dictionary telemetry + } +``` + +## Yaml Example + +```yaml +requestId: exec_abc123 +toolCallId: call_abc123 +toolName: powershell +success: true +exitCode: 0 +durationMs: 250 +errorKind: timeout +``` + +## Properties + +| Name | Type | Description | +| ---- | ---- | ----------- | +| requestId | string | Stable host execution request identifier | +| toolCallId | string | Associated model tool call identifier, when available | +| toolName | string | Name of the host tool that executed | +| success | boolean | Whether the host execution completed successfully | +| result | unknown | Host-normalized execution result | +| exitCode | int32 | Process or host exit code, when applicable | +| durationMs | float64 | Tool execution duration in milliseconds | +| errorKind | string | Machine-readable error category when success is false | +| telemetry | dictionary | Host-specific telemetry for the execution | diff --git a/web/src/content/docs/reference/PermissionCompletedPayload.md b/web/src/content/docs/reference/PermissionCompletedPayload.md index 16eaeffb..be33b442 100644 --- a/web/src/content/docs/reference/PermissionCompletedPayload.md +++ b/web/src/content/docs/reference/PermissionCompletedPayload.md @@ -19,15 +19,20 @@ config: --- classDiagram class PermissionCompletedPayload { + +string requestId + +string toolCallId +string permission +boolean approved +string reason + +dictionary result } ``` ## Yaml Example ```yaml +requestId: perm_abc123 +toolCallId: call_abc123 permission: tool.execute approved: true reason: user_approved @@ -37,6 +42,9 @@ reason: user_approved | Name | Type | Description | | ---- | ---- | ----------- | +| requestId | string | Stable permission request identifier | +| toolCallId | string | Associated tool call identifier, when the permission gated a tool call | | permission | string | Permission/action name that was decided | | approved | boolean | Whether the requested permission was approved | | reason | string | Decision reason, if available | +| result | dictionary | Host-specific decision result, such as a durable approval token or denial details | diff --git a/web/src/content/docs/reference/PermissionDecision.md b/web/src/content/docs/reference/PermissionDecision.md new file mode 100644 index 00000000..f5021629 --- /dev/null +++ b/web/src/content/docs/reference/PermissionDecision.md @@ -0,0 +1,50 @@ +--- +title: "PermissionDecision" +description: "Documentation for the PermissionDecision type." +slug: "reference/permissiondecision" +--- + +Decision returned by a permission resolver. + +## Class Diagram + +```mermaid +--- +title: PermissionDecision +config: + look: handDrawn + theme: colorful + class: + hideEmptyMembersBox: true +--- +classDiagram + class PermissionDecision { + +string requestId + +string toolCallId + +string permission + +boolean approved + +string reason + +dictionary result + } +``` + +## Yaml Example + +```yaml +requestId: perm_abc123 +toolCallId: call_abc123 +permission: tool.execute +approved: true +reason: user_approved +``` + +## Properties + +| Name | Type | Description | +| ---- | ---- | ----------- | +| requestId | string | Stable permission request identifier | +| toolCallId | string | Associated tool call identifier, when the permission gated a tool call | +| permission | string | Permission/action name that was decided | +| approved | boolean | Whether the requested permission was approved | +| reason | string | Decision reason, if available | +| result | dictionary | Host-specific decision result, such as a durable approval token or denial details | diff --git a/web/src/content/docs/reference/PermissionRequest.md b/web/src/content/docs/reference/PermissionRequest.md new file mode 100644 index 00000000..d983f051 --- /dev/null +++ b/web/src/content/docs/reference/PermissionRequest.md @@ -0,0 +1,53 @@ +--- +title: "PermissionRequest" +description: "Documentation for the PermissionRequest type." +slug: "reference/permissionrequest" +--- + +Request passed to a permission resolver. This is the live protocol shape; the +event payloads above can include trace-only metadata such as redaction state. + +## Class Diagram + +```mermaid +--- +title: PermissionRequest +config: + look: handDrawn + theme: colorful + class: + hideEmptyMembersBox: true +--- +classDiagram + class PermissionRequest { + +string requestId + +string toolCallId + +string permission + +string target + +dictionary details + +string promptRequest + +dictionary policy + } +``` + +## Yaml Example + +```yaml +requestId: perm_abc123 +toolCallId: call_abc123 +permission: tool.execute +target: shell +promptRequest: Allow shell to run tests? +``` + +## Properties + +| Name | Type | Description | +| ---- | ---- | ----------- | +| requestId | string | Stable permission request identifier | +| toolCallId | string | Associated tool call identifier, when the permission gates a tool call | +| permission | string | Permission/action name being requested | +| target | string | Resource or tool the permission applies to | +| details | dictionary | Additional host-specific permission details | +| promptRequest | string | Human-readable prompt or rationale that can be shown to an approval UI | +| policy | dictionary | Policy metadata used to evaluate or explain the permission request | diff --git a/web/src/content/docs/reference/PermissionRequestedPayload.md b/web/src/content/docs/reference/PermissionRequestedPayload.md index a5832895..9c1a5e7f 100644 --- a/web/src/content/docs/reference/PermissionRequestedPayload.md +++ b/web/src/content/docs/reference/PermissionRequestedPayload.md @@ -19,23 +19,48 @@ config: --- classDiagram class PermissionRequestedPayload { + +string requestId + +string toolCallId +string permission +string target +dictionary details + +string promptRequest + +dictionary policy + +RedactionMetadata redaction } + class RedactionMetadata { + +boolean sanitized + +RedactedField[] fields + +string policy + } + PermissionRequestedPayload *-- RedactionMetadata ``` ## Yaml Example ```yaml +requestId: perm_abc123 +toolCallId: call_abc123 permission: tool.execute target: shell +promptRequest: Allow shell to run tests? ``` ## Properties | Name | Type | Description | | ---- | ---- | ----------- | +| requestId | string | Stable permission request identifier | +| toolCallId | string | Associated tool call identifier, when the permission gates a tool call | | permission | string | Permission/action name being requested | | target | string | Resource or tool the permission applies to | | details | dictionary | Additional host-specific permission details | +| promptRequest | string | Human-readable prompt or rationale that can be shown to an approval UI | +| policy | dictionary | Policy metadata used to evaluate or explain the permission request | +| redaction | [RedactionMetadata](../redactionmetadata/) | Redaction state for sensitive request fields | + +## Composed Types + +The following types are composed within `PermissionRequestedPayload`: + +- [RedactionMetadata](../redactionmetadata/) diff --git a/web/src/content/docs/reference/PermissionResolver.md b/web/src/content/docs/reference/PermissionResolver.md new file mode 100644 index 00000000..c4cebf48 --- /dev/null +++ b/web/src/content/docs/reference/PermissionResolver.md @@ -0,0 +1,33 @@ +--- +title: "PermissionResolver" +description: "Documentation for the PermissionResolver type." +slug: "reference/permissionresolver" +--- + +Resolves host permission requests for potentially sensitive actions. + +## Class Diagram + +```mermaid +--- +title: PermissionResolver +config: + look: handDrawn + theme: colorful + class: + hideEmptyMembersBox: true +--- +classDiagram + class PermissionResolver { + <> + +request(request: PermissionRequest) PermissionDecision [async-capable] + } +``` + +## Helper Methods + +The following helper methods are declared via `@method` and must be implemented by every runtime. The schema declares the logical protocol contract; each runtime maps async-capable methods to idiomatic sync/async shapes for that language. + +| Name | Signature | Runtime shape | Description | +| ---- | --------- | ------------- | ----------- | +| `request` | `request(request: PermissionRequest) -> PermissionDecision` | async-capable | Resolve a host permission request | diff --git a/web/src/content/docs/reference/RedactedField.md b/web/src/content/docs/reference/RedactedField.md new file mode 100644 index 00000000..89e63470 --- /dev/null +++ b/web/src/content/docs/reference/RedactedField.md @@ -0,0 +1,42 @@ +--- +title: "RedactedField" +description: "Documentation for the RedactedField type." +slug: "reference/redactedfield" +--- + +Redaction handling for one JSON-shaped field path. + +## Class Diagram + +```mermaid +--- +title: RedactedField +config: + look: handDrawn + theme: colorful + class: + hideEmptyMembersBox: true +--- +classDiagram + class RedactedField { + +string path + +string mode + +string reason + } +``` + +## Yaml Example + +```yaml +path: $.arguments.apiKey +mode: redacted +reason: secret +``` + +## Properties + +| Name | Type | Description | +| ---- | ---- | ----------- | +| path | string | JSONPath-like field path, relative to the containing payload | +| mode | string | How the field was represented | +| reason | string | Human-readable reason or policy that caused this handling | diff --git a/web/src/content/docs/reference/RedactionMetadata.md b/web/src/content/docs/reference/RedactionMetadata.md new file mode 100644 index 00000000..18d0617a --- /dev/null +++ b/web/src/content/docs/reference/RedactionMetadata.md @@ -0,0 +1,53 @@ +--- +title: "RedactionMetadata" +description: "Documentation for the RedactionMetadata type." +slug: "reference/redactionmetadata" +--- + +Metadata describing whether and how a payload was sanitized. + +## Class Diagram + +```mermaid +--- +title: RedactionMetadata +config: + look: handDrawn + theme: colorful + class: + hideEmptyMembersBox: true +--- +classDiagram + class RedactionMetadata { + +boolean sanitized + +RedactedField[] fields + +string policy + } + class RedactedField { + +string path + +string mode + +string reason + } + RedactionMetadata *-- RedactedField +``` + +## Yaml Example + +```yaml +sanitized: true +policy: default-v1 +``` + +## Properties + +| Name | Type | Description | +| ---- | ---- | ----------- | +| sanitized | boolean | Whether the payload has been sanitized for persistence or external display | +| fields | [RedactedField[]](../redactedfield/) | Field-level redaction details | +| policy | string | Host policy or sanitizer version that produced this metadata | + +## Composed Types + +The following types are composed within `RedactionMetadata`: + +- [RedactedField](../redactedfield/) diff --git a/web/src/content/docs/reference/SessionEndPayload.md b/web/src/content/docs/reference/SessionEndPayload.md new file mode 100644 index 00000000..a8d47344 --- /dev/null +++ b/web/src/content/docs/reference/SessionEndPayload.md @@ -0,0 +1,45 @@ +--- +title: "SessionEndPayload" +description: "Documentation for the SessionEndPayload type." +slug: "reference/sessionendpayload" +--- + +Payload for "session_end" events. + +## Class Diagram + +```mermaid +--- +title: SessionEndPayload +config: + look: handDrawn + theme: colorful + class: + hideEmptyMembersBox: true +--- +classDiagram + class SessionEndPayload { + +string sessionId + +string status + +string reason + +float64 durationMs + } +``` + +## Yaml Example + +```yaml +sessionId: sess_abc123 +status: success +reason: complete +durationMs: 12500 +``` + +## Properties + +| Name | Type | Description | +| ---- | ---- | ----------- | +| sessionId | string | Stable session identifier | +| status | string | Final session status | +| reason | string | Host-specific reason the session ended | +| durationMs | float64 | Total elapsed session duration in milliseconds | diff --git a/web/src/content/docs/reference/SessionEvent.md b/web/src/content/docs/reference/SessionEvent.md new file mode 100644 index 00000000..3c7819a0 --- /dev/null +++ b/web/src/content/docs/reference/SessionEvent.md @@ -0,0 +1,69 @@ +--- +title: "SessionEvent" +description: "Documentation for the SessionEvent type." +slug: "reference/sessionevent" +--- + +A canonical event envelope emitted by an outer harness session. + +## Class Diagram + +```mermaid +--- +title: SessionEvent +config: + look: handDrawn + theme: colorful + class: + hideEmptyMembersBox: true +--- +classDiagram + class SessionEvent { + +string id + +string type + +string timestamp + +string sessionId + +string turnId + +string parentId + +string spanId + +dictionary payload + +RedactionMetadata redaction + } + class RedactionMetadata { + +boolean sanitized + +RedactedField[] fields + +string policy + } + SessionEvent *-- RedactionMetadata +``` + +## Yaml Example + +```yaml +id: evt_abc123 +timestamp: 2026-06-09T20:00:00Z +sessionId: sess_abc123 +turnId: turn_001 +parentId: evt_parent +spanId: span_hook_001 +``` + +## Properties + +| Name | Type | Description | +| ---- | ---- | ----------- | +| id | string | Unique identifier for this event | +| type | string | Event type discriminator | +| timestamp | string | ISO 8601 UTC timestamp when the event was emitted | +| sessionId | string | Stable identifier for the outer session | +| turnId | string | Associated turn identifier, when this session event is linked to a turn | +| parentId | string | Parent event or span identifier for reconstructing event hierarchy | +| spanId | string | Trace span identifier associated with this event | +| payload | dictionary | Event-specific payload. Use the typed payload model matching 'type'. | +| redaction | [RedactionMetadata](../redactionmetadata/) | Redaction state for sensitive payload fields | + +## Composed Types + +The following types are composed within `SessionEvent`: + +- [RedactionMetadata](../redactionmetadata/) diff --git a/web/src/content/docs/reference/SessionFileRef.md b/web/src/content/docs/reference/SessionFileRef.md new file mode 100644 index 00000000..cf7d7e3c --- /dev/null +++ b/web/src/content/docs/reference/SessionFileRef.md @@ -0,0 +1,48 @@ +--- +title: "SessionFileRef" +description: "Documentation for the SessionFileRef type." +slug: "reference/sessionfileref" +--- + +A file observed or touched by a harness session. + +## Class Diagram + +```mermaid +--- +title: SessionFileRef +config: + look: handDrawn + theme: colorful + class: + hideEmptyMembersBox: true +--- +classDiagram + class SessionFileRef { + +string sessionId + +string path + +string toolName + +int32 turnIndex + +string firstSeenAt + } +``` + +## Yaml Example + +```yaml +sessionId: sess_abc123 +path: src/index.ts +toolName: view +turnIndex: 2 +firstSeenAt: 2026-06-09T20:00:00Z +``` + +## Properties + +| Name | Type | Description | +| ---- | ---- | ----------- | +| sessionId | string | Stable session identifier | +| path | string | File path, relative to the harness workspace when possible | +| toolName | string | Tool that first observed the file, when known | +| turnIndex | int32 | Zero-based turn index where the file was first observed | +| firstSeenAt | string | ISO 8601 UTC timestamp when the file was first observed | diff --git a/web/src/content/docs/reference/SessionRef.md b/web/src/content/docs/reference/SessionRef.md new file mode 100644 index 00000000..9fc79d1d --- /dev/null +++ b/web/src/content/docs/reference/SessionRef.md @@ -0,0 +1,48 @@ +--- +title: "SessionRef" +description: "Documentation for the SessionRef type." +slug: "reference/sessionref" +--- + +A non-file reference observed by a harness session. + +## Class Diagram + +```mermaid +--- +title: SessionRef +config: + look: handDrawn + theme: colorful + class: + hideEmptyMembersBox: true +--- +classDiagram + class SessionRef { + +string sessionId + +string refType + +string refValue + +int32 turnIndex + +string createdAt + } +``` + +## Yaml Example + +```yaml +sessionId: sess_abc123 +refType: issue +refValue: owner/repo#123 +turnIndex: 2 +createdAt: 2026-06-09T20:00:00Z +``` + +## Properties + +| Name | Type | Description | +| ---- | ---- | ----------- | +| sessionId | string | Stable session identifier | +| refType | string | Reference category | +| refValue | string | Reference value | +| turnIndex | int32 | Zero-based turn index where the reference was first observed | +| createdAt | string | ISO 8601 UTC timestamp when the reference was recorded | diff --git a/web/src/content/docs/reference/SessionStartPayload.md b/web/src/content/docs/reference/SessionStartPayload.md new file mode 100644 index 00000000..cda9b85b --- /dev/null +++ b/web/src/content/docs/reference/SessionStartPayload.md @@ -0,0 +1,71 @@ +--- +title: "SessionStartPayload" +description: "Documentation for the SessionStartPayload type." +slug: "reference/sessionstartpayload" +--- + +Payload for "session_start" events. + +## Class Diagram + +```mermaid +--- +title: SessionStartPayload +config: + look: handDrawn + theme: colorful + class: + hideEmptyMembersBox: true +--- +classDiagram + class SessionStartPayload { + +string sessionId + +int32 version + +string producer + +string runtime + +string promptyVersion + +string startTime + +string selectedModel + +string reasoningEffort + +HarnessContext context + } + class HarnessContext { + +string cwd + +string gitRoot + +dictionary metadata + } + SessionStartPayload *-- HarnessContext +``` + +## Yaml Example + +```yaml +sessionId: sess_abc123 +version: 1 +producer: prompty-agent +runtime: typescript +promptyVersion: 2.0.0 +startTime: 2026-06-09T20:00:00Z +selectedModel: gpt-4o-mini +reasoningEffort: medium +``` + +## Properties + +| Name | Type | Description | +| ---- | ---- | ----------- | +| sessionId | string | Stable session identifier | +| version | int32 | Session event schema version | +| producer | string | Producer that started the session | +| runtime | string | Runtime that produced the session | +| promptyVersion | string | Prompty library version | +| startTime | string | ISO 8601 UTC timestamp when the session started | +| selectedModel | string | Selected model identifier, when known | +| reasoningEffort | string | Selected reasoning effort or equivalent model setting, when known | +| context | [HarnessContext](../harnesscontext/) | Repository and execution context | + +## Composed Types + +The following types are composed within `SessionStartPayload`: + +- [HarnessContext](../harnesscontext/) diff --git a/web/src/content/docs/reference/SessionSummary.md b/web/src/content/docs/reference/SessionSummary.md new file mode 100644 index 00000000..4b75b5a5 --- /dev/null +++ b/web/src/content/docs/reference/SessionSummary.md @@ -0,0 +1,62 @@ +--- +title: "SessionSummary" +description: "Documentation for the SessionSummary type." +slug: "reference/sessionsummary" +--- + +Summary statistics for a completed session trace. + +## Class Diagram + +```mermaid +--- +title: SessionSummary +config: + look: handDrawn + theme: colorful + class: + hideEmptyMembersBox: true +--- +classDiagram + class SessionSummary { + +string sessionId + +string status + +int32 turns + +int32 checkpoints + +TokenUsage usage + +float64 durationMs + } + class TokenUsage { + +int32 promptTokens + +int32 completionTokens + +int32 totalTokens + } + SessionSummary *-- TokenUsage +``` + +## Yaml Example + +```yaml +sessionId: sess_abc123 +status: success +turns: 5 +checkpoints: 2 +durationMs: 12500 +``` + +## Properties + +| Name | Type | Description | +| ---- | ---- | ----------- | +| sessionId | string | Stable session identifier | +| status | string | Final session status | +| turns | int32 | Number of user/assistant turns in the session | +| checkpoints | int32 | Number of checkpoints created | +| usage | [TokenUsage](../tokenusage/) | Aggregated token usage for the session | +| durationMs | float64 | Total elapsed session duration in milliseconds | + +## Composed Types + +The following types are composed within `SessionSummary`: + +- [TokenUsage](../tokenusage/) diff --git a/web/src/content/docs/reference/SessionTrace.md b/web/src/content/docs/reference/SessionTrace.md new file mode 100644 index 00000000..138582b0 --- /dev/null +++ b/web/src/content/docs/reference/SessionTrace.md @@ -0,0 +1,142 @@ +--- +title: "SessionTrace" +description: "Documentation for the SessionTrace type." +slug: "reference/sessiontrace" +--- + +Portable replay container for an outer harness session. + +## Class Diagram + +```mermaid +--- +title: SessionTrace +config: + look: handDrawn + theme: colorful + class: + hideEmptyMembersBox: true +--- +classDiagram + class SessionTrace { + +string version + +string runtime + +string promptyVersion + +string sessionId + +SessionEvent[] events + +TurnTrace[] turns + +Checkpoint[] checkpoints + +TrajectoryEvent[] trajectory + +SessionFileRef[] files + +SessionRef[] refs + +SessionSummary summary + } + class SessionEvent { + +string id + +string type + +string timestamp + +string sessionId + +string turnId + +string parentId + +string spanId + +dictionary payload + +RedactionMetadata redaction + } + SessionTrace *-- SessionEvent + class TurnTrace { + +string version + +string runtime + +string promptyVersion + +TurnEvent[] events + +TurnSummary summary + } + SessionTrace *-- TurnTrace + class Checkpoint { + +string id + +string sessionId + +string turnId + +int32 checkpointNumber + +string title + +string overview + +dictionary state + +string summary + +dictionary metadata + +string createdAt + +RedactionMetadata redaction + } + SessionTrace *-- Checkpoint + class TrajectoryEvent { + +string id + +string sessionId + +string turnId + +string toolCallId + +int32 turnIndex + +string eventType + +dictionary data + +string createdAt + +RedactionMetadata redaction + } + SessionTrace *-- TrajectoryEvent + class SessionFileRef { + +string sessionId + +string path + +string toolName + +int32 turnIndex + +string firstSeenAt + } + SessionTrace *-- SessionFileRef + class SessionRef { + +string sessionId + +string refType + +string refValue + +int32 turnIndex + +string createdAt + } + SessionTrace *-- SessionRef + class SessionSummary { + +string sessionId + +string status + +int32 turns + +int32 checkpoints + +TokenUsage usage + +float64 durationMs + } + SessionTrace *-- SessionSummary +``` + +## Yaml Example + +```yaml +version: "1" +runtime: typescript +promptyVersion: 2.0.0 +sessionId: sess_abc123 +``` + +## Properties + +| Name | Type | Description | +| ---- | ---- | ----------- | +| version | string | Trace schema version | +| runtime | string | Runtime name that produced the trace | +| promptyVersion | string | Prompty library version that produced the trace | +| sessionId | string | Stable session identifier | +| events | [SessionEvent[]](../sessionevent/) | Recorded session events in emission order | +| turns | [TurnTrace[]](../turntrace/) | Recorded turn traces associated with the session | +| checkpoints | [Checkpoint[]](../checkpoint/) | Checkpoints created during the session | +| trajectory | [TrajectoryEvent[]](../trajectoryevent/) | Compact trajectory records associated with the session | +| files | [SessionFileRef[]](../sessionfileref/) | Files observed or touched during the session | +| refs | [SessionRef[]](../sessionref/) | Non-file references observed during the session | +| summary | [SessionSummary](../sessionsummary/) | Optional summary computed from the event stream | + +## Composed Types + +The following types are composed within `SessionTrace`: + +- [SessionEvent](../sessionevent/) +- [TurnTrace](../turntrace/) +- [Checkpoint](../checkpoint/) +- [TrajectoryEvent](../trajectoryevent/) +- [SessionFileRef](../sessionfileref/) +- [SessionRef](../sessionref/) +- [SessionSummary](../sessionsummary/) diff --git a/web/src/content/docs/reference/SessionWarningPayload.md b/web/src/content/docs/reference/SessionWarningPayload.md new file mode 100644 index 00000000..e2b16fd5 --- /dev/null +++ b/web/src/content/docs/reference/SessionWarningPayload.md @@ -0,0 +1,41 @@ +--- +title: "SessionWarningPayload" +description: "Documentation for the SessionWarningPayload type." +slug: "reference/sessionwarningpayload" +--- + +Payload for "session_warning" events. + +## Class Diagram + +```mermaid +--- +title: SessionWarningPayload +config: + look: handDrawn + theme: colorful + class: + hideEmptyMembersBox: true +--- +classDiagram + class SessionWarningPayload { + +string warningType + +string message + +dictionary details + } +``` + +## Yaml Example + +```yaml +warningType: remote +message: Remote session disabled +``` + +## Properties + +| Name | Type | Description | +| ---- | ---- | ----------- | +| warningType | string | Stable machine-readable warning category | +| message | string | Human-readable warning message | +| details | dictionary | Additional host-specific warning details | diff --git a/web/src/content/docs/reference/ToolExecutionCompletePayload.md b/web/src/content/docs/reference/ToolExecutionCompletePayload.md new file mode 100644 index 00000000..dba8d7bf --- /dev/null +++ b/web/src/content/docs/reference/ToolExecutionCompletePayload.md @@ -0,0 +1,72 @@ +--- +title: "ToolExecutionCompletePayload" +description: "Documentation for the ToolExecutionCompletePayload type." +slug: "reference/toolexecutioncompletepayload" +--- + +Payload for "tool_execution_complete" events — a concrete host tool execution finished. + +## Class Diagram + +```mermaid +--- +title: ToolExecutionCompletePayload +config: + look: handDrawn + theme: colorful + class: + hideEmptyMembersBox: true +--- +classDiagram + class ToolExecutionCompletePayload { + +string requestId + +string toolCallId + +string toolName + +boolean success + +unknown result + +int32 exitCode + +float64 durationMs + +string errorKind + +dictionary telemetry + +RedactionMetadata redaction + } + class RedactionMetadata { + +boolean sanitized + +RedactedField[] fields + +string policy + } + ToolExecutionCompletePayload *-- RedactionMetadata +``` + +## Yaml Example + +```yaml +requestId: exec_abc123 +toolCallId: call_abc123 +toolName: powershell +success: true +exitCode: 0 +durationMs: 250 +errorKind: timeout +``` + +## Properties + +| Name | Type | Description | +| ---- | ---- | ----------- | +| requestId | string | Stable host execution request identifier | +| toolCallId | string | Associated model tool call identifier, when available | +| toolName | string | Name of the host tool that executed | +| success | boolean | Whether the host execution completed successfully | +| result | unknown | Host-normalized execution result | +| exitCode | int32 | Process or host exit code, when applicable | +| durationMs | float64 | Tool execution duration in milliseconds | +| errorKind | string | Machine-readable error category when success is false | +| telemetry | dictionary | Host-specific telemetry for the execution | +| redaction | [RedactionMetadata](../redactionmetadata/) | Redaction state for sensitive result fields | + +## Composed Types + +The following types are composed within `ToolExecutionCompletePayload`: + +- [RedactionMetadata](../redactionmetadata/) diff --git a/web/src/content/docs/reference/ToolExecutionStartPayload.md b/web/src/content/docs/reference/ToolExecutionStartPayload.md new file mode 100644 index 00000000..12e6145a --- /dev/null +++ b/web/src/content/docs/reference/ToolExecutionStartPayload.md @@ -0,0 +1,64 @@ +--- +title: "ToolExecutionStartPayload" +description: "Documentation for the ToolExecutionStartPayload type." +slug: "reference/toolexecutionstartpayload" +--- + +Payload for "tool_execution_start" events — the host is about to execute a concrete tool request. + +This is distinct from "tool_call_start", which records the model requesting a tool. +Tool execution events capture the harness-side action after policy and permission checks. + +## Class Diagram + +```mermaid +--- +title: ToolExecutionStartPayload +config: + look: handDrawn + theme: colorful + class: + hideEmptyMembersBox: true +--- +classDiagram + class ToolExecutionStartPayload { + +string requestId + +string toolCallId + +string toolName + +dictionary arguments + +string workingDirectory + +RedactionMetadata redaction + } + class RedactionMetadata { + +boolean sanitized + +RedactedField[] fields + +string policy + } + ToolExecutionStartPayload *-- RedactionMetadata +``` + +## Yaml Example + +```yaml +requestId: exec_abc123 +toolCallId: call_abc123 +toolName: powershell +workingDirectory: /workspace/project +``` + +## Properties + +| Name | Type | Description | +| ---- | ---- | ----------- | +| requestId | string | Stable host execution request identifier | +| toolCallId | string | Associated model tool call identifier, when available | +| toolName | string | Name of the host tool being executed | +| arguments | dictionary | Tool arguments after host-side sanitization | +| workingDirectory | string | Working directory or execution scope for the tool | +| redaction | [RedactionMetadata](../redactionmetadata/) | Redaction state for sensitive argument fields | + +## Composed Types + +The following types are composed within `ToolExecutionStartPayload`: + +- [RedactionMetadata](../redactionmetadata/) diff --git a/web/src/content/docs/reference/TraceWriter.md b/web/src/content/docs/reference/TraceWriter.md new file mode 100644 index 00000000..0af54705 --- /dev/null +++ b/web/src/content/docs/reference/TraceWriter.md @@ -0,0 +1,37 @@ +--- +title: "TraceWriter" +description: "Documentation for the TraceWriter type." +slug: "reference/tracewriter" +--- + +Persists typed events to a replayable trace. + +## Class Diagram + +```mermaid +--- +title: TraceWriter +config: + look: handDrawn + theme: colorful + class: + hideEmptyMembersBox: true +--- +classDiagram + class TraceWriter { + <> + +appendTurn(turnEvent: TurnEvent) boolean [sync] + +appendSession(sessionEvent: SessionEvent) boolean [sync] + +close(summary: SessionSummary?) boolean [sync] + } +``` + +## Helper Methods + +The following helper methods are declared via `@method` and must be implemented by every runtime. The schema declares the logical protocol contract; each runtime maps async-capable methods to idiomatic sync/async shapes for that language. + +| Name | Signature | Runtime shape | Description | +| ---- | --------- | ------------- | ----------- | +| `appendTurn` | `appendTurn(turnEvent: TurnEvent) -> boolean` | sync | Append a turn event to a replayable trace | +| `appendSession` | `appendSession(sessionEvent: SessionEvent) -> boolean` | sync | Append a session event to a replayable trace | +| `close` | `close(summary: SessionSummary?) -> boolean` | sync | Finalize the trace with an optional session summary | diff --git a/web/src/content/docs/reference/TrajectoryEvent.md b/web/src/content/docs/reference/TrajectoryEvent.md new file mode 100644 index 00000000..0a1eeae1 --- /dev/null +++ b/web/src/content/docs/reference/TrajectoryEvent.md @@ -0,0 +1,70 @@ +--- +title: "TrajectoryEvent" +description: "Documentation for the TrajectoryEvent type." +slug: "reference/trajectoryevent" +--- + +A compact, replay-oriented record of one harness-side action or observation. + +## Class Diagram + +```mermaid +--- +title: TrajectoryEvent +config: + look: handDrawn + theme: colorful + class: + hideEmptyMembersBox: true +--- +classDiagram + class TrajectoryEvent { + +string id + +string sessionId + +string turnId + +string toolCallId + +int32 turnIndex + +string eventType + +dictionary data + +string createdAt + +RedactionMetadata redaction + } + class RedactionMetadata { + +boolean sanitized + +RedactedField[] fields + +string policy + } + TrajectoryEvent *-- RedactionMetadata +``` + +## Yaml Example + +```yaml +id: traj_abc123 +sessionId: sess_abc123 +turnId: turn_001 +toolCallId: call_abc123 +turnIndex: 4 +eventType: command +createdAt: 2026-06-09T20:00:00Z +``` + +## Properties + +| Name | Type | Description | +| ---- | ---- | ----------- | +| id | string | Stable trajectory event identifier | +| sessionId | string | Stable session identifier | +| turnId | string | Associated turn identifier, when available | +| toolCallId | string | Associated tool call identifier, when available | +| turnIndex | int32 | Zero-based turn index in the session | +| eventType | string | Host-defined trajectory event category | +| data | dictionary | Sanitized event data | +| createdAt | string | ISO 8601 UTC timestamp when the trajectory event was recorded | +| redaction | [RedactionMetadata](../redactionmetadata/) | Redaction state for sensitive trajectory fields | + +## Composed Types + +The following types are composed within `TrajectoryEvent`: + +- [RedactionMetadata](../redactionmetadata/) From 9060ceb8933ee08d9b17e9e6ce13ca1a6f59a206 Mon Sep 17 00:00:00 2001 From: Seth Juarez Date: Wed, 10 Jun 2026 10:35:12 -0700 Subject: [PATCH 03/22] Tighten harness contract shapes Clarify hook scope, distinguish permission event payloads from live decisions, and align session start schema versioning across generated runtimes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../SessionStartPayloadConversionTests.cs | 20 ++++----- .../Model/events/HookEndPayload.cs | 16 +++++++ .../Prompty.Core/Model/events/HookEndScope.cs | 17 +++++++ .../Model/events/HookStartPayload.cs | 16 +++++++ .../Model/events/HookStartScope.cs | 17 +++++++ .../events/PermissionCompletedPayload.cs | 16 +++++++ .../Model/events/SessionStartPayload.cs | 10 ++--- runtime/go/prompty/model/hook_end_payload.go | 16 +++++++ .../go/prompty/model/hook_start_payload.go | 16 +++++++ .../model/permission_completed_payload.go | 10 +++++ .../go/prompty/model/session_start_payload.go | 22 +++------- .../model/session_start_payload_test.go | 22 +++++----- .../prompty/model/events/_HookEndPayload.py | 11 ++++- .../prompty/model/events/_HookStartPayload.py | 11 ++++- .../events/_PermissionCompletedPayload.py | 8 ++++ .../model/events/_SessionStartPayload.py | 12 ++--- .../events/test_session_start_payload.py | 16 +++---- .../src/model/events/hook_end_payload.rs | 44 +++++++++++++++++++ .../src/model/events/hook_start_payload.rs | 44 +++++++++++++++++++ .../events/permission_completed_payload.rs | 11 +++++ .../src/model/events/session_start_payload.rs | 8 ++-- .../model/events/hook_end_payload_test.rs | 1 + .../model/events/hook_start_payload_test.rs | 1 + .../events/session_start_payload_test.rs | 12 ++--- .../core/src/model/events/hook-end-payload.ts | 12 +++++ .../src/model/events/hook-start-payload.ts | 12 +++++ .../events/permission-completed-payload.ts | 14 ++++++ .../src/model/events/session-start-payload.ts | 14 +++--- .../events/session-start-payload.test.ts | 16 +++---- schema/model/events/payloads.tsp | 22 ++++++++++ schema/model/events/session.tsp | 4 +- vscode/prompty/schemas/HookEndPayload.yaml | 7 +++ vscode/prompty/schemas/HookStartPayload.yaml | 7 +++ .../schemas/PermissionCompletedPayload.yaml | 3 ++ .../prompty/schemas/SessionStartPayload.yaml | 8 ++-- .../content/docs/reference/HookEndPayload.md | 2 + .../docs/reference/HookStartPayload.md | 2 + .../reference/PermissionCompletedPayload.md | 14 ++++++ .../docs/reference/SessionStartPayload.md | 6 +-- 39 files changed, 427 insertions(+), 93 deletions(-) create mode 100644 runtime/csharp/Prompty.Core/Model/events/HookEndScope.cs create mode 100644 runtime/csharp/Prompty.Core/Model/events/HookStartScope.cs diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/SessionStartPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/SessionStartPayloadConversionTests.cs index 0b86fb08..160fc3b3 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/SessionStartPayloadConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/SessionStartPayloadConversionTests.cs @@ -12,7 +12,7 @@ public void LoadYamlInput() { string yamlData = """ sessionId: sess_abc123 -version: 1 +schemaVersion: "1" producer: prompty-agent runtime: typescript promptyVersion: 2.0.0 @@ -26,7 +26,7 @@ public void LoadYamlInput() Assert.NotNull(instance); Assert.Equal("sess_abc123", instance.SessionId); - Assert.Equal(1, instance.Version); + Assert.Equal("1", instance.SchemaVersion); Assert.Equal("prompty-agent", instance.Producer); Assert.Equal("typescript", instance.Runtime); Assert.Equal("2.0.0", instance.PromptyVersion); @@ -41,7 +41,7 @@ public void LoadJsonInput() string jsonData = """ { "sessionId": "sess_abc123", - "version": 1, + "schemaVersion": "1", "producer": "prompty-agent", "runtime": "typescript", "promptyVersion": "2.0.0", @@ -54,7 +54,7 @@ public void LoadJsonInput() var instance = SessionStartPayload.FromJson(jsonData); Assert.NotNull(instance); Assert.Equal("sess_abc123", instance.SessionId); - Assert.Equal(1, instance.Version); + Assert.Equal("1", instance.SchemaVersion); Assert.Equal("prompty-agent", instance.Producer); Assert.Equal("typescript", instance.Runtime); Assert.Equal("2.0.0", instance.PromptyVersion); @@ -70,7 +70,7 @@ public void RoundtripJson() string jsonData = """ { "sessionId": "sess_abc123", - "version": 1, + "schemaVersion": "1", "producer": "prompty-agent", "runtime": "typescript", "promptyVersion": "2.0.0", @@ -89,7 +89,7 @@ public void RoundtripJson() var reloaded = SessionStartPayload.FromJson(json); Assert.NotNull(reloaded); Assert.Equal("sess_abc123", reloaded.SessionId); - Assert.Equal(1, reloaded.Version); + Assert.Equal("1", reloaded.SchemaVersion); Assert.Equal("prompty-agent", reloaded.Producer); Assert.Equal("typescript", reloaded.Runtime); Assert.Equal("2.0.0", reloaded.PromptyVersion); @@ -104,7 +104,7 @@ public void RoundtripYaml() // Test that FromYaml -> ToYaml -> FromYaml produces equivalent data string yamlData = """ sessionId: sess_abc123 -version: 1 +schemaVersion: "1" producer: prompty-agent runtime: typescript promptyVersion: 2.0.0 @@ -123,7 +123,7 @@ public void RoundtripYaml() var reloaded = SessionStartPayload.FromYaml(yaml); Assert.NotNull(reloaded); Assert.Equal("sess_abc123", reloaded.SessionId); - Assert.Equal(1, reloaded.Version); + Assert.Equal("1", reloaded.SchemaVersion); Assert.Equal("prompty-agent", reloaded.Producer); Assert.Equal("typescript", reloaded.Runtime); Assert.Equal("2.0.0", reloaded.PromptyVersion); @@ -138,7 +138,7 @@ public void ToJsonProducesValidJson() string jsonData = """ { "sessionId": "sess_abc123", - "version": 1, + "schemaVersion": "1", "producer": "prompty-agent", "runtime": "typescript", "promptyVersion": "2.0.0", @@ -161,7 +161,7 @@ public void ToYamlProducesValidYaml() { string yamlData = """ sessionId: sess_abc123 -version: 1 +schemaVersion: "1" producer: prompty-agent runtime: typescript promptyVersion: 2.0.0 diff --git a/runtime/csharp/Prompty.Core/Model/events/HookEndPayload.cs b/runtime/csharp/Prompty.Core/Model/events/HookEndPayload.cs index 6ae0f142..42f6c80a 100644 --- a/runtime/csharp/Prompty.Core/Model/events/HookEndPayload.cs +++ b/runtime/csharp/Prompty.Core/Model/events/HookEndPayload.cs @@ -35,6 +35,11 @@ public HookEndPayload() /// public string HookType { get; set; } = string.Empty; + /// + /// Whether the hook is scoped to a turn or the outer session + /// + public HookEndScope? Scope { get; set; } + /// /// Whether the hook completed successfully /// @@ -92,6 +97,11 @@ public static HookEndPayload Load(Dictionary data, LoadContext? instance.HookType = hookTypeValue?.ToString()!; } + if (data.TryGetValue("scope", out var scopeValue) && scopeValue is not null) + { + instance.Scope = Enum.Parse(scopeValue?.ToString()!, true); + } + if (data.TryGetValue("success", out var successValue) && successValue is not null) { instance.Success = Convert.ToBoolean(successValue); @@ -152,6 +162,12 @@ public static HookEndPayload Load(Dictionary data, LoadContext? result["hookType"] = obj.HookType; + if (obj.Scope is not null) + { + result["scope"] = obj.Scope.Value.ToString().ToLowerInvariant(); + } + + result["success"] = obj.Success; diff --git a/runtime/csharp/Prompty.Core/Model/events/HookEndScope.cs b/runtime/csharp/Prompty.Core/Model/events/HookEndScope.cs new file mode 100644 index 00000000..0133e67b --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/HookEndScope.cs @@ -0,0 +1,17 @@ +// +// Code generated by Prompty emitter; DO NOT EDIT. + +using System.Text.Json.Serialization; + +namespace Prompty.Core; + +[JsonConverter(typeof(JsonStringEnumConverter))] +public enum HookEndScope +{ + [JsonPropertyName("turn")] + Turn, + + [JsonPropertyName("session")] + Session, + +} diff --git a/runtime/csharp/Prompty.Core/Model/events/HookStartPayload.cs b/runtime/csharp/Prompty.Core/Model/events/HookStartPayload.cs index 8fd18972..f6637e9a 100644 --- a/runtime/csharp/Prompty.Core/Model/events/HookStartPayload.cs +++ b/runtime/csharp/Prompty.Core/Model/events/HookStartPayload.cs @@ -35,6 +35,11 @@ public HookStartPayload() /// public string HookType { get; set; } = string.Empty; + /// + /// Whether the hook is scoped to a turn or the outer session + /// + public HookStartScope? Scope { get; set; } + /// /// Hook input after host-side sanitization /// @@ -77,6 +82,11 @@ public static HookStartPayload Load(Dictionary data, LoadContex instance.HookType = hookTypeValue?.ToString()!; } + if (data.TryGetValue("scope", out var scopeValue) && scopeValue is not null) + { + instance.Scope = Enum.Parse(scopeValue?.ToString()!, true); + } + if (data.TryGetValue("input", out var inputValue) && inputValue is not null) { instance.Input = inputValue.GetDictionary()!; @@ -122,6 +132,12 @@ public static HookStartPayload Load(Dictionary data, LoadContex result["hookType"] = obj.HookType; + if (obj.Scope is not null) + { + result["scope"] = obj.Scope.Value.ToString().ToLowerInvariant(); + } + + if (obj.Input is not null) { result["input"] = obj.Input; diff --git a/runtime/csharp/Prompty.Core/Model/events/HookStartScope.cs b/runtime/csharp/Prompty.Core/Model/events/HookStartScope.cs new file mode 100644 index 00000000..3b987870 --- /dev/null +++ b/runtime/csharp/Prompty.Core/Model/events/HookStartScope.cs @@ -0,0 +1,17 @@ +// +// Code generated by Prompty emitter; DO NOT EDIT. + +using System.Text.Json.Serialization; + +namespace Prompty.Core; + +[JsonConverter(typeof(JsonStringEnumConverter))] +public enum HookStartScope +{ + [JsonPropertyName("turn")] + Turn, + + [JsonPropertyName("session")] + Session, + +} diff --git a/runtime/csharp/Prompty.Core/Model/events/PermissionCompletedPayload.cs b/runtime/csharp/Prompty.Core/Model/events/PermissionCompletedPayload.cs index c8b119c5..b2eef078 100644 --- a/runtime/csharp/Prompty.Core/Model/events/PermissionCompletedPayload.cs +++ b/runtime/csharp/Prompty.Core/Model/events/PermissionCompletedPayload.cs @@ -55,6 +55,11 @@ public PermissionCompletedPayload() /// public IDictionary? Result { get; set; } + /// + /// Redaction state for sensitive decision fields + /// + public RedactionMetadata? Redaction { get; set; } + #region Load Methods @@ -107,6 +112,11 @@ public static PermissionCompletedPayload Load(Dictionary data, instance.Result = resultValue.GetDictionary()!; } + if (data.TryGetValue("redaction", out var redactionValue) && redactionValue is not null) + { + instance.Redaction = RedactionMetadata.Load(redactionValue.GetDictionary(RedactionMetadata.ShorthandProperty), context); + } + if (context is not null) { instance = context.ProcessOutput(instance); @@ -166,6 +176,12 @@ public static PermissionCompletedPayload Load(Dictionary data, } + if (obj.Redaction is not null) + { + result["redaction"] = obj.Redaction?.Save(context); + } + + if (context is not null) { result = context.ProcessDict(result); diff --git a/runtime/csharp/Prompty.Core/Model/events/SessionStartPayload.cs b/runtime/csharp/Prompty.Core/Model/events/SessionStartPayload.cs index c1282f96..3ec79122 100644 --- a/runtime/csharp/Prompty.Core/Model/events/SessionStartPayload.cs +++ b/runtime/csharp/Prompty.Core/Model/events/SessionStartPayload.cs @@ -33,7 +33,7 @@ public SessionStartPayload() /// /// Session event schema version /// - public int? Version { get; set; } + public string? SchemaVersion { get; set; } /// /// Producer that started the session @@ -97,9 +97,9 @@ public static SessionStartPayload Load(Dictionary data, LoadCon instance.SessionId = sessionIdValue?.ToString()!; } - if (data.TryGetValue("version", out var versionValue) && versionValue is not null) + if (data.TryGetValue("schemaVersion", out var schemaVersionValue) && schemaVersionValue is not null) { - instance.Version = Convert.ToInt32(versionValue); + instance.SchemaVersion = schemaVersionValue?.ToString()!; } if (data.TryGetValue("producer", out var producerValue) && producerValue is not null) @@ -169,9 +169,9 @@ public static SessionStartPayload Load(Dictionary data, LoadCon result["sessionId"] = obj.SessionId; - if (obj.Version is not null) + if (obj.SchemaVersion is not null) { - result["version"] = obj.Version; + result["schemaVersion"] = obj.SchemaVersion; } diff --git a/runtime/go/prompty/model/hook_end_payload.go b/runtime/go/prompty/model/hook_end_payload.go index 38d5b82f..8b6ca7fb 100644 --- a/runtime/go/prompty/model/hook_end_payload.go +++ b/runtime/go/prompty/model/hook_end_payload.go @@ -9,11 +9,20 @@ import ( "gopkg.in/yaml.v3" ) +// HookEndScope represents the allowed values for HookEndScope. +type HookEndScope string + +const ( + HookEndScopeTurn HookEndScope = "turn" + HookEndScopeSession HookEndScope = "session" +) + // HookEndPayload represents Payload for "hook_end" events — a host lifecycle hook finished. type HookEndPayload struct { HookInvocationId string `json:"hookInvocationId" yaml:"hookInvocationId"` HookType string `json:"hookType" yaml:"hookType"` + Scope *HookEndScope `json:"scope,omitempty" yaml:"scope,omitempty"` Success bool `json:"success" yaml:"success"` Output map[string]interface{} `json:"output,omitempty" yaml:"output,omitempty"` DurationMs *float64 `json:"durationMs,omitempty" yaml:"durationMs,omitempty"` @@ -33,6 +42,10 @@ func LoadHookEndPayload(data interface{}, ctx *LoadContext) (HookEndPayload, err if val, ok := m["hookType"]; ok && val != nil { result.HookType = string(val.(string)) } + if val, ok := m["scope"]; ok && val != nil { + v := HookEndScope(val.(string)) + result.Scope = &v + } if val, ok := m["success"]; ok && val != nil { result.Success = val.(bool) } @@ -77,6 +90,9 @@ func (obj *HookEndPayload) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["hookInvocationId"] = obj.HookInvocationId result["hookType"] = obj.HookType + if obj.Scope != nil { + result["scope"] = string(*obj.Scope) + } result["success"] = obj.Success if obj.Output != nil { result["output"] = obj.Output diff --git a/runtime/go/prompty/model/hook_start_payload.go b/runtime/go/prompty/model/hook_start_payload.go index 7bb8d795..529803f4 100644 --- a/runtime/go/prompty/model/hook_start_payload.go +++ b/runtime/go/prompty/model/hook_start_payload.go @@ -9,11 +9,20 @@ import ( "gopkg.in/yaml.v3" ) +// HookStartScope represents the allowed values for HookStartScope. +type HookStartScope string + +const ( + HookStartScopeTurn HookStartScope = "turn" + HookStartScopeSession HookStartScope = "session" +) + // HookStartPayload represents Payload for "hook_start" events — a host lifecycle hook is beginning. type HookStartPayload struct { HookInvocationId string `json:"hookInvocationId" yaml:"hookInvocationId"` HookType string `json:"hookType" yaml:"hookType"` + Scope *HookStartScope `json:"scope,omitempty" yaml:"scope,omitempty"` Input map[string]interface{} `json:"input,omitempty" yaml:"input,omitempty"` Redaction *RedactionMetadata `json:"redaction,omitempty" yaml:"redaction,omitempty"` } @@ -30,6 +39,10 @@ func LoadHookStartPayload(data interface{}, ctx *LoadContext) (HookStartPayload, if val, ok := m["hookType"]; ok && val != nil { result.HookType = string(val.(string)) } + if val, ok := m["scope"]; ok && val != nil { + v := HookStartScope(val.(string)) + result.Scope = &v + } if val, ok := m["input"]; ok && val != nil { if m, ok := val.(map[string]interface{}); ok { result.Input = m @@ -51,6 +64,9 @@ func (obj *HookStartPayload) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["hookInvocationId"] = obj.HookInvocationId result["hookType"] = obj.HookType + if obj.Scope != nil { + result["scope"] = string(*obj.Scope) + } if obj.Input != nil { result["input"] = obj.Input } diff --git a/runtime/go/prompty/model/permission_completed_payload.go b/runtime/go/prompty/model/permission_completed_payload.go index c2831053..0673e31d 100644 --- a/runtime/go/prompty/model/permission_completed_payload.go +++ b/runtime/go/prompty/model/permission_completed_payload.go @@ -18,6 +18,7 @@ type PermissionCompletedPayload struct { Approved bool `json:"approved" yaml:"approved"` Reason *string `json:"reason,omitempty" yaml:"reason,omitempty"` Result map[string]interface{} `json:"result,omitempty" yaml:"result,omitempty"` + Redaction *RedactionMetadata `json:"redaction,omitempty" yaml:"redaction,omitempty"` } // LoadPermissionCompletedPayload creates a PermissionCompletedPayload from a map[string]interface{} @@ -49,6 +50,12 @@ func LoadPermissionCompletedPayload(data interface{}, ctx *LoadContext) (Permiss result.Result = m } } + if val, ok := m["redaction"]; ok && val != nil { + if m, ok := val.(map[string]interface{}); ok { + loaded, _ := LoadRedactionMetadata(m, ctx) + result.Redaction = &loaded + } + } } return result, nil @@ -71,6 +78,9 @@ func (obj *PermissionCompletedPayload) Save(ctx *SaveContext) map[string]interfa if obj.Result != nil { result["result"] = obj.Result } + if obj.Redaction != nil { + result["redaction"] = obj.Redaction.Save(ctx) + } return result } diff --git a/runtime/go/prompty/model/session_start_payload.go b/runtime/go/prompty/model/session_start_payload.go index 38c60d7b..9c11166f 100644 --- a/runtime/go/prompty/model/session_start_payload.go +++ b/runtime/go/prompty/model/session_start_payload.go @@ -13,7 +13,7 @@ import ( type SessionStartPayload struct { SessionId string `json:"sessionId" yaml:"sessionId"` - Version *int32 `json:"version,omitempty" yaml:"version,omitempty"` + SchemaVersion *string `json:"schemaVersion,omitempty" yaml:"schemaVersion,omitempty"` Producer *string `json:"producer,omitempty" yaml:"producer,omitempty"` Runtime *string `json:"runtime,omitempty" yaml:"runtime,omitempty"` PromptyVersion *string `json:"promptyVersion,omitempty" yaml:"promptyVersion,omitempty"` @@ -32,19 +32,9 @@ func LoadSessionStartPayload(data interface{}, ctx *LoadContext) (SessionStartPa if val, ok := m["sessionId"]; ok && val != nil { result.SessionId = string(val.(string)) } - if val, ok := m["version"]; ok && val != nil { // Handle various numeric types from JSON/YAML/roundtrip - var v int32 - switch n := val.(type) { - case int: - v = int32(n) - case int32: - v = int32(n) - case int64: - v = int32(n) - case float64: - v = int32(n) - } - result.Version = &v + if val, ok := m["schemaVersion"]; ok && val != nil { + v := string(val.(string)) + result.SchemaVersion = &v } if val, ok := m["producer"]; ok && val != nil { v := string(val.(string)) @@ -85,8 +75,8 @@ func LoadSessionStartPayload(data interface{}, ctx *LoadContext) (SessionStartPa func (obj *SessionStartPayload) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["sessionId"] = obj.SessionId - if obj.Version != nil { - result["version"] = *obj.Version + if obj.SchemaVersion != nil { + result["schemaVersion"] = *obj.SchemaVersion } if obj.Producer != nil { result["producer"] = *obj.Producer diff --git a/runtime/go/prompty/model/session_start_payload_test.go b/runtime/go/prompty/model/session_start_payload_test.go index 8cea9baa..ad3fd52d 100644 --- a/runtime/go/prompty/model/session_start_payload_test.go +++ b/runtime/go/prompty/model/session_start_payload_test.go @@ -16,7 +16,7 @@ func TestSessionStartPayloadLoadJSON(t *testing.T) { jsonData := ` { "sessionId": "sess_abc123", - "version": 1, + "schemaVersion": "1", "producer": "prompty-agent", "runtime": "typescript", "promptyVersion": "2.0.0", @@ -38,8 +38,8 @@ func TestSessionStartPayloadLoadJSON(t *testing.T) { if instance.SessionId != "sess_abc123" { t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, instance.SessionId) } - if instance.Version == nil || *instance.Version != 1 { - t.Errorf(`Expected Version to be 1, got %v`, instance.Version) + if instance.SchemaVersion == nil || *instance.SchemaVersion != "1" { + t.Errorf(`Expected SchemaVersion to be "1", got %v`, instance.SchemaVersion) } if instance.Producer == nil || *instance.Producer != "prompty-agent" { t.Errorf(`Expected Producer to be "prompty-agent", got %v`, instance.Producer) @@ -65,7 +65,7 @@ func TestSessionStartPayloadLoadJSON(t *testing.T) { func TestSessionStartPayloadLoadYAML(t *testing.T) { yamlData := ` sessionId: sess_abc123 -version: 1 +schemaVersion: "1" producer: prompty-agent runtime: typescript promptyVersion: 2.0.0 @@ -87,8 +87,8 @@ reasoningEffort: medium if instance.SessionId != "sess_abc123" { t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, instance.SessionId) } - if instance.Version == nil || *instance.Version != 1 { - t.Errorf(`Expected Version to be 1, got %v`, instance.Version) + if instance.SchemaVersion == nil || *instance.SchemaVersion != "1" { + t.Errorf(`Expected SchemaVersion to be "1", got %v`, instance.SchemaVersion) } if instance.Producer == nil || *instance.Producer != "prompty-agent" { t.Errorf(`Expected Producer to be "prompty-agent", got %v`, instance.Producer) @@ -115,7 +115,7 @@ func TestSessionStartPayloadRoundtrip(t *testing.T) { jsonData := ` { "sessionId": "sess_abc123", - "version": 1, + "schemaVersion": "1", "producer": "prompty-agent", "runtime": "typescript", "promptyVersion": "2.0.0", @@ -144,8 +144,8 @@ func TestSessionStartPayloadRoundtrip(t *testing.T) { if reloaded.SessionId != "sess_abc123" { t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, reloaded.SessionId) } - if reloaded.Version == nil || *reloaded.Version != 1 { - t.Errorf(`Expected Version to be 1, got %v`, reloaded.Version) + if reloaded.SchemaVersion == nil || *reloaded.SchemaVersion != "1" { + t.Errorf(`Expected SchemaVersion to be "1", got %v`, reloaded.SchemaVersion) } if reloaded.Producer == nil || *reloaded.Producer != "prompty-agent" { t.Errorf(`Expected Producer to be "prompty-agent", got %v`, reloaded.Producer) @@ -172,7 +172,7 @@ func TestSessionStartPayloadToJSON(t *testing.T) { jsonData := ` { "sessionId": "sess_abc123", - "version": 1, + "schemaVersion": "1", "producer": "prompty-agent", "runtime": "typescript", "promptyVersion": "2.0.0", @@ -207,7 +207,7 @@ func TestSessionStartPayloadToYAML(t *testing.T) { jsonData := ` { "sessionId": "sess_abc123", - "version": 1, + "schemaVersion": "1", "producer": "prompty-agent", "runtime": "typescript", "promptyVersion": "2.0.0", diff --git a/runtime/python/prompty/prompty/model/events/_HookEndPayload.py b/runtime/python/prompty/prompty/model/events/_HookEndPayload.py index 91151cee..02819f5e 100644 --- a/runtime/python/prompty/prompty/model/events/_HookEndPayload.py +++ b/runtime/python/prompty/prompty/model/events/_HookEndPayload.py @@ -5,11 +5,13 @@ ########################################## from dataclasses import dataclass, field -from typing import Any, ClassVar +from typing import Any, ClassVar, Literal from .._context import LoadContext, SaveContext from ._RedactionMetadata import RedactionMetadata +HookEndScope = Literal["turn", "session"] + @dataclass class HookEndPayload: @@ -21,6 +23,8 @@ class HookEndPayload: Stable hook invocation identifier hook_type : str Host-defined hook type + scope : Optional[str] + Whether the hook is scoped to a turn or the outer session success : bool Whether the hook completed successfully output : Optional[dict[str, Any]] @@ -37,6 +41,7 @@ class HookEndPayload: hook_invocation_id: str = field(default="") hook_type: str = field(default="") + scope: HookEndScope | None = None success: bool = field(default=False) output: dict[str, Any] | None = None duration_ms: float | None = None @@ -67,6 +72,8 @@ def load(data: Any, context: LoadContext | None = None) -> "HookEndPayload": instance.hook_invocation_id = data["hookInvocationId"] if data is not None and "hookType" in data: instance.hook_type = data["hookType"] + if data is not None and "scope" in data: + instance.scope = data["scope"] if data is not None and "success" in data: instance.success = data["success"] if data is not None and "output" in data: @@ -99,6 +106,8 @@ def save(self, context: SaveContext | None = None) -> dict[str, Any]: result["hookInvocationId"] = obj.hook_invocation_id if obj.hook_type is not None: result["hookType"] = obj.hook_type + if obj.scope is not None: + result["scope"] = obj.scope if obj.success is not None: result["success"] = obj.success if obj.output is not None: diff --git a/runtime/python/prompty/prompty/model/events/_HookStartPayload.py b/runtime/python/prompty/prompty/model/events/_HookStartPayload.py index f06e7b77..edaa4496 100644 --- a/runtime/python/prompty/prompty/model/events/_HookStartPayload.py +++ b/runtime/python/prompty/prompty/model/events/_HookStartPayload.py @@ -5,11 +5,13 @@ ########################################## from dataclasses import dataclass, field -from typing import Any, ClassVar +from typing import Any, ClassVar, Literal from .._context import LoadContext, SaveContext from ._RedactionMetadata import RedactionMetadata +HookStartScope = Literal["turn", "session"] + @dataclass class HookStartPayload: @@ -21,6 +23,8 @@ class HookStartPayload: Stable hook invocation identifier hook_type : str Host-defined hook type + scope : Optional[str] + Whether the hook is scoped to a turn or the outer session input : Optional[dict[str, Any]] Hook input after host-side sanitization redaction : Optional[RedactionMetadata] @@ -31,6 +35,7 @@ class HookStartPayload: hook_invocation_id: str = field(default="") hook_type: str = field(default="") + scope: HookStartScope | None = None input: dict[str, Any] | None = None redaction: RedactionMetadata | None = None @@ -58,6 +63,8 @@ def load(data: Any, context: LoadContext | None = None) -> "HookStartPayload": instance.hook_invocation_id = data["hookInvocationId"] if data is not None and "hookType" in data: instance.hook_type = data["hookType"] + if data is not None and "scope" in data: + instance.scope = data["scope"] if data is not None and "input" in data: instance.input = data["input"] if data is not None and "redaction" in data: @@ -84,6 +91,8 @@ def save(self, context: SaveContext | None = None) -> dict[str, Any]: result["hookInvocationId"] = obj.hook_invocation_id if obj.hook_type is not None: result["hookType"] = obj.hook_type + if obj.scope is not None: + result["scope"] = obj.scope if obj.input is not None: result["input"] = obj.input if obj.redaction is not None: diff --git a/runtime/python/prompty/prompty/model/events/_PermissionCompletedPayload.py b/runtime/python/prompty/prompty/model/events/_PermissionCompletedPayload.py index 913ea1d2..100a2617 100644 --- a/runtime/python/prompty/prompty/model/events/_PermissionCompletedPayload.py +++ b/runtime/python/prompty/prompty/model/events/_PermissionCompletedPayload.py @@ -8,6 +8,7 @@ from typing import Any, ClassVar from .._context import LoadContext, SaveContext +from ._RedactionMetadata import RedactionMetadata @dataclass @@ -28,6 +29,8 @@ class PermissionCompletedPayload: Decision reason, if available result : Optional[dict[str, Any]] Host-specific decision result, such as a durable approval token or denial details + redaction : Optional[RedactionMetadata] + Redaction state for sensitive decision fields """ _shorthand_property: ClassVar[str | None] = None @@ -38,6 +41,7 @@ class PermissionCompletedPayload: approved: bool = field(default=False) reason: str | None = None result: dict[str, Any] | None = None + redaction: RedactionMetadata | None = None @staticmethod def load(data: Any, context: LoadContext | None = None) -> "PermissionCompletedPayload": @@ -71,6 +75,8 @@ def load(data: Any, context: LoadContext | None = None) -> "PermissionCompletedP instance.reason = data["reason"] if data is not None and "result" in data: instance.result = data["result"] + if data is not None and "redaction" in data: + instance.redaction = RedactionMetadata.load(data["redaction"], context) if context is not None: instance = context.process_output(instance) return instance @@ -101,6 +107,8 @@ def save(self, context: SaveContext | None = None) -> dict[str, Any]: result["reason"] = obj.reason if obj.result is not None: result["result"] = obj.result + if obj.redaction is not None: + result["redaction"] = obj.redaction.save(context) if context is not None: result = context.process_dict(result) diff --git a/runtime/python/prompty/prompty/model/events/_SessionStartPayload.py b/runtime/python/prompty/prompty/model/events/_SessionStartPayload.py index 0a22e953..81fbbf94 100644 --- a/runtime/python/prompty/prompty/model/events/_SessionStartPayload.py +++ b/runtime/python/prompty/prompty/model/events/_SessionStartPayload.py @@ -19,7 +19,7 @@ class SessionStartPayload: ---------- session_id : str Stable session identifier - version : Optional[int] + schema_version : Optional[str] Session event schema version producer : Optional[str] Producer that started the session @@ -40,7 +40,7 @@ class SessionStartPayload: _shorthand_property: ClassVar[str | None] = None session_id: str = field(default="") - version: int | None = None + schema_version: str | None = None producer: str | None = None runtime: str | None = None prompty_version: str | None = None @@ -71,8 +71,8 @@ def load(data: Any, context: LoadContext | None = None) -> "SessionStartPayload" if data is not None and "sessionId" in data: instance.session_id = data["sessionId"] - if data is not None and "version" in data: - instance.version = data["version"] + if data is not None and "schemaVersion" in data: + instance.schema_version = data["schemaVersion"] if data is not None and "producer" in data: instance.producer = data["producer"] if data is not None and "runtime" in data: @@ -107,8 +107,8 @@ def save(self, context: SaveContext | None = None) -> dict[str, Any]: if obj.session_id is not None: result["sessionId"] = obj.session_id - if obj.version is not None: - result["version"] = obj.version + if obj.schema_version is not None: + result["schemaVersion"] = obj.schema_version if obj.producer is not None: result["producer"] = obj.producer if obj.runtime is not None: diff --git a/runtime/python/prompty/tests/model/events/test_session_start_payload.py b/runtime/python/prompty/tests/model/events/test_session_start_payload.py index bd989baf..bc5e1fc8 100644 --- a/runtime/python/prompty/tests/model/events/test_session_start_payload.py +++ b/runtime/python/prompty/tests/model/events/test_session_start_payload.py @@ -9,7 +9,7 @@ def test_load_json_sessionstartpayload(): json_data = r""" { "sessionId": "sess_abc123", - "version": 1, + "schemaVersion": "1", "producer": "prompty-agent", "runtime": "typescript", "promptyVersion": "2.0.0", @@ -22,7 +22,7 @@ def test_load_json_sessionstartpayload(): instance = SessionStartPayload.load(data) assert instance is not None assert instance.session_id == "sess_abc123" - assert instance.version == 1 + assert instance.schema_version == "1" assert instance.producer == "prompty-agent" assert instance.runtime == "typescript" assert instance.prompty_version == "2.0.0" @@ -34,7 +34,7 @@ def test_load_json_sessionstartpayload(): def test_load_yaml_sessionstartpayload(): yaml_data = r""" sessionId: sess_abc123 - version: 1 + schemaVersion: "1" producer: prompty-agent runtime: typescript promptyVersion: 2.0.0 @@ -47,7 +47,7 @@ def test_load_yaml_sessionstartpayload(): instance = SessionStartPayload.load(data) assert instance is not None assert instance.session_id == "sess_abc123" - assert instance.version == 1 + assert instance.schema_version == "1" assert instance.producer == "prompty-agent" assert instance.runtime == "typescript" assert instance.prompty_version == "2.0.0" @@ -61,7 +61,7 @@ def test_roundtrip_json_sessionstartpayload(): json_data = r""" { "sessionId": "sess_abc123", - "version": 1, + "schemaVersion": "1", "producer": "prompty-agent", "runtime": "typescript", "promptyVersion": "2.0.0", @@ -76,7 +76,7 @@ def test_roundtrip_json_sessionstartpayload(): reloaded = SessionStartPayload.load(saved_data) assert reloaded is not None assert reloaded.session_id == "sess_abc123" - assert reloaded.version == 1 + assert reloaded.schema_version == "1" assert reloaded.producer == "prompty-agent" assert reloaded.runtime == "typescript" assert reloaded.prompty_version == "2.0.0" @@ -90,7 +90,7 @@ def test_to_json_sessionstartpayload(): json_data = r""" { "sessionId": "sess_abc123", - "version": 1, + "schemaVersion": "1", "producer": "prompty-agent", "runtime": "typescript", "promptyVersion": "2.0.0", @@ -112,7 +112,7 @@ def test_to_yaml_sessionstartpayload(): json_data = r""" { "sessionId": "sess_abc123", - "version": 1, + "schemaVersion": "1", "producer": "prompty-agent", "runtime": "typescript", "promptyVersion": "2.0.0", diff --git a/runtime/rust/prompty/src/model/events/hook_end_payload.rs b/runtime/rust/prompty/src/model/events/hook_end_payload.rs index 9fc3b2c0..35da9b0d 100644 --- a/runtime/rust/prompty/src/model/events/hook_end_payload.rs +++ b/runtime/rust/prompty/src/model/events/hook_end_payload.rs @@ -6,6 +6,44 @@ use super::super::context::{LoadContext, SaveContext}; use super::redaction_metadata::RedactionMetadata; +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum HookEndScope { + Turn, + Session, +} + +impl Default for HookEndScope { + fn default() -> Self { + Self::Turn + } +} + +impl std::fmt::Display for HookEndScope { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Turn => write!(f, "turn"), + Self::Session => write!(f, "session"), + } + } +} + +impl HookEndScope { + pub fn from_str_opt(s: &str) -> Option { + match s { + "turn" => Some(Self::Turn), + "session" => Some(Self::Session), + _ => None, + } + } + + pub fn as_str(&self) -> &str { + match self { + Self::Turn => "turn", + Self::Session => "session", + } + } +} + /// Payload for "hook_end" events — a host lifecycle hook finished. #[derive(Debug, Clone, Default)] pub struct HookEndPayload { @@ -13,6 +51,8 @@ pub struct HookEndPayload { pub hook_invocation_id: String, /// Host-defined hook type pub hook_type: String, + /// Whether the hook is scoped to a turn or the outer session + pub scope: Option, /// Whether the hook completed successfully pub success: bool, /// Hook output after host-side sanitization @@ -51,6 +91,7 @@ impl HookEndPayload { Self { hook_invocation_id: value.get("hookInvocationId").and_then(|v| v.as_str()).unwrap_or_default().to_string(), hook_type: value.get("hookType").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + scope: value.get("scope").and_then(|v| v.as_str()).and_then(|s| HookEndScope::from_str_opt(s)), success: value.get("success").and_then(|v| v.as_bool()).unwrap_or(false), output: value.get("output").cloned().unwrap_or(serde_json::Value::Null), duration_ms: value.get("durationMs").and_then(|v| v.as_f64()), @@ -71,6 +112,9 @@ impl HookEndPayload { if !self.hook_type.is_empty() { result.insert("hookType".to_string(), serde_json::Value::String(self.hook_type.clone())); } + if let Some(ref val) = self.scope { + result.insert("scope".to_string(), serde_json::Value::String(val.to_string())); + } result.insert("success".to_string(), serde_json::Value::Bool(self.success)); if !self.output.is_null() { result.insert("output".to_string(), self.output.clone()); diff --git a/runtime/rust/prompty/src/model/events/hook_start_payload.rs b/runtime/rust/prompty/src/model/events/hook_start_payload.rs index 8b785312..39ec15f3 100644 --- a/runtime/rust/prompty/src/model/events/hook_start_payload.rs +++ b/runtime/rust/prompty/src/model/events/hook_start_payload.rs @@ -6,6 +6,44 @@ use super::super::context::{LoadContext, SaveContext}; use super::redaction_metadata::RedactionMetadata; +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum HookStartScope { + Turn, + Session, +} + +impl Default for HookStartScope { + fn default() -> Self { + Self::Turn + } +} + +impl std::fmt::Display for HookStartScope { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Turn => write!(f, "turn"), + Self::Session => write!(f, "session"), + } + } +} + +impl HookStartScope { + pub fn from_str_opt(s: &str) -> Option { + match s { + "turn" => Some(Self::Turn), + "session" => Some(Self::Session), + _ => None, + } + } + + pub fn as_str(&self) -> &str { + match self { + Self::Turn => "turn", + Self::Session => "session", + } + } +} + /// Payload for "hook_start" events — a host lifecycle hook is beginning. #[derive(Debug, Clone, Default)] pub struct HookStartPayload { @@ -13,6 +51,8 @@ pub struct HookStartPayload { pub hook_invocation_id: String, /// Host-defined hook type pub hook_type: String, + /// Whether the hook is scoped to a turn or the outer session + pub scope: Option, /// Hook input after host-side sanitization pub input: serde_json::Value, /// Redaction state for sensitive hook input fields @@ -45,6 +85,7 @@ impl HookStartPayload { Self { hook_invocation_id: value.get("hookInvocationId").and_then(|v| v.as_str()).unwrap_or_default().to_string(), hook_type: value.get("hookType").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + scope: value.get("scope").and_then(|v| v.as_str()).and_then(|s| HookStartScope::from_str_opt(s)), input: value.get("input").cloned().unwrap_or(serde_json::Value::Null), redaction: value.get("redaction").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| RedactionMetadata::load_from_value(v, ctx)), } @@ -62,6 +103,9 @@ impl HookStartPayload { if !self.hook_type.is_empty() { result.insert("hookType".to_string(), serde_json::Value::String(self.hook_type.clone())); } + if let Some(ref val) = self.scope { + result.insert("scope".to_string(), serde_json::Value::String(val.to_string())); + } if !self.input.is_null() { result.insert("input".to_string(), self.input.clone()); } diff --git a/runtime/rust/prompty/src/model/events/permission_completed_payload.rs b/runtime/rust/prompty/src/model/events/permission_completed_payload.rs index daffe201..f2223efe 100644 --- a/runtime/rust/prompty/src/model/events/permission_completed_payload.rs +++ b/runtime/rust/prompty/src/model/events/permission_completed_payload.rs @@ -4,6 +4,8 @@ use super::super::context::{LoadContext, SaveContext}; +use super::redaction_metadata::RedactionMetadata; + /// Payload for permission completion events — an approval decision was made. #[derive(Debug, Clone, Default)] pub struct PermissionCompletedPayload { @@ -19,6 +21,8 @@ pub struct PermissionCompletedPayload { pub reason: Option, /// Host-specific decision result, such as a durable approval token or denial details pub result: serde_json::Value, + /// Redaction state for sensitive decision fields + pub redaction: Option, } impl PermissionCompletedPayload { @@ -51,6 +55,7 @@ impl PermissionCompletedPayload { approved: value.get("approved").and_then(|v| v.as_bool()).unwrap_or(false), reason: value.get("reason").and_then(|v| v.as_str()).map(|s| s.to_string()), result: value.get("result").cloned().unwrap_or(serde_json::Value::Null), + redaction: value.get("redaction").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| RedactionMetadata::load_from_value(v, ctx)), } } @@ -76,6 +81,12 @@ impl PermissionCompletedPayload { if !self.result.is_null() { result.insert("result".to_string(), self.result.clone()); } + if let Some(ref val) = self.redaction { + let nested = val.to_value(ctx); + if !nested.is_null() { + result.insert("redaction".to_string(), nested); + } + } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/events/session_start_payload.rs b/runtime/rust/prompty/src/model/events/session_start_payload.rs index dddae728..a98a03f6 100644 --- a/runtime/rust/prompty/src/model/events/session_start_payload.rs +++ b/runtime/rust/prompty/src/model/events/session_start_payload.rs @@ -12,7 +12,7 @@ pub struct SessionStartPayload { /// Stable session identifier pub session_id: String, /// Session event schema version - pub version: Option, + pub schema_version: Option, /// Producer that started the session pub producer: Option, /// Runtime that produced the session @@ -54,7 +54,7 @@ impl SessionStartPayload { let value = ctx.process_input(value.clone()); Self { session_id: value.get("sessionId").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - version: value.get("version").and_then(|v| v.as_i64()).map(|v| v as i32), + schema_version: value.get("schemaVersion").and_then(|v| v.as_str()).map(|s| s.to_string()), producer: value.get("producer").and_then(|v| v.as_str()).map(|s| s.to_string()), runtime: value.get("runtime").and_then(|v| v.as_str()).map(|s| s.to_string()), prompty_version: value.get("promptyVersion").and_then(|v| v.as_str()).map(|s| s.to_string()), @@ -74,8 +74,8 @@ impl SessionStartPayload { if !self.session_id.is_empty() { result.insert("sessionId".to_string(), serde_json::Value::String(self.session_id.clone())); } - if let Some(val) = self.version { - result.insert("version".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + if let Some(ref val) = self.schema_version { + result.insert("schemaVersion".to_string(), serde_json::Value::String(val.clone())); } if let Some(ref val) = self.producer { result.insert("producer".to_string(), serde_json::Value::String(val.clone())); diff --git a/runtime/rust/prompty/tests/model/events/hook_end_payload_test.rs b/runtime/rust/prompty/tests/model/events/hook_end_payload_test.rs index d9b910c3..69c2823b 100644 --- a/runtime/rust/prompty/tests/model/events/hook_end_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/hook_end_payload_test.rs @@ -3,6 +3,7 @@ #![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::HookEndPayload; +use prompty::model::HookEndScope; use prompty::model::context::{LoadContext, SaveContext}; #[test] diff --git a/runtime/rust/prompty/tests/model/events/hook_start_payload_test.rs b/runtime/rust/prompty/tests/model/events/hook_start_payload_test.rs index 3bdb1df7..bb0d14c7 100644 --- a/runtime/rust/prompty/tests/model/events/hook_start_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/hook_start_payload_test.rs @@ -3,6 +3,7 @@ #![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] use prompty::model::HookStartPayload; +use prompty::model::HookStartScope; use prompty::model::context::{LoadContext, SaveContext}; #[test] diff --git a/runtime/rust/prompty/tests/model/events/session_start_payload_test.rs b/runtime/rust/prompty/tests/model/events/session_start_payload_test.rs index 18e4ee0e..497a1173 100644 --- a/runtime/rust/prompty/tests/model/events/session_start_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/session_start_payload_test.rs @@ -10,7 +10,7 @@ fn test_session_start_payload_load_json() { let json = r####" { "sessionId": "sess_abc123", - "version": 1, + "schemaVersion": "1", "producer": "prompty-agent", "runtime": "typescript", "promptyVersion": "2.0.0", @@ -24,8 +24,8 @@ fn test_session_start_payload_load_json() { assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.session_id, "sess_abc123"); - assert!(instance.version.is_some(), "Expected version to be Some"); - assert_eq!(instance.version.as_ref().unwrap(), &1); + assert!(instance.schema_version.is_some(), "Expected schema_version to be Some"); + assert_eq!(instance.schema_version.as_ref().unwrap(), &"1"); assert!(instance.producer.is_some(), "Expected producer to be Some"); assert_eq!(instance.producer.as_ref().unwrap(), &"prompty-agent"); assert!(instance.runtime.is_some(), "Expected runtime to be Some"); @@ -44,7 +44,7 @@ fn test_session_start_payload_load_json() { fn test_session_start_payload_load_yaml() { let yaml = r####" sessionId: sess_abc123 -version: 1 +schemaVersion: "1" producer: prompty-agent runtime: typescript promptyVersion: 2.0.0 @@ -58,7 +58,7 @@ reasoningEffort: medium assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); let instance = result.unwrap(); assert_eq!(instance.session_id, "sess_abc123"); - assert!(instance.version.is_some(), "Expected version to be Some"); + assert!(instance.schema_version.is_some(), "Expected schema_version to be Some"); assert!(instance.producer.is_some(), "Expected producer to be Some"); assert!(instance.runtime.is_some(), "Expected runtime to be Some"); assert!(instance.prompty_version.is_some(), "Expected prompty_version to be Some"); @@ -72,7 +72,7 @@ fn test_session_start_payload_roundtrip() { let json = r####" { "sessionId": "sess_abc123", - "version": 1, + "schemaVersion": "1", "producer": "prompty-agent", "runtime": "typescript", "promptyVersion": "2.0.0", diff --git a/runtime/typescript/packages/core/src/model/events/hook-end-payload.ts b/runtime/typescript/packages/core/src/model/events/hook-end-payload.ts index 796eb93c..57245d45 100644 --- a/runtime/typescript/packages/core/src/model/events/hook-end-payload.ts +++ b/runtime/typescript/packages/core/src/model/events/hook-end-payload.ts @@ -4,11 +4,14 @@ import { LoadContext, SaveContext } from "../context"; import { RedactionMetadata } from "./redaction-metadata"; +export type HookEndScope = "turn" | "session"; + export class HookEndPayload { static readonly shorthandProperty: string | undefined = undefined; hookInvocationId: string = ""; hookType: string = ""; + scope?: HookEndScope | undefined; success: boolean = false; output?: Record | undefined; durationMs?: number | undefined; @@ -18,6 +21,9 @@ export class HookEndPayload { constructor(init?: Partial) { this.hookInvocationId = init?.hookInvocationId ?? ""; this.hookType = init?.hookType ?? ""; + if (init?.scope !== undefined) { + this.scope = init.scope; + } this.success = init?.success ?? false; if (init?.output !== undefined) { this.output = init.output; @@ -54,6 +60,9 @@ export class HookEndPayload { if (data["hookType"] !== undefined && data["hookType"] !== null) { instance.hookType = String(data["hookType"]); } + if (data["scope"] !== undefined && data["scope"] !== null) { + instance.scope = String(data["scope"]) as HookEndScope; + } if (data["success"] !== undefined && data["success"] !== null) { instance.success = Boolean(data["success"]); } @@ -97,6 +106,9 @@ export class HookEndPayload { if (obj.hookType !== undefined && obj.hookType !== null) { result["hookType"] = obj.hookType; } + if (obj.scope !== undefined && obj.scope !== null) { + result["scope"] = obj.scope; + } if (obj.success !== undefined && obj.success !== null) { result["success"] = obj.success; } diff --git a/runtime/typescript/packages/core/src/model/events/hook-start-payload.ts b/runtime/typescript/packages/core/src/model/events/hook-start-payload.ts index a76195f3..f1710483 100644 --- a/runtime/typescript/packages/core/src/model/events/hook-start-payload.ts +++ b/runtime/typescript/packages/core/src/model/events/hook-start-payload.ts @@ -4,17 +4,23 @@ import { LoadContext, SaveContext } from "../context"; import { RedactionMetadata } from "./redaction-metadata"; +export type HookStartScope = "turn" | "session"; + export class HookStartPayload { static readonly shorthandProperty: string | undefined = undefined; hookInvocationId: string = ""; hookType: string = ""; + scope?: HookStartScope | undefined; input?: Record | undefined; redaction?: RedactionMetadata | undefined; constructor(init?: Partial) { this.hookInvocationId = init?.hookInvocationId ?? ""; this.hookType = init?.hookType ?? ""; + if (init?.scope !== undefined) { + this.scope = init.scope; + } if (init?.input !== undefined) { this.input = init.input; } @@ -44,6 +50,9 @@ export class HookStartPayload { if (data["hookType"] !== undefined && data["hookType"] !== null) { instance.hookType = String(data["hookType"]); } + if (data["scope"] !== undefined && data["scope"] !== null) { + instance.scope = String(data["scope"]) as HookStartScope; + } if (data["input"] !== undefined && data["input"] !== null) { instance.input = data["input"] as Record; } @@ -78,6 +87,9 @@ export class HookStartPayload { if (obj.hookType !== undefined && obj.hookType !== null) { result["hookType"] = obj.hookType; } + if (obj.scope !== undefined && obj.scope !== null) { + result["scope"] = obj.scope; + } if (obj.input !== undefined && obj.input !== null) { result["input"] = obj.input; } diff --git a/runtime/typescript/packages/core/src/model/events/permission-completed-payload.ts b/runtime/typescript/packages/core/src/model/events/permission-completed-payload.ts index 7a760ed6..d71fa080 100644 --- a/runtime/typescript/packages/core/src/model/events/permission-completed-payload.ts +++ b/runtime/typescript/packages/core/src/model/events/permission-completed-payload.ts @@ -2,6 +2,7 @@ // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. import { LoadContext, SaveContext } from "../context"; +import { RedactionMetadata } from "./redaction-metadata"; export class PermissionCompletedPayload { static readonly shorthandProperty: string | undefined = undefined; @@ -12,6 +13,7 @@ export class PermissionCompletedPayload { approved: boolean = false; reason?: string | undefined; result?: Record | undefined; + redaction?: RedactionMetadata | undefined; constructor(init?: Partial) { if (init?.requestId !== undefined) { @@ -28,6 +30,9 @@ export class PermissionCompletedPayload { if (init?.result !== undefined) { this.result = init.result; } + if (init?.redaction !== undefined) { + this.redaction = init.redaction; + } } //#region Load Methods @@ -60,6 +65,12 @@ export class PermissionCompletedPayload { if (data["result"] !== undefined && data["result"] !== null) { instance.result = data["result"] as Record; } + if (data["redaction"] !== undefined && data["redaction"] !== null) { + instance.redaction = RedactionMetadata.load( + data["redaction"] as Record, + context, + ); + } if (context) { return context.processOutput(instance) as PermissionCompletedPayload; @@ -97,6 +108,9 @@ export class PermissionCompletedPayload { if (obj.result !== undefined && obj.result !== null) { result["result"] = obj.result; } + if (obj.redaction !== undefined && obj.redaction !== null) { + result["redaction"] = obj.redaction.save(context); + } if (context) { return context.processDict(result); diff --git a/runtime/typescript/packages/core/src/model/events/session-start-payload.ts b/runtime/typescript/packages/core/src/model/events/session-start-payload.ts index 4852f8d3..732aace2 100644 --- a/runtime/typescript/packages/core/src/model/events/session-start-payload.ts +++ b/runtime/typescript/packages/core/src/model/events/session-start-payload.ts @@ -8,7 +8,7 @@ export class SessionStartPayload { static readonly shorthandProperty: string | undefined = undefined; sessionId: string = ""; - version?: number | undefined; + schemaVersion?: string | undefined; producer?: string | undefined; runtime?: string | undefined; promptyVersion?: string | undefined; @@ -19,8 +19,8 @@ export class SessionStartPayload { constructor(init?: Partial) { this.sessionId = init?.sessionId ?? ""; - if (init?.version !== undefined) { - this.version = init.version; + if (init?.schemaVersion !== undefined) { + this.schemaVersion = init.schemaVersion; } if (init?.producer !== undefined) { this.producer = init.producer; @@ -60,8 +60,8 @@ export class SessionStartPayload { if (data["sessionId"] !== undefined && data["sessionId"] !== null) { instance.sessionId = String(data["sessionId"]); } - if (data["version"] !== undefined && data["version"] !== null) { - instance.version = Number(data["version"]); + if (data["schemaVersion"] !== undefined && data["schemaVersion"] !== null) { + instance.schemaVersion = String(data["schemaVersion"]); } if (data["producer"] !== undefined && data["producer"] !== null) { instance.producer = String(data["producer"]); @@ -115,8 +115,8 @@ export class SessionStartPayload { if (obj.sessionId !== undefined && obj.sessionId !== null) { result["sessionId"] = obj.sessionId; } - if (obj.version !== undefined && obj.version !== null) { - result["version"] = obj.version; + if (obj.schemaVersion !== undefined && obj.schemaVersion !== null) { + result["schemaVersion"] = obj.schemaVersion; } if (obj.producer !== undefined && obj.producer !== null) { result["producer"] = obj.producer; diff --git a/runtime/typescript/packages/core/tests/model/events/session-start-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/session-start-payload.test.ts index 551a7305..eb551c2e 100644 --- a/runtime/typescript/packages/core/tests/model/events/session-start-payload.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/session-start-payload.test.ts @@ -18,11 +18,11 @@ describe("SessionStartPayload", () => { describe("JSON serialization", () => { it("should load from JSON - example 1", () => { - const json = `{\n "sessionId": "sess_abc123",\n "version": 1,\n "producer": "prompty-agent",\n "runtime": "typescript",\n "promptyVersion": "2.0.0",\n "startTime": "2026-06-09T20:00:00Z",\n "selectedModel": "gpt-4o-mini",\n "reasoningEffort": "medium"\n}`; + const json = `{\n "sessionId": "sess_abc123",\n "schemaVersion": "1",\n "producer": "prompty-agent",\n "runtime": "typescript",\n "promptyVersion": "2.0.0",\n "startTime": "2026-06-09T20:00:00Z",\n "selectedModel": "gpt-4o-mini",\n "reasoningEffort": "medium"\n}`; const instance = SessionStartPayload.fromJson(json); expect(instance).toBeDefined(); expect(instance.sessionId).toEqual("sess_abc123"); - expect(instance.version).toEqual(1); + expect(instance.schemaVersion).toEqual("1"); expect(instance.producer).toEqual("prompty-agent"); expect(instance.runtime).toEqual("typescript"); expect(instance.promptyVersion).toEqual("2.0.0"); @@ -32,12 +32,12 @@ describe("SessionStartPayload", () => { }); it("should round-trip JSON - example 1", () => { - const json = `{\n "sessionId": "sess_abc123",\n "version": 1,\n "producer": "prompty-agent",\n "runtime": "typescript",\n "promptyVersion": "2.0.0",\n "startTime": "2026-06-09T20:00:00Z",\n "selectedModel": "gpt-4o-mini",\n "reasoningEffort": "medium"\n}`; + const json = `{\n "sessionId": "sess_abc123",\n "schemaVersion": "1",\n "producer": "prompty-agent",\n "runtime": "typescript",\n "promptyVersion": "2.0.0",\n "startTime": "2026-06-09T20:00:00Z",\n "selectedModel": "gpt-4o-mini",\n "reasoningEffort": "medium"\n}`; const instance = SessionStartPayload.fromJson(json); const output = instance.toJson(); const reloaded = SessionStartPayload.fromJson(output); expect(reloaded.sessionId).toEqual(instance.sessionId); - expect(reloaded.version).toEqual(instance.version); + expect(reloaded.schemaVersion).toEqual(instance.schemaVersion); expect(reloaded.producer).toEqual(instance.producer); expect(reloaded.runtime).toEqual(instance.runtime); expect(reloaded.promptyVersion).toEqual(instance.promptyVersion); @@ -49,11 +49,11 @@ describe("SessionStartPayload", () => { describe("YAML serialization", () => { it("should load from YAML - example 1", () => { - const yaml = `sessionId: sess_abc123\nversion: 1\nproducer: prompty-agent\nruntime: typescript\npromptyVersion: 2.0.0\nstartTime: "2026-06-09T20:00:00Z"\nselectedModel: gpt-4o-mini\nreasoningEffort: medium\n`; + const yaml = `sessionId: sess_abc123\nschemaVersion: "1"\nproducer: prompty-agent\nruntime: typescript\npromptyVersion: 2.0.0\nstartTime: "2026-06-09T20:00:00Z"\nselectedModel: gpt-4o-mini\nreasoningEffort: medium\n`; const instance = SessionStartPayload.fromYaml(yaml); expect(instance).toBeDefined(); expect(instance.sessionId).toEqual("sess_abc123"); - expect(instance.version).toEqual(1); + expect(instance.schemaVersion).toEqual("1"); expect(instance.producer).toEqual("prompty-agent"); expect(instance.runtime).toEqual("typescript"); expect(instance.promptyVersion).toEqual("2.0.0"); @@ -63,12 +63,12 @@ describe("SessionStartPayload", () => { }); it("should round-trip YAML - example 1", () => { - const yaml = `sessionId: sess_abc123\nversion: 1\nproducer: prompty-agent\nruntime: typescript\npromptyVersion: 2.0.0\nstartTime: "2026-06-09T20:00:00Z"\nselectedModel: gpt-4o-mini\nreasoningEffort: medium\n`; + const yaml = `sessionId: sess_abc123\nschemaVersion: "1"\nproducer: prompty-agent\nruntime: typescript\npromptyVersion: 2.0.0\nstartTime: "2026-06-09T20:00:00Z"\nselectedModel: gpt-4o-mini\nreasoningEffort: medium\n`; const instance = SessionStartPayload.fromYaml(yaml); const output = instance.toYaml(); const reloaded = SessionStartPayload.fromYaml(output); expect(reloaded.sessionId).toEqual(instance.sessionId); - expect(reloaded.version).toEqual(instance.version); + expect(reloaded.schemaVersion).toEqual(instance.schemaVersion); expect(reloaded.producer).toEqual(instance.producer); expect(reloaded.runtime).toEqual(instance.runtime); expect(reloaded.promptyVersion).toEqual(instance.promptyVersion); diff --git a/schema/model/events/payloads.tsp b/schema/model/events/payloads.tsp index 9a68f801..ae6d5859 100644 --- a/schema/model/events/payloads.tsp +++ b/schema/model/events/payloads.tsp @@ -41,6 +41,19 @@ alias TurnEventType = */ alias TurnStatus = "success" | "error" | "cancelled"; +/** + * Scope where a host lifecycle hook is starting. + */ +alias HookStartScope = "turn" | "session"; + +/** + * Scope where a host lifecycle hook finished. + * + * This intentionally mirrors HookStartScope but remains distinct because some + * language generators emit enum aliases in each model file. + */ +alias HookEndScope = "turn" | "session"; + /** * A canonical event envelope emitted by the turn harness. The payload is kept * JSON-shaped so runtimes can load all events even when newer payload types are @@ -239,6 +252,9 @@ model PermissionCompletedPayload { @doc("Host-specific decision result, such as a durable approval token or denial details") result?: Record; + + @doc("Redaction state for sensitive decision fields") + redaction?: RedactionMetadata; } /** @@ -511,6 +527,9 @@ model HookStartPayload { @sample(#{ hookType: "preToolUse" }) hookType: string; + @doc("Whether the hook is scoped to a turn or the outer session") + scope?: HookStartScope; + @doc("Hook input after host-side sanitization") input?: Record; @@ -530,6 +549,9 @@ model HookEndPayload { @sample(#{ hookType: "preToolUse" }) hookType: string; + @doc("Whether the hook is scoped to a turn or the outer session") + scope?: HookEndScope; + @doc("Whether the hook completed successfully") @sample(#{ success: true }) success: boolean; diff --git a/schema/model/events/session.tsp b/schema/model/events/session.tsp index 37fac077..21d032a6 100644 --- a/schema/model/events/session.tsp +++ b/schema/model/events/session.tsp @@ -58,8 +58,8 @@ model SessionStartPayload { sessionId: string; @doc("Session event schema version") - @sample(#{ version: 1 }) - version?: int32 = 1; + @sample(#{ schemaVersion: "1" }) + schemaVersion?: string = "1"; @doc("Producer that started the session") @sample(#{ producer: "prompty-agent" }) diff --git a/vscode/prompty/schemas/HookEndPayload.yaml b/vscode/prompty/schemas/HookEndPayload.yaml index f68b7242..37b56ecc 100644 --- a/vscode/prompty/schemas/HookEndPayload.yaml +++ b/vscode/prompty/schemas/HookEndPayload.yaml @@ -8,6 +8,13 @@ properties: hookType: type: string description: Host-defined hook type + scope: + anyOf: + - type: string + const: turn + - type: string + const: session + description: Whether the hook is scoped to a turn or the outer session success: type: boolean description: Whether the hook completed successfully diff --git a/vscode/prompty/schemas/HookStartPayload.yaml b/vscode/prompty/schemas/HookStartPayload.yaml index 6505ae59..304cf577 100644 --- a/vscode/prompty/schemas/HookStartPayload.yaml +++ b/vscode/prompty/schemas/HookStartPayload.yaml @@ -8,6 +8,13 @@ properties: hookType: type: string description: Host-defined hook type + scope: + anyOf: + - type: string + const: turn + - type: string + const: session + description: Whether the hook is scoped to a turn or the outer session input: $ref: RecordUnknown.yaml description: Hook input after host-side sanitization diff --git a/vscode/prompty/schemas/PermissionCompletedPayload.yaml b/vscode/prompty/schemas/PermissionCompletedPayload.yaml index d6873573..12938e84 100644 --- a/vscode/prompty/schemas/PermissionCompletedPayload.yaml +++ b/vscode/prompty/schemas/PermissionCompletedPayload.yaml @@ -20,6 +20,9 @@ properties: result: $ref: RecordUnknown.yaml description: Host-specific decision result, such as a durable approval token or denial details + redaction: + $ref: RedactionMetadata.yaml + description: Redaction state for sensitive decision fields required: - permission - approved diff --git a/vscode/prompty/schemas/SessionStartPayload.yaml b/vscode/prompty/schemas/SessionStartPayload.yaml index a12a41ec..75174bf7 100644 --- a/vscode/prompty/schemas/SessionStartPayload.yaml +++ b/vscode/prompty/schemas/SessionStartPayload.yaml @@ -5,11 +5,9 @@ properties: sessionId: type: string description: Stable session identifier - version: - type: integer - minimum: -2147483648 - maximum: 2147483647 - default: 1 + schemaVersion: + type: string + default: "1" description: Session event schema version producer: type: string diff --git a/web/src/content/docs/reference/HookEndPayload.md b/web/src/content/docs/reference/HookEndPayload.md index 6f9a3486..3620a9cc 100644 --- a/web/src/content/docs/reference/HookEndPayload.md +++ b/web/src/content/docs/reference/HookEndPayload.md @@ -21,6 +21,7 @@ classDiagram class HookEndPayload { +string hookInvocationId +string hookType + +string scope +boolean success +dictionary output +float64 durationMs @@ -51,6 +52,7 @@ error: hook failed | ---- | ---- | ----------- | | hookInvocationId | string | Stable hook invocation identifier | | hookType | string | Host-defined hook type | +| scope | string | Whether the hook is scoped to a turn or the outer session | | success | boolean | Whether the hook completed successfully | | output | dictionary | Hook output after host-side sanitization | | durationMs | float64 | Hook execution duration in milliseconds | diff --git a/web/src/content/docs/reference/HookStartPayload.md b/web/src/content/docs/reference/HookStartPayload.md index 9d72d5e7..f29b4a4d 100644 --- a/web/src/content/docs/reference/HookStartPayload.md +++ b/web/src/content/docs/reference/HookStartPayload.md @@ -21,6 +21,7 @@ classDiagram class HookStartPayload { +string hookInvocationId +string hookType + +string scope +dictionary input +RedactionMetadata redaction } @@ -45,6 +46,7 @@ hookType: preToolUse | ---- | ---- | ----------- | | hookInvocationId | string | Stable hook invocation identifier | | hookType | string | Host-defined hook type | +| scope | string | Whether the hook is scoped to a turn or the outer session | | input | dictionary | Hook input after host-side sanitization | | redaction | [RedactionMetadata](../redactionmetadata/) | Redaction state for sensitive hook input fields | diff --git a/web/src/content/docs/reference/PermissionCompletedPayload.md b/web/src/content/docs/reference/PermissionCompletedPayload.md index be33b442..5af3768d 100644 --- a/web/src/content/docs/reference/PermissionCompletedPayload.md +++ b/web/src/content/docs/reference/PermissionCompletedPayload.md @@ -25,7 +25,14 @@ classDiagram +boolean approved +string reason +dictionary result + +RedactionMetadata redaction } + class RedactionMetadata { + +boolean sanitized + +RedactedField[] fields + +string policy + } + PermissionCompletedPayload *-- RedactionMetadata ``` ## Yaml Example @@ -48,3 +55,10 @@ reason: user_approved | approved | boolean | Whether the requested permission was approved | | reason | string | Decision reason, if available | | result | dictionary | Host-specific decision result, such as a durable approval token or denial details | +| redaction | [RedactionMetadata](../redactionmetadata/) | Redaction state for sensitive decision fields | + +## Composed Types + +The following types are composed within `PermissionCompletedPayload`: + +- [RedactionMetadata](../redactionmetadata/) diff --git a/web/src/content/docs/reference/SessionStartPayload.md b/web/src/content/docs/reference/SessionStartPayload.md index cda9b85b..daf312f5 100644 --- a/web/src/content/docs/reference/SessionStartPayload.md +++ b/web/src/content/docs/reference/SessionStartPayload.md @@ -20,7 +20,7 @@ config: classDiagram class SessionStartPayload { +string sessionId - +int32 version + +string schemaVersion +string producer +string runtime +string promptyVersion @@ -41,7 +41,7 @@ classDiagram ```yaml sessionId: sess_abc123 -version: 1 +schemaVersion: "1" producer: prompty-agent runtime: typescript promptyVersion: 2.0.0 @@ -55,7 +55,7 @@ reasoningEffort: medium | Name | Type | Description | | ---- | ---- | ----------- | | sessionId | string | Stable session identifier | -| version | int32 | Session event schema version | +| schemaVersion | string | Session event schema version | | producer | string | Producer that started the session | | runtime | string | Runtime that produced the session | | promptyVersion | string | Prompty library version | From fd939311b49ce33cc2499519ef9421a2d93ee552 Mon Sep 17 00:00:00 2001 From: Seth Juarez Date: Wed, 10 Jun 2026 11:44:59 -0700 Subject: [PATCH 04/22] Add runtime harness adapters Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../HarnessAdaptersTests.cs | 182 ++++++++++ .../csharp/Prompty.Core/HarnessAdapters.cs | 272 +++++++++++++++ runtime/go/prompty/model/harness_adapters.go | 239 +++++++++++++ .../go/prompty/model/harness_adapters_test.go | 240 +++++++++++++ runtime/python/prompty/prompty/__init__.py | 14 + .../prompty/prompty/harness/__init__.py | 19 ++ .../prompty/prompty/harness/adapters.py | 183 ++++++++++ .../prompty/tests/test_harness_adapters.py | 136 ++++++++ runtime/rust/prompty/src/harness.rs | 321 ++++++++++++++++++ runtime/rust/prompty/src/lib.rs | 5 + .../rust/prompty/tests/harness_adapters.rs | 281 +++++++++++++++ .../packages/core/src/harness/adapters.ts | 180 ++++++++++ .../packages/core/src/harness/index.ts | 8 + runtime/typescript/packages/core/src/index.ts | 26 ++ .../core/tests/harness/adapters.test.ts | 164 +++++++++ 15 files changed, 2270 insertions(+) create mode 100644 runtime/csharp/Prompty.Core.Tests/HarnessAdaptersTests.cs create mode 100644 runtime/csharp/Prompty.Core/HarnessAdapters.cs create mode 100644 runtime/go/prompty/model/harness_adapters.go create mode 100644 runtime/go/prompty/model/harness_adapters_test.go create mode 100644 runtime/python/prompty/prompty/harness/__init__.py create mode 100644 runtime/python/prompty/prompty/harness/adapters.py create mode 100644 runtime/python/prompty/tests/test_harness_adapters.py create mode 100644 runtime/rust/prompty/src/harness.rs create mode 100644 runtime/rust/prompty/tests/harness_adapters.rs create mode 100644 runtime/typescript/packages/core/src/harness/adapters.ts create mode 100644 runtime/typescript/packages/core/src/harness/index.ts create mode 100644 runtime/typescript/packages/core/tests/harness/adapters.test.ts diff --git a/runtime/csharp/Prompty.Core.Tests/HarnessAdaptersTests.cs b/runtime/csharp/Prompty.Core.Tests/HarnessAdaptersTests.cs new file mode 100644 index 00000000..6f334ef4 --- /dev/null +++ b/runtime/csharp/Prompty.Core.Tests/HarnessAdaptersTests.cs @@ -0,0 +1,182 @@ +// Copyright (c) Microsoft. All rights reserved. + +using System.Text.Json; +using Prompty.Core; + +namespace Prompty.Core.Tests; + +public class HarnessAdaptersTests +{ + [Fact] + public void CollectingEventSink_CapturesEvents() + { + var sink = new CollectingEventSink(); + + Assert.True(sink.EmitTurn(TurnEvent())); + Assert.True(sink.EmitSession(SessionEvent())); + + Assert.Equal("turn-event", sink.TurnEvents.Single().Id); + Assert.Equal("session-event", sink.SessionEvents.Single().Id); + } + + [Fact] + public void JsonlTraceWriter_WritesRecords() + { + var directory = Directory.CreateTempSubdirectory("prompty-trace-"); + try + { + var path = Path.Combine(directory.FullName, "trace.jsonl"); + var writer = new JsonlTraceWriter(path); + + writer.AppendTurn(TurnEvent()); + writer.AppendSession(SessionEvent()); + writer.Close(new SessionSummary { SessionId = "session-1", Turns = 1 }); + + var lines = File.ReadAllLines(path) + .Select(line => JsonSerializer.Deserialize>(line)!) + .ToList(); + + Assert.Equal(new[] { "turn", "session", "summary" }, lines.Select(line => line["kind"].GetString()).ToArray()); + Assert.Equal("turn-event", lines[0]["event"].GetProperty("id").GetString()); + Assert.Equal("session-event", lines[1]["event"].GetProperty("id").GetString()); + Assert.Equal("session-1", lines[2]["summary"].GetProperty("sessionId").GetString()); + Assert.DoesNotContain("\r\n", File.ReadAllText(path)); + } + finally + { + directory.Delete(recursive: true); + } + } + + [Fact] + public void JsonlTraceWriter_ReturnsFalseAfterClose() + { + var directory = Directory.CreateTempSubdirectory("prompty-trace-"); + try + { + var writer = new JsonlTraceWriter(Path.Combine(directory.FullName, "trace.jsonl")); + + Assert.True(writer.Close(null)); + Assert.False(writer.AppendTurn(TurnEvent())); + } + finally + { + directory.Delete(recursive: true); + } + } + + [Fact] + public async Task InMemoryCheckpointStore_StoresCheckpoints() + { + var store = new InMemoryCheckpointStore(); + var checkpoint = new Checkpoint { Id = "checkpoint-1", SessionId = "session-1", Title = "First" }; + + Assert.Same(checkpoint, await store.SaveAsync(checkpoint)); + Assert.Same(checkpoint, await store.LoadAsync("session-1", "checkpoint-1")); + Assert.Null(await store.LoadAsync("session-1", "missing")); + Assert.Equal([checkpoint], await store.ListCheckpointsAsync("session-1")); + } + + [Fact] + public async Task InMemoryCheckpointStore_RequiresKeys() + { + var store = new InMemoryCheckpointStore(); + + await Assert.ThrowsAsync(() => + store.SaveAsync(new Checkpoint { Id = "checkpoint-1", Title = "Missing session" })); + await Assert.ThrowsAsync(() => + store.SaveAsync(new Checkpoint { SessionId = "session-1", Title = "Missing id" })); + } + + [Fact] + public async Task PermissionResolvers_ReturnDecisions() + { + var request = new PermissionRequest + { + RequestId = "permission-1", + ToolCallId = "tool-call-1", + Permission = "tool.execute" + }; + + var allow = await new AllowAllPermissionResolver().RequestAsync(request); + var deny = await new DenyAllPermissionResolver().RequestAsync(request); + + Assert.True(allow.Approved); + Assert.Equal("allow_all", allow.Reason); + Assert.Equal("permission-1", allow.RequestId); + Assert.Equal("tool-call-1", allow.ToolCallId); + Assert.False(deny.Approved); + Assert.Equal("deny_all", deny.Reason); + } + + [Fact] + public async Task FunctionHostToolExecutor_ExecutesRegisteredHandlers() + { + var executor = new FunctionHostToolExecutor(new Dictionary + { + ["add"] = (args, _) => Task.FromResult(Convert.ToInt32(args!["a"]) + Convert.ToInt32(args["b"])) + }); + + var result = await executor.ExecuteAsync(new HostToolRequest + { + RequestId = "exec-1", + ToolName = "add", + Arguments = new Dictionary { ["a"] = 2, ["b"] = 3 } + }); + + Assert.True(result.Success); + Assert.Equal("exec-1", result.RequestId); + Assert.Equal("add", result.ToolName); + Assert.Equal(5, result.Result); + } + + [Fact] + public async Task FunctionHostToolExecutor_PassesEmptyArguments() + { + var executor = new FunctionHostToolExecutor(new Dictionary + { + ["count"] = (args, _) => Task.FromResult(args.Count) + }); + + var result = await executor.ExecuteAsync(new HostToolRequest { ToolName = "count" }); + + Assert.True(result.Success); + Assert.Equal(0, result.Result); + } + + [Fact] + public async Task FunctionHostToolExecutor_ReturnsFailureResults() + { + var executor = new FunctionHostToolExecutor(new Dictionary + { + ["fail"] = (_, _) => throw new InvalidOperationException("boom") + }); + + var missing = await executor.ExecuteAsync(new HostToolRequest { ToolName = "missing" }); + var thrown = await executor.ExecuteAsync(new HostToolRequest { ToolName = "fail" }); + + Assert.False(missing.Success); + Assert.Equal("not_found", missing.ErrorKind); + Assert.False(thrown.Success); + Assert.Equal("exception", thrown.ErrorKind); + var result = Assert.IsType>(thrown.Result); + Assert.Equal("boom", result["message"]); + } + + private static TurnEvent TurnEvent() => new() + { + Id = "turn-event", + Type = TurnEventType.TurnStart, + Timestamp = "2026-06-10T00:00:00Z", + Payload = new Dictionary { ["phase"] = "start" } + }; + + private static SessionEvent SessionEvent() => new() + { + Id = "session-event", + Type = SessionEventType.SessionStart, + Timestamp = "2026-06-10T00:00:00Z", + SessionId = "session-1", + Payload = new Dictionary { ["phase"] = "start" } + }; +} diff --git a/runtime/csharp/Prompty.Core/HarnessAdapters.cs b/runtime/csharp/Prompty.Core/HarnessAdapters.cs new file mode 100644 index 00000000..68c673b7 --- /dev/null +++ b/runtime/csharp/Prompty.Core/HarnessAdapters.cs @@ -0,0 +1,272 @@ +// Copyright (c) Microsoft. All rights reserved. + +using System.Diagnostics; +using System.Text.Json; + +namespace Prompty.Core; + +/// +/// Captures emitted turn and session events in memory. +/// +public sealed class CollectingEventSink : IEventSink +{ + private readonly object _lock = new(); + private readonly List _turnEvents = []; + private readonly List _sessionEvents = []; + + public List TurnEvents + { + get + { + lock (_lock) + { + return [.. _turnEvents]; + } + } + } + + public List SessionEvents + { + get + { + lock (_lock) + { + return [.. _sessionEvents]; + } + } + } + + public bool EmitTurn(TurnEvent turnEvent) + { + lock (_lock) + { + _turnEvents.Add(turnEvent); + } + return true; + } + + public bool EmitSession(SessionEvent sessionEvent) + { + lock (_lock) + { + _sessionEvents.Add(sessionEvent); + } + return true; + } +} + +/// +/// Appends replayable trace records as newline-delimited JSON. +/// +public sealed class JsonlTraceWriter : ITraceWriter +{ + private readonly object _lock = new(); + private readonly string _path; + private bool _closed; + + public JsonlTraceWriter(string path) + { + _path = path; + var directory = Path.GetDirectoryName(path); + if (!string.IsNullOrEmpty(directory)) + { + Directory.CreateDirectory(directory); + } + } + + public bool AppendTurn(TurnEvent turnEvent) + { + return Write(new Dictionary + { + ["kind"] = "turn", + ["event"] = turnEvent.Save() + }); + } + + public bool AppendSession(SessionEvent sessionEvent) + { + return Write(new Dictionary + { + ["kind"] = "session", + ["event"] = sessionEvent.Save() + }); + } + + public bool Close(SessionSummary? summary) + { + if (summary is not null) + { + if (!Write(new Dictionary + { + ["kind"] = "summary", + ["summary"] = summary.Save() + })) + { + return false; + } + } + _closed = true; + return true; + } + + private bool Write(Dictionary record) + { + lock (_lock) + { + if (_closed) + { + return false; + } + File.AppendAllText(_path, JsonSerializer.Serialize(record) + "\n"); + return true; + } + } +} + +/// +/// Stores checkpoints in memory by session and checkpoint identifier. +/// +public sealed class InMemoryCheckpointStore : ICheckpointStore +{ + private readonly object _lock = new(); + private readonly Dictionary<(string SessionId, string CheckpointId), Checkpoint> _checkpoints = []; + + public Task SaveAsync(Checkpoint checkpoint) + { + var key = RequireCheckpointKey(checkpoint); + lock (_lock) + { + _checkpoints[key] = checkpoint; + } + return Task.FromResult(checkpoint); + } + + public Task LoadAsync(string sessionId, string checkpointId) + { + Checkpoint? checkpoint; + lock (_lock) + { + _checkpoints.TryGetValue((sessionId, checkpointId), out checkpoint); + } + return Task.FromResult(checkpoint); + } + + public Task> ListCheckpointsAsync(string sessionId) + { + List checkpoints; + lock (_lock) + { + checkpoints = _checkpoints.Values.Where(checkpoint => checkpoint.SessionId == sessionId).ToList(); + } + return Task.FromResult(checkpoints); + } + + private static (string SessionId, string CheckpointId) RequireCheckpointKey(Checkpoint checkpoint) + { + if (string.IsNullOrEmpty(checkpoint.SessionId)) + { + throw new ArgumentException("Checkpoint SessionId is required", nameof(checkpoint)); + } + if (string.IsNullOrEmpty(checkpoint.Id)) + { + throw new ArgumentException("Checkpoint Id is required", nameof(checkpoint)); + } + return (checkpoint.SessionId, checkpoint.Id); + } +} + +/// +/// Resolves every permission request as approved. +/// +public sealed class AllowAllPermissionResolver : IPermissionResolver +{ + public Task RequestAsync(PermissionRequest request) + { + return Task.FromResult(new PermissionDecision + { + RequestId = request.RequestId, + ToolCallId = request.ToolCallId, + Permission = request.Permission, + Approved = true, + Reason = "allow_all" + }); + } +} + +/// +/// Resolves every permission request as denied. +/// +public sealed class DenyAllPermissionResolver : IPermissionResolver +{ + public Task RequestAsync(PermissionRequest request) + { + return Task.FromResult(new PermissionDecision + { + RequestId = request.RequestId, + ToolCallId = request.ToolCallId, + Permission = request.Permission, + Approved = false, + Reason = "deny_all" + }); + } +} + +public delegate Task HostToolHandler(IDictionary arguments, HostToolRequest request); + +/// +/// Dispatches host tool requests to registered local functions. +/// +public sealed class FunctionHostToolExecutor : IHostToolExecutor +{ + private readonly IReadOnlyDictionary _handlers; + + public FunctionHostToolExecutor(IReadOnlyDictionary handlers) + { + _handlers = handlers; + } + + public async Task ExecuteAsync(HostToolRequest request) + { + var stopwatch = Stopwatch.StartNew(); + if (!_handlers.TryGetValue(request.ToolName, out var handler)) + { + return new HostToolResult + { + RequestId = request.RequestId, + ToolCallId = request.ToolCallId, + ToolName = request.ToolName, + Success = false, + ErrorKind = "not_found", + Result = new Dictionary { ["message"] = $"No host tool registered for '{request.ToolName}'" }, + DurationMs = stopwatch.Elapsed.TotalMilliseconds + }; + } + + try + { + var result = await handler(request.Arguments ?? new Dictionary(), request); + return new HostToolResult + { + RequestId = request.RequestId, + ToolCallId = request.ToolCallId, + ToolName = request.ToolName, + Success = true, + Result = result, + DurationMs = stopwatch.Elapsed.TotalMilliseconds + }; + } + catch (Exception exception) + { + return new HostToolResult + { + RequestId = request.RequestId, + ToolCallId = request.ToolCallId, + ToolName = request.ToolName, + Success = false, + ErrorKind = "exception", + Result = new Dictionary { ["message"] = exception.Message }, + DurationMs = stopwatch.Elapsed.TotalMilliseconds + }; + } + } +} diff --git a/runtime/go/prompty/model/harness_adapters.go b/runtime/go/prompty/model/harness_adapters.go new file mode 100644 index 00000000..75775594 --- /dev/null +++ b/runtime/go/prompty/model/harness_adapters.go @@ -0,0 +1,239 @@ +package prompty + +import ( + "encoding/json" + "fmt" + "os" + "path/filepath" + "sort" + "sync" + "time" +) + +// CollectingEventSink captures emitted turn and session events in memory. +type CollectingEventSink struct { + mu sync.Mutex + TurnEvents []TurnEvent + SessionEvents []SessionEvent +} + +func (s *CollectingEventSink) EmitTurn(turnEvent TurnEvent) (bool, error) { + s.mu.Lock() + defer s.mu.Unlock() + s.TurnEvents = append(s.TurnEvents, turnEvent) + return true, nil +} + +func (s *CollectingEventSink) EmitSession(sessionEvent SessionEvent) (bool, error) { + s.mu.Lock() + defer s.mu.Unlock() + s.SessionEvents = append(s.SessionEvents, sessionEvent) + return true, nil +} + +// JsonlTraceWriter appends replayable trace records as newline-delimited JSON. +type JsonlTraceWriter struct { + mu sync.Mutex + Path string + closed bool +} + +func NewJsonlTraceWriter(path string) (*JsonlTraceWriter, error) { + if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { + return nil, err + } + return &JsonlTraceWriter{Path: path}, nil +} + +func (w *JsonlTraceWriter) AppendTurn(turnEvent TurnEvent) (bool, error) { + return w.write(map[string]interface{}{"kind": "turn", "event": turnEvent.Save(NewSaveContext())}) +} + +func (w *JsonlTraceWriter) AppendSession(sessionEvent SessionEvent) (bool, error) { + return w.write(map[string]interface{}{"kind": "session", "event": sessionEvent.Save(NewSaveContext())}) +} + +func (w *JsonlTraceWriter) Close(summary *SessionSummary) (bool, error) { + if summary != nil { + if ok, err := w.write(map[string]interface{}{"kind": "summary", "summary": summary.Save(NewSaveContext())}); !ok || err != nil { + return ok, err + } + } + w.mu.Lock() + w.closed = true + w.mu.Unlock() + return true, nil +} + +func (w *JsonlTraceWriter) write(record map[string]interface{}) (bool, error) { + w.mu.Lock() + defer w.mu.Unlock() + if w.closed { + return false, fmt.Errorf("trace writer is closed") + } + file, err := os.OpenFile(w.Path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0o644) + if err != nil { + return false, err + } + defer file.Close() + bytes, err := json.Marshal(record) + if err != nil { + return false, err + } + if _, err := file.Write(append(bytes, '\n')); err != nil { + return false, err + } + return true, nil +} + +// InMemoryCheckpointStore stores checkpoints by session and checkpoint identifier. +type InMemoryCheckpointStore struct { + mu sync.Mutex + checkpoints map[string]Checkpoint +} + +func NewInMemoryCheckpointStore() *InMemoryCheckpointStore { + return &InMemoryCheckpointStore{checkpoints: map[string]Checkpoint{}} +} + +func (s *InMemoryCheckpointStore) Save(checkpoint Checkpoint) (Checkpoint, error) { + key, err := requireCheckpointKey(checkpoint) + if err != nil { + return Checkpoint{}, err + } + s.mu.Lock() + defer s.mu.Unlock() + s.checkpoints[key] = checkpoint + return checkpoint, nil +} + +func (s *InMemoryCheckpointStore) Load(sessionId string, checkpointId string) (*Checkpoint, error) { + s.mu.Lock() + defer s.mu.Unlock() + checkpoint, ok := s.checkpoints[checkpointKey(sessionId, checkpointId)] + if !ok { + return nil, nil + } + return &checkpoint, nil +} + +func (s *InMemoryCheckpointStore) ListCheckpoints(sessionId string) ([]Checkpoint, error) { + s.mu.Lock() + defer s.mu.Unlock() + checkpoints := []Checkpoint{} + for _, checkpoint := range s.checkpoints { + if checkpoint.SessionId != nil && *checkpoint.SessionId == sessionId { + checkpoints = append(checkpoints, checkpoint) + } + } + sort.Slice(checkpoints, func(i int, j int) bool { + left := "" + right := "" + if checkpoints[i].Id != nil { + left = *checkpoints[i].Id + } + if checkpoints[j].Id != nil { + right = *checkpoints[j].Id + } + return left < right + }) + return checkpoints, nil +} + +func checkpointKey(sessionId string, checkpointId string) string { + return sessionId + "\x00" + checkpointId +} + +func requireCheckpointKey(checkpoint Checkpoint) (string, error) { + if checkpoint.SessionId == nil || *checkpoint.SessionId == "" { + return "", fmt.Errorf("checkpoint sessionId is required") + } + if checkpoint.Id == nil || *checkpoint.Id == "" { + return "", fmt.Errorf("checkpoint id is required") + } + return checkpointKey(*checkpoint.SessionId, *checkpoint.Id), nil +} + +// AllowAllPermissionResolver resolves every permission request as approved. +type AllowAllPermissionResolver struct{} + +func (r AllowAllPermissionResolver) Request(request PermissionRequest) (PermissionDecision, error) { + reason := "allow_all" + return PermissionDecision{ + RequestId: request.RequestId, + ToolCallId: request.ToolCallId, + Permission: request.Permission, + Approved: true, + Reason: &reason, + }, nil +} + +// DenyAllPermissionResolver resolves every permission request as denied. +type DenyAllPermissionResolver struct{} + +func (r DenyAllPermissionResolver) Request(request PermissionRequest) (PermissionDecision, error) { + reason := "deny_all" + return PermissionDecision{ + RequestId: request.RequestId, + ToolCallId: request.ToolCallId, + Permission: request.Permission, + Approved: false, + Reason: &reason, + }, nil +} + +type HostToolHandler func(arguments map[string]interface{}, request HostToolRequest) (interface{}, error) + +// FunctionHostToolExecutor dispatches host tool requests to registered functions. +type FunctionHostToolExecutor struct { + Handlers map[string]HostToolHandler +} + +func (e FunctionHostToolExecutor) Execute(request HostToolRequest) (HostToolResult, error) { + started := time.Now() + handler, ok := e.Handlers[request.ToolName] + if !ok { + errorKind := "not_found" + result := interface{}(map[string]interface{}{"message": fmt.Sprintf("No host tool registered for '%s'", request.ToolName)}) + durationMs := float64(time.Since(started).Microseconds()) / 1000 + return HostToolResult{ + RequestId: request.RequestId, + ToolCallId: request.ToolCallId, + ToolName: request.ToolName, + Success: false, + Result: &result, + DurationMs: &durationMs, + ErrorKind: &errorKind, + }, nil + } + + arguments := request.Arguments + if arguments == nil { + arguments = map[string]interface{}{} + } + result, err := handler(arguments, request) + durationMs := float64(time.Since(started).Microseconds()) / 1000 + if err != nil { + errorKind := "exception" + errorResult := interface{}(map[string]interface{}{"message": err.Error()}) + return HostToolResult{ + RequestId: request.RequestId, + ToolCallId: request.ToolCallId, + ToolName: request.ToolName, + Success: false, + Result: &errorResult, + DurationMs: &durationMs, + ErrorKind: &errorKind, + }, nil + } + + resultValue := interface{}(result) + return HostToolResult{ + RequestId: request.RequestId, + ToolCallId: request.ToolCallId, + ToolName: request.ToolName, + Success: true, + Result: &resultValue, + DurationMs: &durationMs, + }, nil +} diff --git a/runtime/go/prompty/model/harness_adapters_test.go b/runtime/go/prompty/model/harness_adapters_test.go new file mode 100644 index 00000000..bcc949bb --- /dev/null +++ b/runtime/go/prompty/model/harness_adapters_test.go @@ -0,0 +1,240 @@ +package prompty + +import ( + "encoding/json" + "fmt" + "os" + "path/filepath" + "strings" + "testing" +) + +func testTurnEvent() TurnEvent { + return TurnEvent{ + Id: "turn-event", + Type: TurnEventTypeTurnStart, + Timestamp: "2026-06-10T00:00:00Z", + Payload: map[string]interface{}{"phase": "start"}, + } +} + +func testSessionEvent() SessionEvent { + sessionId := "session-1" + return SessionEvent{ + Id: "session-event", + Type: SessionEventTypeSessionStart, + Timestamp: "2026-06-10T00:00:00Z", + SessionId: &sessionId, + Payload: map[string]interface{}{"phase": "start"}, + } +} + +func TestCollectingEventSink(t *testing.T) { + sink := &CollectingEventSink{} + + if ok, err := sink.EmitTurn(testTurnEvent()); !ok || err != nil { + t.Fatalf("EmitTurn failed: %v", err) + } + if ok, err := sink.EmitSession(testSessionEvent()); !ok || err != nil { + t.Fatalf("EmitSession failed: %v", err) + } + if sink.TurnEvents[0].Id != "turn-event" { + t.Fatalf("unexpected turn event: %#v", sink.TurnEvents[0]) + } + if sink.SessionEvents[0].Id != "session-event" { + t.Fatalf("unexpected session event: %#v", sink.SessionEvents[0]) + } +} + +func TestJsonlTraceWriter(t *testing.T) { + path := filepath.Join(t.TempDir(), "trace.jsonl") + writer, err := NewJsonlTraceWriter(path) + if err != nil { + t.Fatal(err) + } + + if ok, err := writer.AppendTurn(testTurnEvent()); !ok || err != nil { + t.Fatalf("AppendTurn failed: %v", err) + } + if ok, err := writer.AppendSession(testSessionEvent()); !ok || err != nil { + t.Fatalf("AppendSession failed: %v", err) + } + if ok, err := writer.Close(&SessionSummary{SessionId: "session-1"}); !ok || err != nil { + t.Fatalf("Close failed: %v", err) + } + + content, err := os.ReadFile(path) + if err != nil { + t.Fatal(err) + } + lines := splitLines(string(content)) + if len(lines) != 3 { + t.Fatalf("expected 3 lines, got %d", len(lines)) + } + var records []map[string]interface{} + for _, line := range lines { + var record map[string]interface{} + if err := json.Unmarshal([]byte(line), &record); err != nil { + t.Fatal(err) + } + records = append(records, record) + } + if records[0]["kind"] != "turn" || records[1]["kind"] != "session" || records[2]["kind"] != "summary" { + t.Fatalf("unexpected record kinds: %#v", records) + } +} + +func TestJsonlTraceWriterAfterClose(t *testing.T) { + path := filepath.Join(t.TempDir(), "trace.jsonl") + writer, err := NewJsonlTraceWriter(path) + if err != nil { + t.Fatal(err) + } + + if ok, err := writer.Close(nil); !ok || err != nil { + t.Fatalf("Close failed: %v", err) + } + if ok, err := writer.AppendTurn(testTurnEvent()); ok || err == nil { + t.Fatalf("expected closed writer failure, ok=%v err=%v", ok, err) + } +} + +func TestInMemoryCheckpointStore(t *testing.T) { + store := NewInMemoryCheckpointStore() + sessionId := "session-1" + checkpointId := "checkpoint-1" + checkpoint := Checkpoint{Id: &checkpointId, SessionId: &sessionId, Title: "First"} + + saved, err := store.Save(checkpoint) + if err != nil { + t.Fatal(err) + } + if saved.Title != "First" { + t.Fatalf("unexpected checkpoint: %#v", saved) + } + loaded, err := store.Load("session-1", "checkpoint-1") + if err != nil { + t.Fatal(err) + } + if loaded == nil || loaded.Title != "First" { + t.Fatalf("unexpected loaded checkpoint: %#v", loaded) + } + missing, err := store.Load("session-1", "missing") + if err != nil { + t.Fatal(err) + } + if missing != nil { + t.Fatalf("expected nil missing checkpoint, got %#v", missing) + } + listed, err := store.ListCheckpoints("session-1") + if err != nil { + t.Fatal(err) + } + if len(listed) != 1 { + t.Fatalf("expected one checkpoint, got %d", len(listed)) + } +} + +func TestInMemoryCheckpointStoreRequiresKeys(t *testing.T) { + store := NewInMemoryCheckpointStore() + checkpointId := "checkpoint-1" + sessionId := "session-1" + + if _, err := store.Save(Checkpoint{Id: &checkpointId}); err == nil { + t.Fatal("expected missing sessionId error") + } + if _, err := store.Save(Checkpoint{SessionId: &sessionId}); err == nil { + t.Fatal("expected missing id error") + } +} + +func TestPermissionResolvers(t *testing.T) { + requestId := "permission-1" + toolCallId := "tool-call-1" + request := PermissionRequest{RequestId: &requestId, ToolCallId: &toolCallId, Permission: "tool.execute"} + + allow, err := AllowAllPermissionResolver{}.Request(request) + if err != nil { + t.Fatal(err) + } + deny, err := DenyAllPermissionResolver{}.Request(request) + if err != nil { + t.Fatal(err) + } + if !allow.Approved || *allow.Reason != "allow_all" || *allow.RequestId != "permission-1" { + t.Fatalf("unexpected allow decision: %#v", allow) + } + if deny.Approved || *deny.Reason != "deny_all" { + t.Fatalf("unexpected deny decision: %#v", deny) + } +} + +func TestFunctionHostToolExecutor(t *testing.T) { + requestId := "exec-1" + executor := FunctionHostToolExecutor{Handlers: map[string]HostToolHandler{ + "add": func(arguments map[string]interface{}, request HostToolRequest) (interface{}, error) { + return int(arguments["a"].(int)) + int(arguments["b"].(int)), nil + }, + }} + + result, err := executor.Execute(HostToolRequest{ + RequestId: &requestId, + ToolName: "add", + Arguments: map[string]interface{}{"a": 2, "b": 3}, + }) + if err != nil { + t.Fatal(err) + } + if !result.Success || *result.Result != 5 { + t.Fatalf("unexpected success result: %#v", result) + } +} + +func TestFunctionHostToolExecutorEmptyArguments(t *testing.T) { + executor := FunctionHostToolExecutor{Handlers: map[string]HostToolHandler{ + "count": func(arguments map[string]interface{}, request HostToolRequest) (interface{}, error) { + return len(arguments), nil + }, + }} + + result, err := executor.Execute(HostToolRequest{ToolName: "count"}) + if err != nil { + t.Fatal(err) + } + if !result.Success || *result.Result != 0 { + t.Fatalf("unexpected success result: %#v", result) + } +} + +func TestFunctionHostToolExecutorFailures(t *testing.T) { + executor := FunctionHostToolExecutor{Handlers: map[string]HostToolHandler{ + "fail": func(arguments map[string]interface{}, request HostToolRequest) (interface{}, error) { + return nil, fmt.Errorf("boom") + }, + }} + + missing, err := executor.Execute(HostToolRequest{ToolName: "missing"}) + if err != nil { + t.Fatal(err) + } + thrown, err := executor.Execute(HostToolRequest{ToolName: "fail"}) + if err != nil { + t.Fatal(err) + } + if missing.Success || *missing.ErrorKind != "not_found" { + t.Fatalf("unexpected missing result: %#v", missing) + } + if thrown.Success || *thrown.ErrorKind != "exception" { + t.Fatalf("unexpected thrown result: %#v", thrown) + } +} + +func splitLines(content string) []string { + var lines []string + for _, line := range strings.Split(content, "\n") { + if line != "" { + lines = append(lines, line) + } + } + return lines +} diff --git a/runtime/python/prompty/prompty/__init__.py b/runtime/python/prompty/prompty/__init__.py index b87df1b9..5f59b6a8 100644 --- a/runtime/python/prompty/prompty/__init__.py +++ b/runtime/python/prompty/prompty/__init__.py @@ -110,6 +110,12 @@ "GuardrailError", "GuardrailResult", "Guardrails", + "AllowAllPermissionResolver", + "CollectingEventSink", + "DenyAllPermissionResolver", + "FunctionHostToolExecutor", + "InMemoryCheckpointStore", + "JsonlTraceWriter", "Steering", "StructuredResult", "cast", @@ -132,6 +138,14 @@ from .core.connections import clear_connections, get_connection, register_connection from .core.context import estimate_chars, format_dropped_messages, summarize_dropped, trim_to_context_window from .core.guardrails import GuardrailError, GuardrailResult, Guardrails +from .harness import ( + AllowAllPermissionResolver, + CollectingEventSink, + DenyAllPermissionResolver, + FunctionHostToolExecutor, + InMemoryCheckpointStore, + JsonlTraceWriter, +) # Loader from .core.loader import load, load_async diff --git a/runtime/python/prompty/prompty/harness/__init__.py b/runtime/python/prompty/prompty/harness/__init__.py new file mode 100644 index 00000000..143727e8 --- /dev/null +++ b/runtime/python/prompty/prompty/harness/__init__.py @@ -0,0 +1,19 @@ +"""Provide reference harness adapters for event, trace, permission, and tool protocols.""" + +from .adapters import ( + AllowAllPermissionResolver, + CollectingEventSink, + DenyAllPermissionResolver, + FunctionHostToolExecutor, + InMemoryCheckpointStore, + JsonlTraceWriter, +) + +__all__ = [ + "AllowAllPermissionResolver", + "CollectingEventSink", + "DenyAllPermissionResolver", + "FunctionHostToolExecutor", + "InMemoryCheckpointStore", + "JsonlTraceWriter", +] diff --git a/runtime/python/prompty/prompty/harness/adapters.py b/runtime/python/prompty/prompty/harness/adapters.py new file mode 100644 index 00000000..54d6bc3f --- /dev/null +++ b/runtime/python/prompty/prompty/harness/adapters.py @@ -0,0 +1,183 @@ +"""Implement dependency-free reference adapters for harness protocols.""" + +from __future__ import annotations + +import inspect +import json +from collections.abc import Awaitable, Callable +from pathlib import Path +from time import perf_counter +from typing import Any + +from ..model import ( + Checkpoint, + HostToolRequest, + HostToolResult, + PermissionDecision, + PermissionRequest, + SessionEvent, + SessionSummary, + TurnEvent, +) + +ToolHandler = Callable[[dict[str, Any], HostToolRequest], Any | Awaitable[Any]] + + +def _checkpoint_key(session_id: str, checkpoint_id: str) -> tuple[str, str]: + return (session_id, checkpoint_id) + + +def _require_checkpoint_key(checkpoint: Checkpoint) -> tuple[str, str]: + if not checkpoint.session_id: + raise ValueError("Checkpoint session_id is required") + if not checkpoint.id: + raise ValueError("Checkpoint id is required") + return _checkpoint_key(checkpoint.session_id, checkpoint.id) + + +def _error_message(error: BaseException) -> str: + return str(error) + + +class CollectingEventSink: + """Capture emitted turn and session events in memory.""" + + def __init__(self) -> None: + self.turn_events: list[TurnEvent] = [] + self.session_events: list[SessionEvent] = [] + + def emit_turn(self, turn_event: TurnEvent) -> bool: + """Append a turn event.""" + self.turn_events.append(turn_event) + return True + + def emit_session(self, session_event: SessionEvent) -> bool: + """Append a session event.""" + self.session_events.append(session_event) + return True + + +class JsonlTraceWriter: + """Append replayable trace records as newline-delimited JSON.""" + + def __init__(self, path: str | Path) -> None: + self.path = Path(path) + self.path.parent.mkdir(parents=True, exist_ok=True) + self._closed = False + + def append_turn(self, turn_event: TurnEvent) -> bool: + """Append a turn event record.""" + return self._write({"kind": "turn", "event": turn_event.save()}) + + def append_session(self, session_event: SessionEvent) -> bool: + """Append a session event record.""" + return self._write({"kind": "session", "event": session_event.save()}) + + def close(self, summary: SessionSummary | None) -> bool: + """Append an optional summary and close the writer.""" + if summary is not None: + if not self._write({"kind": "summary", "summary": summary.save()}): + return False + self._closed = True + return True + + def _write(self, record: dict[str, Any]) -> bool: + if self._closed: + return False + with self.path.open("a", encoding="utf-8") as file: + file.write(json.dumps(record, separators=(",", ":"))) + file.write("\n") + return True + + +class InMemoryCheckpointStore: + """Store checkpoints in memory by session and checkpoint identifier.""" + + def __init__(self) -> None: + self._checkpoints: dict[tuple[str, str], Checkpoint] = {} + + async def save(self, checkpoint: Checkpoint) -> Checkpoint: + """Persist a checkpoint in memory.""" + self._checkpoints[_require_checkpoint_key(checkpoint)] = checkpoint + return checkpoint + + async def load(self, session_id: str, checkpoint_id: str) -> Checkpoint | None: + """Load a checkpoint by identifiers.""" + return self._checkpoints.get(_checkpoint_key(session_id, checkpoint_id)) + + async def list_checkpoints(self, session_id: str) -> list[Checkpoint]: + """List checkpoints for a session.""" + return [checkpoint for checkpoint in self._checkpoints.values() if checkpoint.session_id == session_id] + + +class AllowAllPermissionResolver: + """Resolve every permission request as approved.""" + + async def request(self, request: PermissionRequest) -> PermissionDecision: + """Return an approved permission decision.""" + return PermissionDecision( + request_id=request.request_id, + tool_call_id=request.tool_call_id, + permission=request.permission, + approved=True, + reason="allow_all", + ) + + +class DenyAllPermissionResolver: + """Resolve every permission request as denied.""" + + async def request(self, request: PermissionRequest) -> PermissionDecision: + """Return a denied permission decision.""" + return PermissionDecision( + request_id=request.request_id, + tool_call_id=request.tool_call_id, + permission=request.permission, + approved=False, + reason="deny_all", + ) + + +class FunctionHostToolExecutor: + """Dispatch host tool requests to registered local callables.""" + + def __init__(self, handlers: dict[str, ToolHandler]) -> None: + self.handlers = handlers + + async def execute(self, request: HostToolRequest) -> HostToolResult: + """Execute a registered host tool callable.""" + started = perf_counter() + handler = self.handlers.get(request.tool_name) + if handler is None: + return HostToolResult( + request_id=request.request_id, + tool_call_id=request.tool_call_id, + tool_name=request.tool_name, + success=False, + error_kind="not_found", + result={"message": f"No host tool registered for '{request.tool_name}'"}, + duration_ms=(perf_counter() - started) * 1000, + ) + + try: + result = handler(request.arguments or {}, request) + if inspect.isawaitable(result): + result = await result + return HostToolResult( + request_id=request.request_id, + tool_call_id=request.tool_call_id, + tool_name=request.tool_name, + success=True, + result=result, + duration_ms=(perf_counter() - started) * 1000, + ) + except Exception as error: + return HostToolResult( + request_id=request.request_id, + tool_call_id=request.tool_call_id, + tool_name=request.tool_name, + success=False, + error_kind="exception", + result={"message": _error_message(error)}, + duration_ms=(perf_counter() - started) * 1000, + ) diff --git a/runtime/python/prompty/tests/test_harness_adapters.py b/runtime/python/prompty/tests/test_harness_adapters.py new file mode 100644 index 00000000..36d4e2cd --- /dev/null +++ b/runtime/python/prompty/tests/test_harness_adapters.py @@ -0,0 +1,136 @@ +from __future__ import annotations + +import json + +import pytest + +from prompty import ( + AllowAllPermissionResolver, + CollectingEventSink, + DenyAllPermissionResolver, + FunctionHostToolExecutor, + InMemoryCheckpointStore, + JsonlTraceWriter, +) +from prompty.model import Checkpoint, HostToolRequest, PermissionRequest, SessionEvent, SessionSummary, TurnEvent + + +def _turn_event() -> TurnEvent: + return TurnEvent(id="turn-event", type="turn_start", timestamp="2026-06-10T00:00:00Z", payload={"phase": "start"}) + + +def _session_event() -> SessionEvent: + return SessionEvent( + id="session-event", + type="session_start", + timestamp="2026-06-10T00:00:00Z", + session_id="session-1", + payload={"phase": "start"}, + ) + + +def test_collecting_event_sink_captures_events() -> None: + sink = CollectingEventSink() + + assert sink.emit_turn(_turn_event()) is True + assert sink.emit_session(_session_event()) is True + + assert [event.id for event in sink.turn_events] == ["turn-event"] + assert [event.id for event in sink.session_events] == ["session-event"] + + +def test_jsonl_trace_writer_writes_records(tmp_path) -> None: + trace_path = tmp_path / "trace.jsonl" + writer = JsonlTraceWriter(trace_path) + + writer.append_turn(_turn_event()) + writer.append_session(_session_event()) + writer.close(SessionSummary(session_id="session-1", turns=1)) + + lines = [json.loads(line) for line in trace_path.read_text(encoding="utf-8").splitlines()] + assert [line["kind"] for line in lines] == ["turn", "session", "summary"] + assert lines[0]["event"]["id"] == "turn-event" + assert lines[1]["event"]["id"] == "session-event" + assert lines[2]["summary"]["sessionId"] == "session-1" + + +def test_jsonl_trace_writer_returns_false_after_close(tmp_path) -> None: + writer = JsonlTraceWriter(tmp_path / "trace.jsonl") + + assert writer.close(None) is True + assert writer.append_turn(_turn_event()) is False + + +@pytest.mark.asyncio +async def test_in_memory_checkpoint_store() -> None: + store = InMemoryCheckpointStore() + checkpoint = Checkpoint(id="checkpoint-1", session_id="session-1", title="First") + + assert await store.save(checkpoint) is checkpoint + assert await store.load("session-1", "checkpoint-1") is checkpoint + assert await store.load("session-1", "missing") is None + assert await store.list_checkpoints("session-1") == [checkpoint] + + +@pytest.mark.asyncio +async def test_in_memory_checkpoint_store_requires_keys() -> None: + store = InMemoryCheckpointStore() + + with pytest.raises(ValueError, match="session_id"): + await store.save(Checkpoint(id="checkpoint-1", title="Missing session")) + with pytest.raises(ValueError, match="id"): + await store.save(Checkpoint(session_id="session-1", title="Missing id")) + + +@pytest.mark.asyncio +async def test_permission_resolvers() -> None: + request = PermissionRequest(request_id="permission-1", tool_call_id="tool-call-1", permission="tool.execute") + + allow = await AllowAllPermissionResolver().request(request) + deny = await DenyAllPermissionResolver().request(request) + + assert allow.approved is True + assert allow.reason == "allow_all" + assert allow.request_id == "permission-1" + assert allow.tool_call_id == "tool-call-1" + assert deny.approved is False + assert deny.reason == "deny_all" + + +@pytest.mark.asyncio +async def test_function_host_tool_executor_success() -> None: + executor = FunctionHostToolExecutor({"add": lambda args, request: int(args["a"]) + int(args["b"])}) + + result = await executor.execute(HostToolRequest(request_id="exec-1", tool_name="add", arguments={"a": 2, "b": 3})) + + assert result.success is True + assert result.result == 5 + assert result.request_id == "exec-1" + assert result.tool_name == "add" + + +@pytest.mark.asyncio +async def test_function_host_tool_executor_passes_empty_arguments() -> None: + executor = FunctionHostToolExecutor({"count": lambda args, request: len(args)}) + + result = await executor.execute(HostToolRequest(tool_name="count")) + + assert result.success is True + assert result.result == 0 + + +@pytest.mark.asyncio +async def test_function_host_tool_executor_failures() -> None: + def fail(args, request): + raise RuntimeError("boom") + + executor = FunctionHostToolExecutor({"fail": fail}) + + missing = await executor.execute(HostToolRequest(tool_name="missing")) + thrown = await executor.execute(HostToolRequest(tool_name="fail")) + + assert missing.success is False + assert missing.error_kind == "not_found" + assert thrown.success is False + assert thrown.error_kind == "exception" + assert thrown.result == {"message": "boom"} diff --git a/runtime/rust/prompty/src/harness.rs b/runtime/rust/prompty/src/harness.rs new file mode 100644 index 00000000..0e05dd99 --- /dev/null +++ b/runtime/rust/prompty/src/harness.rs @@ -0,0 +1,321 @@ +//! Reference harness adapters for event, trace, permission, checkpoint, and tool protocols. + +use std::collections::HashMap; +use std::error::Error; +use std::fs::{OpenOptions, create_dir_all}; +use std::io::Write; +use std::path::PathBuf; +use std::sync::{Arc, Mutex}; +use std::time::Instant; + +use serde_json::{Value, json}; + +use crate::model::context::SaveContext; +use crate::model::events::{ + checkpoint::Checkpoint, host_tool_request::HostToolRequest, host_tool_result::HostToolResult, + permission_decision::PermissionDecision, permission_request::PermissionRequest, + session_event::SessionEvent, session_summary::SessionSummary, turn_event::TurnEvent, +}; +use crate::model::pipeline::{ + checkpoint_store::CheckpointStore, event_sink::EventSink, host_tool_executor::HostToolExecutor, + permission_resolver::PermissionResolver, trace_writer::TraceWriter, +}; + +type AdapterError = Box; +type ToolHandler = dyn Fn(&Value, &HostToolRequest) -> Result + Send + Sync; + +fn checkpoint_key(session_id: &str, checkpoint_id: &str) -> (String, String) { + (session_id.to_string(), checkpoint_id.to_string()) +} + +fn require_checkpoint_key(checkpoint: &Checkpoint) -> Result<(String, String), AdapterError> { + let session_id = checkpoint.session_id.clone().ok_or_else(|| { + std::io::Error::new( + std::io::ErrorKind::InvalidInput, + "Checkpoint session_id is required", + ) + })?; + let checkpoint_id = checkpoint.id.clone().ok_or_else(|| { + std::io::Error::new( + std::io::ErrorKind::InvalidInput, + "Checkpoint id is required", + ) + })?; + Ok(checkpoint_key(&session_id, &checkpoint_id)) +} + +/// Captures emitted turn and session events in memory. +#[derive(Debug, Clone, Default)] +pub struct CollectingEventSink { + turn_events: Arc>>, + session_events: Arc>>, +} + +impl CollectingEventSink { + pub fn new() -> Self { + Self::default() + } + + pub fn turn_events(&self) -> Vec { + self.turn_events + .lock() + .expect("turn events lock poisoned") + .clone() + } + + pub fn session_events(&self) -> Vec { + self.session_events + .lock() + .expect("session events lock poisoned") + .clone() + } +} + +impl EventSink for CollectingEventSink { + fn emit_turn(&self, turn_event: &TurnEvent) -> bool { + self.turn_events + .lock() + .expect("turn events lock poisoned") + .push(turn_event.clone()); + true + } + + fn emit_session(&self, session_event: &SessionEvent) -> bool { + self.session_events + .lock() + .expect("session events lock poisoned") + .push(session_event.clone()); + true + } +} + +/// Appends replayable trace records as newline-delimited JSON. +#[derive(Debug)] +pub struct JsonlTraceWriter { + path: PathBuf, + closed: Mutex, +} + +impl JsonlTraceWriter { + pub fn new(path: impl Into) -> Self { + let path = path.into(); + if let Some(parent) = path.parent() { + let _ = create_dir_all(parent); + } + Self { + path, + closed: Mutex::new(false), + } + } + + fn write(&self, record: Value) -> bool { + let closed = self.closed.lock().expect("trace writer lock poisoned"); + if *closed { + return false; + } + Self::append_record(&self.path, record) + } + + fn append_record(path: &PathBuf, record: Value) -> bool { + let mut file = match OpenOptions::new() + .create(true) + .append(true) + .open(path) + { + Ok(file) => file, + Err(_) => return false, + }; + writeln!(file, "{}", record).is_ok() + } +} + +impl TraceWriter for JsonlTraceWriter { + fn append_turn(&self, turn_event: &TurnEvent) -> bool { + self.write(json!({ "kind": "turn", "event": turn_event.to_value(&SaveContext::new()) })) + } + + fn append_session(&self, session_event: &SessionEvent) -> bool { + self.write( + json!({ "kind": "session", "event": session_event.to_value(&SaveContext::new()) }), + ) + } + + fn close(&self, summary: &Option) -> bool { + let mut closed = self.closed.lock().expect("trace writer lock poisoned"); + if *closed { + return false; + } + let wrote_summary = match summary { + Some(summary) => Self::append_record( + &self.path, + json!({ "kind": "summary", "summary": summary.to_value(&SaveContext::new()) }), + ), + None => true, + }; + if !wrote_summary { + return false; + } + *closed = true; + wrote_summary + } +} + +/// Stores checkpoints in memory by session and checkpoint identifier. +#[derive(Debug, Clone, Default)] +pub struct InMemoryCheckpointStore { + checkpoints: Arc>>, +} + +impl InMemoryCheckpointStore { + pub fn new() -> Self { + Self::default() + } +} + +#[async_trait::async_trait] +impl CheckpointStore for InMemoryCheckpointStore { + async fn save(&self, checkpoint: &Checkpoint) -> Result { + self.checkpoints + .lock() + .expect("checkpoint store lock poisoned") + .insert(require_checkpoint_key(checkpoint)?, checkpoint.clone()); + Ok(checkpoint.clone()) + } + + async fn load( + &self, + session_id: &String, + checkpoint_id: &String, + ) -> Result, AdapterError> { + Ok(self + .checkpoints + .lock() + .expect("checkpoint store lock poisoned") + .get(&checkpoint_key(session_id, checkpoint_id)) + .cloned()) + } + + async fn list_checkpoints(&self, session_id: &String) -> Result, AdapterError> { + let mut checkpoints: Vec = self + .checkpoints + .lock() + .expect("checkpoint store lock poisoned") + .values() + .filter(|checkpoint| checkpoint.session_id.as_deref() == Some(session_id.as_str())) + .cloned() + .collect(); + checkpoints.sort_by(|left, right| left.id.cmp(&right.id)); + Ok(checkpoints) + } +} + +/// Resolves every permission request as approved. +#[derive(Debug, Clone, Default)] +pub struct AllowAllPermissionResolver; + +#[async_trait::async_trait] +impl PermissionResolver for AllowAllPermissionResolver { + async fn request( + &self, + request: &PermissionRequest, + ) -> Result { + Ok(PermissionDecision { + request_id: request.request_id.clone(), + tool_call_id: request.tool_call_id.clone(), + permission: request.permission.clone(), + approved: true, + reason: Some("allow_all".to_string()), + result: Value::Null, + }) + } +} + +/// Resolves every permission request as denied. +#[derive(Debug, Clone, Default)] +pub struct DenyAllPermissionResolver; + +#[async_trait::async_trait] +impl PermissionResolver for DenyAllPermissionResolver { + async fn request( + &self, + request: &PermissionRequest, + ) -> Result { + Ok(PermissionDecision { + request_id: request.request_id.clone(), + tool_call_id: request.tool_call_id.clone(), + permission: request.permission.clone(), + approved: false, + reason: Some("deny_all".to_string()), + result: Value::Null, + }) + } +} + +/// Dispatches host tool requests to registered local functions. +#[derive(Clone, Default)] +pub struct FunctionHostToolExecutor { + handlers: Arc>>, +} + +impl FunctionHostToolExecutor { + pub fn new(handlers: HashMap>) -> Self { + Self { + handlers: Arc::new(handlers), + } + } +} + +#[async_trait::async_trait] +impl HostToolExecutor for FunctionHostToolExecutor { + async fn execute(&self, request: &HostToolRequest) -> Result { + let started = Instant::now(); + let Some(handler) = self.handlers.get(&request.tool_name) else { + return Ok(HostToolResult { + request_id: request.request_id.clone(), + tool_call_id: request.tool_call_id.clone(), + tool_name: request.tool_name.clone(), + success: false, + result: Some( + json!({ "message": format!("No host tool registered for '{}'", request.tool_name) }), + ), + exit_code: None, + duration_ms: Some(started.elapsed().as_secs_f64() * 1000.0), + error_kind: Some("not_found".to_string()), + telemetry: Value::Null, + }); + }; + + let empty_arguments; + let arguments = if request.arguments.is_null() { + empty_arguments = Value::Object(serde_json::Map::new()); + &empty_arguments + } else { + &request.arguments + }; + + match handler(arguments, request) { + Ok(result) => Ok(HostToolResult { + request_id: request.request_id.clone(), + tool_call_id: request.tool_call_id.clone(), + tool_name: request.tool_name.clone(), + success: true, + result: Some(result), + exit_code: None, + duration_ms: Some(started.elapsed().as_secs_f64() * 1000.0), + error_kind: None, + telemetry: Value::Null, + }), + Err(error) => Ok(HostToolResult { + request_id: request.request_id.clone(), + tool_call_id: request.tool_call_id.clone(), + tool_name: request.tool_name.clone(), + success: false, + result: Some(json!({ "message": error.to_string() })), + exit_code: None, + duration_ms: Some(started.elapsed().as_secs_f64() * 1000.0), + error_kind: Some("exception".to_string()), + telemetry: Value::Null, + }), + } + } +} diff --git a/runtime/rust/prompty/src/lib.rs b/runtime/rust/prompty/src/lib.rs index bafb6711..177e1bb3 100644 --- a/runtime/rust/prompty/src/lib.rs +++ b/runtime/rust/prompty/src/lib.rs @@ -38,6 +38,7 @@ pub mod connections; pub mod context; pub mod guardrails; +pub mod harness; pub mod interfaces; pub mod loader; pub mod model; @@ -62,6 +63,10 @@ pub use guardrails::{ GuardrailError, GuardrailPhase, GuardrailResult, Guardrails, InputGuardrail, OutputGuardrail, ToolGuardrail, }; +pub use harness::{ + AllowAllPermissionResolver, CollectingEventSink, DenyAllPermissionResolver, + FunctionHostToolExecutor, InMemoryCheckpointStore, JsonlTraceWriter, +}; pub use interfaces::{ExecuteError, Executor, InvokerError, Parser, Processor, Renderer}; pub use loader::{ LoadError, LoadOptions, load, load_async, load_async_with_options, load_from_string, diff --git a/runtime/rust/prompty/tests/harness_adapters.rs b/runtime/rust/prompty/tests/harness_adapters.rs new file mode 100644 index 00000000..59ac8644 --- /dev/null +++ b/runtime/rust/prompty/tests/harness_adapters.rs @@ -0,0 +1,281 @@ +use std::collections::HashMap; +use std::fs; +use std::sync::Arc; +use std::time::{SystemTime, UNIX_EPOCH}; + +use prompty::harness::{ + AllowAllPermissionResolver, CollectingEventSink, DenyAllPermissionResolver, + FunctionHostToolExecutor, InMemoryCheckpointStore, JsonlTraceWriter, +}; +use prompty::model::events::{ + checkpoint::Checkpoint, + host_tool_request::HostToolRequest, + permission_request::PermissionRequest, + session_event::{SessionEvent, SessionEventType}, + session_summary::SessionSummary, + turn_event::{TurnEvent, TurnEventType}, +}; +use prompty::model::pipeline::{ + checkpoint_store::CheckpointStore, event_sink::EventSink, host_tool_executor::HostToolExecutor, + permission_resolver::PermissionResolver, trace_writer::TraceWriter, +}; +use serde_json::{Value, json}; + +fn turn_event() -> TurnEvent { + TurnEvent { + id: "turn-event".to_string(), + r#type: TurnEventType::Turn_start, + timestamp: "2026-06-10T00:00:00Z".to_string(), + payload: json!({ "phase": "start" }), + ..Default::default() + } +} + +fn session_event() -> SessionEvent { + SessionEvent { + id: "session-event".to_string(), + r#type: SessionEventType::Session_start, + timestamp: "2026-06-10T00:00:00Z".to_string(), + session_id: Some("session-1".to_string()), + payload: json!({ "phase": "start" }), + ..Default::default() + } +} + +#[test] +fn collecting_event_sink_captures_events() { + let sink = CollectingEventSink::new(); + + assert!(sink.emit_turn(&turn_event())); + assert!(sink.emit_session(&session_event())); + + assert_eq!(sink.turn_events()[0].id, "turn-event"); + assert_eq!(sink.session_events()[0].id, "session-event"); +} + +#[test] +fn jsonl_trace_writer_writes_records() { + let path = std::env::temp_dir().join(format!( + "prompty-trace-{}.jsonl", + SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_nanos() + )); + let writer = JsonlTraceWriter::new(&path); + + assert!(writer.append_turn(&turn_event())); + assert!(writer.append_session(&session_event())); + assert!(writer.close(&Some(SessionSummary { + session_id: "session-1".to_string(), + turns: Some(1), + ..Default::default() + }))); + + let records: Vec = fs::read_to_string(&path) + .unwrap() + .lines() + .map(|line| serde_json::from_str(line).unwrap()) + .collect(); + let _ = fs::remove_file(path); + + assert_eq!(records[0]["kind"], "turn"); + assert_eq!(records[0]["event"]["id"], "turn-event"); + assert_eq!(records[1]["kind"], "session"); + assert_eq!(records[1]["event"]["id"], "session-event"); + assert_eq!(records[2]["kind"], "summary"); + assert_eq!(records[2]["summary"]["sessionId"], "session-1"); +} + +#[test] +fn jsonl_trace_writer_returns_false_after_close() { + let path = std::env::temp_dir().join(format!( + "prompty-trace-closed-{}.jsonl", + SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_nanos() + )); + let writer = JsonlTraceWriter::new(&path); + + assert!(writer.close(&None)); + assert!(!writer.append_turn(&turn_event())); + let _ = fs::remove_file(path); +} + +#[tokio::test] +async fn in_memory_checkpoint_store_stores_checkpoints() { + let store = InMemoryCheckpointStore::new(); + let checkpoint = Checkpoint { + id: Some("checkpoint-1".to_string()), + session_id: Some("session-1".to_string()), + title: "First".to_string(), + ..Default::default() + }; + + assert_eq!(store.save(&checkpoint).await.unwrap().id, checkpoint.id); + assert_eq!( + store + .load(&"session-1".to_string(), &"checkpoint-1".to_string()) + .await + .unwrap() + .unwrap() + .title, + "First" + ); + assert!( + store + .load(&"session-1".to_string(), &"missing".to_string()) + .await + .unwrap() + .is_none() + ); + assert_eq!( + store + .list_checkpoints(&"session-1".to_string()) + .await + .unwrap() + .len(), + 1 + ); +} + +#[tokio::test] +async fn in_memory_checkpoint_store_requires_keys() { + let store = InMemoryCheckpointStore::new(); + + assert!( + store + .save(&Checkpoint { + id: Some("checkpoint-1".to_string()), + ..Default::default() + }) + .await + .is_err() + ); + assert!( + store + .save(&Checkpoint { + session_id: Some("session-1".to_string()), + ..Default::default() + }) + .await + .is_err() + ); +} + +#[tokio::test] +async fn permission_resolvers_return_decisions() { + let request = PermissionRequest { + request_id: Some("permission-1".to_string()), + tool_call_id: Some("tool-call-1".to_string()), + permission: "tool.execute".to_string(), + ..Default::default() + }; + + let allow = AllowAllPermissionResolver.request(&request).await.unwrap(); + let deny = DenyAllPermissionResolver.request(&request).await.unwrap(); + + assert!(allow.approved); + assert_eq!(allow.reason.as_deref(), Some("allow_all")); + assert_eq!(allow.request_id.as_deref(), Some("permission-1")); + assert_eq!(allow.tool_call_id.as_deref(), Some("tool-call-1")); + assert!(!deny.approved); + assert_eq!(deny.reason.as_deref(), Some("deny_all")); +} + +#[tokio::test] +async fn function_host_tool_executor_executes_registered_handlers() { + let mut handlers = HashMap::new(); + handlers.insert( + "add".to_string(), + Arc::new( + |args: &Value, + _request: &HostToolRequest| + -> Result> { + Ok(json!( + args["a"].as_i64().unwrap() + args["b"].as_i64().unwrap() + )) + }, + ) as Arc<_>, + ); + let executor = FunctionHostToolExecutor::new(handlers); + + let result = executor + .execute(&HostToolRequest { + request_id: Some("exec-1".to_string()), + tool_name: "add".to_string(), + arguments: json!({ "a": 2, "b": 3 }), + ..Default::default() + }) + .await + .unwrap(); + + assert!(result.success); + assert_eq!(result.request_id.as_deref(), Some("exec-1")); + assert_eq!(result.result, Some(json!(5))); +} + +#[tokio::test] +async fn function_host_tool_executor_passes_empty_arguments() { + let mut handlers = HashMap::new(); + handlers.insert( + "count".to_string(), + Arc::new( + |args: &Value, + _request: &HostToolRequest| + -> Result> { + Ok(json!(args.as_object().unwrap().len())) + }, + ) as Arc<_>, + ); + let executor = FunctionHostToolExecutor::new(handlers); + + let result = executor + .execute(&HostToolRequest { + tool_name: "count".to_string(), + ..Default::default() + }) + .await + .unwrap(); + + assert!(result.success); + assert_eq!(result.result, Some(json!(0))); +} + +#[tokio::test] +async fn function_host_tool_executor_returns_failure_results() { + let mut handlers = HashMap::new(); + handlers.insert( + "fail".to_string(), + Arc::new( + |_args: &Value, + _request: &HostToolRequest| + -> Result> { + Err(Box::new(std::io::Error::other("boom"))) + }, + ) as Arc<_>, + ); + let executor = FunctionHostToolExecutor::new(handlers); + + let missing = executor + .execute(&HostToolRequest { + tool_name: "missing".to_string(), + ..Default::default() + }) + .await + .unwrap(); + let thrown = executor + .execute(&HostToolRequest { + tool_name: "fail".to_string(), + ..Default::default() + }) + .await + .unwrap(); + + assert!(!missing.success); + assert_eq!(missing.error_kind.as_deref(), Some("not_found")); + assert!(!thrown.success); + assert_eq!(thrown.error_kind.as_deref(), Some("exception")); + assert_eq!(thrown.result, Some(json!({ "message": "boom" }))); +} diff --git a/runtime/typescript/packages/core/src/harness/adapters.ts b/runtime/typescript/packages/core/src/harness/adapters.ts new file mode 100644 index 00000000..1d8334f3 --- /dev/null +++ b/runtime/typescript/packages/core/src/harness/adapters.ts @@ -0,0 +1,180 @@ +// Copyright (c) Microsoft. All rights reserved. + +import { appendFileSync, mkdirSync } from "node:fs"; +import { dirname } from "node:path"; + +import { + Checkpoint, + HostToolRequest, + HostToolResult, + PermissionDecision, + PermissionRequest, + SessionEvent, + SessionSummary, + TurnEvent, + type CheckpointStore, + type EventSink, + type HostToolExecutor, + type PermissionResolver, + type TraceWriter, +} from "../model/index.js"; + +type JsonRecord = Record; +type ToolHandler = (args: JsonRecord, request: HostToolRequest) => unknown | Promise; + +function checkpointKey(sessionId: string, checkpointId: string): string { + return `${sessionId}\u0000${checkpointId}`; +} + +function requireCheckpointKey(checkpoint: Checkpoint): { sessionId: string; checkpointId: string } { + if (!checkpoint.sessionId) { + throw new Error("Checkpoint sessionId is required"); + } + if (!checkpoint.id) { + throw new Error("Checkpoint id is required"); + } + return { sessionId: checkpoint.sessionId, checkpointId: checkpoint.id }; +} + +function errorMessage(error: unknown): string { + return error instanceof Error ? error.message : String(error); +} + +/** Captures emitted turn and session events in memory. */ +export class CollectingEventSink implements EventSink { + readonly turnEvents: TurnEvent[] = []; + readonly sessionEvents: SessionEvent[] = []; + + emitTurn(turnEvent: TurnEvent): boolean { + this.turnEvents.push(turnEvent); + return true; + } + + emitSession(sessionEvent: SessionEvent): boolean { + this.sessionEvents.push(sessionEvent); + return true; + } +} + +/** Appends replayable trace records as newline-delimited JSON. */ +export class JsonlTraceWriter implements TraceWriter { + private closed = false; + + constructor(private readonly path: string) { + mkdirSync(dirname(path), { recursive: true }); + } + + appendTurn(turnEvent: TurnEvent): boolean { + return this.write({ kind: "turn", event: turnEvent.save() }); + } + + appendSession(sessionEvent: SessionEvent): boolean { + return this.write({ kind: "session", event: sessionEvent.save() }); + } + + close(summary: SessionSummary | null): boolean { + if (summary) { + if (!this.write({ kind: "summary", summary: summary.save() })) { + return false; + } + } + this.closed = true; + return true; + } + + private write(record: JsonRecord): boolean { + if (this.closed) { + return false; + } + appendFileSync(this.path, `${JSON.stringify(record)}\n`, "utf8"); + return true; + } +} + +/** Stores checkpoints in memory by session and checkpoint identifier. */ +export class InMemoryCheckpointStore implements CheckpointStore { + private readonly checkpoints = new Map(); + + async save(checkpoint: Checkpoint): Promise { + const { sessionId, checkpointId } = requireCheckpointKey(checkpoint); + this.checkpoints.set(checkpointKey(sessionId, checkpointId), checkpoint); + return checkpoint; + } + + async load(sessionId: string, checkpointId: string): Promise { + return this.checkpoints.get(checkpointKey(sessionId, checkpointId)) ?? null; + } + + async listCheckpoints(sessionId: string): Promise { + return [...this.checkpoints.values()].filter((checkpoint) => checkpoint.sessionId === sessionId); + } +} + +/** Resolves every permission request as approved. */ +export class AllowAllPermissionResolver implements PermissionResolver { + async request(request: PermissionRequest): Promise { + return new PermissionDecision({ + requestId: request.requestId, + toolCallId: request.toolCallId, + permission: request.permission, + approved: true, + reason: "allow_all", + }); + } +} + +/** Resolves every permission request as denied. */ +export class DenyAllPermissionResolver implements PermissionResolver { + async request(request: PermissionRequest): Promise { + return new PermissionDecision({ + requestId: request.requestId, + toolCallId: request.toolCallId, + permission: request.permission, + approved: false, + reason: "deny_all", + }); + } +} + +/** Dispatches host tool requests to registered local functions. */ +export class FunctionHostToolExecutor implements HostToolExecutor { + constructor(private readonly handlers: Record) {} + + async execute(request: HostToolRequest): Promise { + const started = Date.now(); + const handler = this.handlers[request.toolName]; + if (!handler) { + return new HostToolResult({ + requestId: request.requestId, + toolCallId: request.toolCallId, + toolName: request.toolName, + success: false, + errorKind: "not_found", + result: { message: `No host tool registered for '${request.toolName}'` }, + durationMs: Date.now() - started, + }); + } + + try { + const result = await handler(request.arguments ?? {}, request); + return new HostToolResult({ + requestId: request.requestId, + toolCallId: request.toolCallId, + toolName: request.toolName, + success: true, + result, + durationMs: Date.now() - started, + }); + } catch (error) { + return new HostToolResult({ + requestId: request.requestId, + toolCallId: request.toolCallId, + toolName: request.toolName, + success: false, + errorKind: "exception", + result: { message: errorMessage(error) }, + durationMs: Date.now() - started, + }); + } + } +} diff --git a/runtime/typescript/packages/core/src/harness/index.ts b/runtime/typescript/packages/core/src/harness/index.ts new file mode 100644 index 00000000..10b4fbce --- /dev/null +++ b/runtime/typescript/packages/core/src/harness/index.ts @@ -0,0 +1,8 @@ +export { + AllowAllPermissionResolver, + CollectingEventSink, + DenyAllPermissionResolver, + FunctionHostToolExecutor, + InMemoryCheckpointStore, + JsonlTraceWriter, +} from "./adapters.js"; diff --git a/runtime/typescript/packages/core/src/index.ts b/runtime/typescript/packages/core/src/index.ts index d33fae02..c4b75b22 100644 --- a/runtime/typescript/packages/core/src/index.ts +++ b/runtime/typescript/packages/core/src/index.ts @@ -113,6 +113,19 @@ export { export { NunjucksRenderer, MustacheRenderer } from "./renderers/index.js"; export { PromptyChatParser } from "./parsers/index.js"; +// --------------------------------------------------------------------------- +// Harness reference adapters +// --------------------------------------------------------------------------- + +export { + AllowAllPermissionResolver, + CollectingEventSink, + DenyAllPermissionResolver, + FunctionHostToolExecutor, + InMemoryCheckpointStore, + JsonlTraceWriter, +} from "./harness/index.js"; + // --------------------------------------------------------------------------- // Tracing // --------------------------------------------------------------------------- @@ -166,6 +179,19 @@ export { PromptyTool, McpApprovalMode, Binding, + TurnEvent, + SessionEvent, + SessionSummary, + Checkpoint, + PermissionRequest, + PermissionDecision, + HostToolRequest, + HostToolResult, + type EventSink, + type TraceWriter, + type PermissionResolver, + type CheckpointStore, + type HostToolExecutor, } from "./model/index.js"; // Backward-compat aliases (will be removed in a future version) diff --git a/runtime/typescript/packages/core/tests/harness/adapters.test.ts b/runtime/typescript/packages/core/tests/harness/adapters.test.ts new file mode 100644 index 00000000..2a824a61 --- /dev/null +++ b/runtime/typescript/packages/core/tests/harness/adapters.test.ts @@ -0,0 +1,164 @@ +import { mkdtempSync, readFileSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; + +import { + AllowAllPermissionResolver, + Checkpoint, + CollectingEventSink, + DenyAllPermissionResolver, + FunctionHostToolExecutor, + HostToolRequest, + InMemoryCheckpointStore, + JsonlTraceWriter, + PermissionRequest, + SessionEvent, + SessionSummary, + TurnEvent, +} from "../../src/index"; + +function turnEvent(): TurnEvent { + return new TurnEvent({ + id: "turn-event", + type: "turn_start", + timestamp: "2026-06-10T00:00:00Z", + payload: { phase: "start" }, + }); +} + +function sessionEvent(): SessionEvent { + return new SessionEvent({ + id: "session-event", + type: "session_start", + timestamp: "2026-06-10T00:00:00Z", + sessionId: "session-1", + payload: { phase: "start" }, + }); +} + +describe("harness reference adapters", () => { + it("collects emitted events in order", () => { + const sink = new CollectingEventSink(); + + expect(sink.emitTurn(turnEvent())).toBe(true); + expect(sink.emitSession(sessionEvent())).toBe(true); + + expect(sink.turnEvents.map((event) => event.id)).toEqual(["turn-event"]); + expect(sink.sessionEvents.map((event) => event.id)).toEqual(["session-event"]); + }); + + it("writes JSONL trace records", () => { + const dir = mkdtempSync(join(tmpdir(), "prompty-trace-")); + try { + const path = join(dir, "trace.jsonl"); + const writer = new JsonlTraceWriter(path); + + writer.appendTurn(turnEvent()); + writer.appendSession(sessionEvent()); + writer.close(new SessionSummary({ sessionId: "session-1", turns: 1 })); + + const lines = readFileSync(path, "utf8").trim().split("\n").map((line) => JSON.parse(line)); + expect(lines.map((line) => line.kind)).toEqual(["turn", "session", "summary"]); + expect(lines[0].event.id).toBe("turn-event"); + expect(lines[1].event.id).toBe("session-event"); + expect(lines[2].summary.sessionId).toBe("session-1"); + } finally { + rmSync(dir, { recursive: true, force: true }); + } + }); + + it("returns false when writing after trace close", () => { + const dir = mkdtempSync(join(tmpdir(), "prompty-trace-")); + try { + const writer = new JsonlTraceWriter(join(dir, "trace.jsonl")); + + expect(writer.close(null)).toBe(true); + expect(writer.appendTurn(turnEvent())).toBe(false); + } finally { + rmSync(dir, { recursive: true, force: true }); + } + }); + + it("stores checkpoints by session and checkpoint id", async () => { + const store = new InMemoryCheckpointStore(); + const checkpoint = new Checkpoint({ id: "checkpoint-1", sessionId: "session-1", title: "First" }); + + await expect(store.save(checkpoint)).resolves.toBe(checkpoint); + await expect(store.load("session-1", "checkpoint-1")).resolves.toBe(checkpoint); + await expect(store.load("session-1", "missing")).resolves.toBeNull(); + await expect(store.listCheckpoints("session-1")).resolves.toEqual([checkpoint]); + }); + + it("requires checkpoint identifiers when saving", async () => { + const store = new InMemoryCheckpointStore(); + + await expect(store.save(new Checkpoint({ id: "checkpoint-1", title: "Missing session" }))).rejects.toThrow( + "sessionId", + ); + await expect(store.save(new Checkpoint({ sessionId: "session-1", title: "Missing id" }))).rejects.toThrow("id"); + }); + + it("resolves allow-all and deny-all permissions", async () => { + const request = new PermissionRequest({ + requestId: "permission-1", + toolCallId: "tool-call-1", + permission: "tool.execute", + }); + + await expect(new AllowAllPermissionResolver().request(request)).resolves.toMatchObject({ + requestId: "permission-1", + toolCallId: "tool-call-1", + permission: "tool.execute", + approved: true, + reason: "allow_all", + }); + await expect(new DenyAllPermissionResolver().request(request)).resolves.toMatchObject({ + approved: false, + reason: "deny_all", + }); + }); + + it("executes registered host tool functions", async () => { + const executor = new FunctionHostToolExecutor({ + add: (args) => Number(args.a) + Number(args.b), + }); + + await expect( + executor.execute(new HostToolRequest({ requestId: "exec-1", toolName: "add", arguments: { a: 2, b: 3 } })), + ).resolves.toMatchObject({ + requestId: "exec-1", + toolName: "add", + success: true, + result: 5, + }); + }); + + it("passes empty arguments to host tool functions when omitted", async () => { + const executor = new FunctionHostToolExecutor({ + count: (args) => Object.keys(args).length, + }); + + await expect(executor.execute(new HostToolRequest({ toolName: "count" }))).resolves.toMatchObject({ + success: true, + result: 0, + }); + }); + + it("returns failed host tool results for missing or throwing handlers", async () => { + const executor = new FunctionHostToolExecutor({ + fail: () => { + throw new Error("boom"); + }, + }); + + await expect(executor.execute(new HostToolRequest({ toolName: "missing" }))).resolves.toMatchObject({ + success: false, + errorKind: "not_found", + }); + await expect(executor.execute(new HostToolRequest({ toolName: "fail" }))).resolves.toMatchObject({ + success: false, + errorKind: "exception", + result: { message: "boom" }, + }); + }); +}); From 808c6c7583e69921469bd335121f4fa1984d796e Mon Sep 17 00:00:00 2001 From: Seth Juarez Date: Sat, 27 Jun 2026 13:31:38 -0700 Subject: [PATCH 05/22] Rename harness trace writer to event journal Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Prompty.Core.Tests/HarnessAdaptersTests.cs | 8 ++++---- runtime/csharp/Prompty.Core/HarnessAdapters.cs | 6 +++--- .../{TraceWriter.cs => EventJournalWriter.cs} | 10 +++++----- .../go/prompty/model/event_journal_writer.go | 15 +++++++++++++++ runtime/go/prompty/model/harness_adapters.go | 16 ++++++++-------- .../go/prompty/model/harness_adapters_test.go | 8 ++++---- runtime/go/prompty/model/trace_writer.go | 15 --------------- runtime/python/prompty/prompty/__init__.py | 4 ++-- .../python/prompty/prompty/harness/__init__.py | 4 ++-- .../python/prompty/prompty/harness/adapters.py | 4 ++-- .../python/prompty/prompty/model/__init__.py | 4 ++-- ...{_TraceWriter.py => _EventJournalWriter.py} | 10 +++++----- .../prompty/prompty/model/pipeline/__init__.py | 4 ++-- .../prompty/tests/test_harness_adapters.py | 10 +++++----- runtime/rust/prompty/src/harness.rs | 12 ++++++------ runtime/rust/prompty/src/lib.rs | 2 +- ...trace_writer.rs => event_journal_writer.rs} | 10 +++++----- runtime/rust/prompty/src/model/pipeline/mod.rs | 4 ++-- runtime/rust/prompty/tests/harness_adapters.rs | 14 +++++++------- .../packages/core/src/harness/adapters.ts | 6 +++--- .../packages/core/src/harness/index.ts | 2 +- runtime/typescript/packages/core/src/index.ts | 4 ++-- .../packages/core/src/model/index.ts | 2 +- ...trace-writer.ts => event-journal-writer.ts} | 10 +++++----- .../packages/core/src/model/pipeline/index.ts | 2 +- .../core/tests/harness/adapters.test.ts | 8 ++++---- schema/model/pipeline/harness.tsp | 18 +++++++++--------- vscode/prompty/schemas/EventJournalWriter.yaml | 5 +++++ vscode/prompty/schemas/TraceWriter.yaml | 5 ----- .../{TraceWriter.md => EventJournalWriter.md} | 18 +++++++++--------- 30 files changed, 120 insertions(+), 120 deletions(-) rename runtime/csharp/Prompty.Core/Model/pipeline/{TraceWriter.cs => EventJournalWriter.cs} (60%) create mode 100644 runtime/go/prompty/model/event_journal_writer.go delete mode 100644 runtime/go/prompty/model/trace_writer.go rename runtime/python/prompty/prompty/model/pipeline/{_TraceWriter.py => _EventJournalWriter.py} (68%) rename runtime/rust/prompty/src/model/pipeline/{trace_writer.rs => event_journal_writer.rs} (65%) rename runtime/typescript/packages/core/src/model/pipeline/{trace-writer.ts => event-journal-writer.ts} (61%) create mode 100644 vscode/prompty/schemas/EventJournalWriter.yaml delete mode 100644 vscode/prompty/schemas/TraceWriter.yaml rename web/src/content/docs/reference/{TraceWriter.md => EventJournalWriter.md} (68%) diff --git a/runtime/csharp/Prompty.Core.Tests/HarnessAdaptersTests.cs b/runtime/csharp/Prompty.Core.Tests/HarnessAdaptersTests.cs index 6f334ef4..1884d3f7 100644 --- a/runtime/csharp/Prompty.Core.Tests/HarnessAdaptersTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/HarnessAdaptersTests.cs @@ -20,13 +20,13 @@ public void CollectingEventSink_CapturesEvents() } [Fact] - public void JsonlTraceWriter_WritesRecords() + public void JsonlEventJournalWriter_WritesRecords() { var directory = Directory.CreateTempSubdirectory("prompty-trace-"); try { var path = Path.Combine(directory.FullName, "trace.jsonl"); - var writer = new JsonlTraceWriter(path); + var writer = new JsonlEventJournalWriter(path); writer.AppendTurn(TurnEvent()); writer.AppendSession(SessionEvent()); @@ -49,12 +49,12 @@ public void JsonlTraceWriter_WritesRecords() } [Fact] - public void JsonlTraceWriter_ReturnsFalseAfterClose() + public void JsonlEventJournalWriter_ReturnsFalseAfterClose() { var directory = Directory.CreateTempSubdirectory("prompty-trace-"); try { - var writer = new JsonlTraceWriter(Path.Combine(directory.FullName, "trace.jsonl")); + var writer = new JsonlEventJournalWriter(Path.Combine(directory.FullName, "trace.jsonl")); Assert.True(writer.Close(null)); Assert.False(writer.AppendTurn(TurnEvent())); diff --git a/runtime/csharp/Prompty.Core/HarnessAdapters.cs b/runtime/csharp/Prompty.Core/HarnessAdapters.cs index 68c673b7..005b7194 100644 --- a/runtime/csharp/Prompty.Core/HarnessAdapters.cs +++ b/runtime/csharp/Prompty.Core/HarnessAdapters.cs @@ -56,15 +56,15 @@ public bool EmitSession(SessionEvent sessionEvent) } /// -/// Appends replayable trace records as newline-delimited JSON. +/// Appends replayable event journal records as newline-delimited JSON. /// -public sealed class JsonlTraceWriter : ITraceWriter +public sealed class JsonlEventJournalWriter : IEventJournalWriter { private readonly object _lock = new(); private readonly string _path; private bool _closed; - public JsonlTraceWriter(string path) + public JsonlEventJournalWriter(string path) { _path = path; var directory = Path.GetDirectoryName(path); diff --git a/runtime/csharp/Prompty.Core/Model/pipeline/TraceWriter.cs b/runtime/csharp/Prompty.Core/Model/pipeline/EventJournalWriter.cs similarity index 60% rename from runtime/csharp/Prompty.Core/Model/pipeline/TraceWriter.cs rename to runtime/csharp/Prompty.Core/Model/pipeline/EventJournalWriter.cs index bc4530ae..ac698266 100644 --- a/runtime/csharp/Prompty.Core/Model/pipeline/TraceWriter.cs +++ b/runtime/csharp/Prompty.Core/Model/pipeline/EventJournalWriter.cs @@ -5,20 +5,20 @@ namespace Prompty.Core; #pragma warning restore IDE0130 /// -/// Persists typed events to a replayable trace. +/// Persists typed events to a durable replay journal. /// -public interface ITraceWriter +public interface IEventJournalWriter { /// - /// Append a turn event to a replayable trace + /// Append a turn event to a durable replay journal /// bool AppendTurn(TurnEvent turnEvent); /// - /// Append a session event to a replayable trace + /// Append a session event to a durable replay journal /// bool AppendSession(SessionEvent sessionEvent); /// - /// Finalize the trace with an optional session summary + /// Finalize the journal with an optional session summary /// bool Close(SessionSummary? summary); } diff --git a/runtime/go/prompty/model/event_journal_writer.go b/runtime/go/prompty/model/event_journal_writer.go new file mode 100644 index 00000000..8a2c9acc --- /dev/null +++ b/runtime/go/prompty/model/event_journal_writer.go @@ -0,0 +1,15 @@ +// Code generated by Prompty emitter; DO NOT EDIT. +// Group: pipeline + +package prompty + +// EventJournalWriter represents Persists typed events to a durable replay journal. + +type EventJournalWriter interface { + // AppendTurn — Append a turn event to a durable replay journal + AppendTurn(turnEvent TurnEvent) (bool, error) + // AppendSession — Append a session event to a durable replay journal + AppendSession(sessionEvent SessionEvent) (bool, error) + // Close — Finalize the journal with an optional session summary + Close(summary *SessionSummary) (bool, error) +} diff --git a/runtime/go/prompty/model/harness_adapters.go b/runtime/go/prompty/model/harness_adapters.go index 75775594..db81e523 100644 --- a/runtime/go/prompty/model/harness_adapters.go +++ b/runtime/go/prompty/model/harness_adapters.go @@ -31,29 +31,29 @@ func (s *CollectingEventSink) EmitSession(sessionEvent SessionEvent) (bool, erro return true, nil } -// JsonlTraceWriter appends replayable trace records as newline-delimited JSON. -type JsonlTraceWriter struct { +// JsonlEventJournalWriter appends replayable event journal records as newline-delimited JSON. +type JsonlEventJournalWriter struct { mu sync.Mutex Path string closed bool } -func NewJsonlTraceWriter(path string) (*JsonlTraceWriter, error) { +func NewJsonlEventJournalWriter(path string) (*JsonlEventJournalWriter, error) { if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { return nil, err } - return &JsonlTraceWriter{Path: path}, nil + return &JsonlEventJournalWriter{Path: path}, nil } -func (w *JsonlTraceWriter) AppendTurn(turnEvent TurnEvent) (bool, error) { +func (w *JsonlEventJournalWriter) AppendTurn(turnEvent TurnEvent) (bool, error) { return w.write(map[string]interface{}{"kind": "turn", "event": turnEvent.Save(NewSaveContext())}) } -func (w *JsonlTraceWriter) AppendSession(sessionEvent SessionEvent) (bool, error) { +func (w *JsonlEventJournalWriter) AppendSession(sessionEvent SessionEvent) (bool, error) { return w.write(map[string]interface{}{"kind": "session", "event": sessionEvent.Save(NewSaveContext())}) } -func (w *JsonlTraceWriter) Close(summary *SessionSummary) (bool, error) { +func (w *JsonlEventJournalWriter) Close(summary *SessionSummary) (bool, error) { if summary != nil { if ok, err := w.write(map[string]interface{}{"kind": "summary", "summary": summary.Save(NewSaveContext())}); !ok || err != nil { return ok, err @@ -65,7 +65,7 @@ func (w *JsonlTraceWriter) Close(summary *SessionSummary) (bool, error) { return true, nil } -func (w *JsonlTraceWriter) write(record map[string]interface{}) (bool, error) { +func (w *JsonlEventJournalWriter) write(record map[string]interface{}) (bool, error) { w.mu.Lock() defer w.mu.Unlock() if w.closed { diff --git a/runtime/go/prompty/model/harness_adapters_test.go b/runtime/go/prompty/model/harness_adapters_test.go index bcc949bb..e845bc2c 100644 --- a/runtime/go/prompty/model/harness_adapters_test.go +++ b/runtime/go/prompty/model/harness_adapters_test.go @@ -46,9 +46,9 @@ func TestCollectingEventSink(t *testing.T) { } } -func TestJsonlTraceWriter(t *testing.T) { +func TestJsonlEventJournalWriter(t *testing.T) { path := filepath.Join(t.TempDir(), "trace.jsonl") - writer, err := NewJsonlTraceWriter(path) + writer, err := NewJsonlEventJournalWriter(path) if err != nil { t.Fatal(err) } @@ -84,9 +84,9 @@ func TestJsonlTraceWriter(t *testing.T) { } } -func TestJsonlTraceWriterAfterClose(t *testing.T) { +func TestJsonlEventJournalWriterAfterClose(t *testing.T) { path := filepath.Join(t.TempDir(), "trace.jsonl") - writer, err := NewJsonlTraceWriter(path) + writer, err := NewJsonlEventJournalWriter(path) if err != nil { t.Fatal(err) } diff --git a/runtime/go/prompty/model/trace_writer.go b/runtime/go/prompty/model/trace_writer.go deleted file mode 100644 index ec0695f7..00000000 --- a/runtime/go/prompty/model/trace_writer.go +++ /dev/null @@ -1,15 +0,0 @@ -// Code generated by Prompty emitter; DO NOT EDIT. -// Group: pipeline - -package prompty - -// TraceWriter represents Persists typed events to a replayable trace. - -type TraceWriter interface { - // AppendTurn — Append a turn event to a replayable trace - AppendTurn(turnEvent TurnEvent) (bool, error) - // AppendSession — Append a session event to a replayable trace - AppendSession(sessionEvent SessionEvent) (bool, error) - // Close — Finalize the trace with an optional session summary - Close(summary *SessionSummary) (bool, error) -} diff --git a/runtime/python/prompty/prompty/__init__.py b/runtime/python/prompty/prompty/__init__.py index 5f59b6a8..49db1d71 100644 --- a/runtime/python/prompty/prompty/__init__.py +++ b/runtime/python/prompty/prompty/__init__.py @@ -115,7 +115,7 @@ "DenyAllPermissionResolver", "FunctionHostToolExecutor", "InMemoryCheckpointStore", - "JsonlTraceWriter", + "JsonlEventJournalWriter", "Steering", "StructuredResult", "cast", @@ -144,7 +144,7 @@ DenyAllPermissionResolver, FunctionHostToolExecutor, InMemoryCheckpointStore, - JsonlTraceWriter, + JsonlEventJournalWriter, ) # Loader diff --git a/runtime/python/prompty/prompty/harness/__init__.py b/runtime/python/prompty/prompty/harness/__init__.py index 143727e8..afec492a 100644 --- a/runtime/python/prompty/prompty/harness/__init__.py +++ b/runtime/python/prompty/prompty/harness/__init__.py @@ -6,7 +6,7 @@ DenyAllPermissionResolver, FunctionHostToolExecutor, InMemoryCheckpointStore, - JsonlTraceWriter, + JsonlEventJournalWriter, ) __all__ = [ @@ -15,5 +15,5 @@ "DenyAllPermissionResolver", "FunctionHostToolExecutor", "InMemoryCheckpointStore", - "JsonlTraceWriter", + "JsonlEventJournalWriter", ] diff --git a/runtime/python/prompty/prompty/harness/adapters.py b/runtime/python/prompty/prompty/harness/adapters.py index 54d6bc3f..da2957c5 100644 --- a/runtime/python/prompty/prompty/harness/adapters.py +++ b/runtime/python/prompty/prompty/harness/adapters.py @@ -57,8 +57,8 @@ def emit_session(self, session_event: SessionEvent) -> bool: return True -class JsonlTraceWriter: - """Append replayable trace records as newline-delimited JSON.""" +class JsonlEventJournalWriter: + """Append replayable event journal records as newline-delimited JSON.""" def __init__(self, path: str | Path) -> None: self.path = Path(path) diff --git a/runtime/python/prompty/prompty/model/__init__.py b/runtime/python/prompty/prompty/model/__init__.py index 8b61065b..3c00cd3e 100644 --- a/runtime/python/prompty/prompty/model/__init__.py +++ b/runtime/python/prompty/prompty/model/__init__.py @@ -98,6 +98,7 @@ from .pipeline import ( CheckpointStore, CompactionConfig, + EventJournalWriter, EventSink, Executor, HostToolExecutor, @@ -105,7 +106,6 @@ PermissionResolver, Processor, Renderer, - TraceWriter, TurnOptions, ) from .streaming import ( @@ -200,7 +200,7 @@ "Executor", "Processor", "EventSink", - "TraceWriter", + "EventJournalWriter", "PermissionResolver", "CheckpointStore", "HostToolExecutor", diff --git a/runtime/python/prompty/prompty/model/pipeline/_TraceWriter.py b/runtime/python/prompty/prompty/model/pipeline/_EventJournalWriter.py similarity index 68% rename from runtime/python/prompty/prompty/model/pipeline/_TraceWriter.py rename to runtime/python/prompty/prompty/model/pipeline/_EventJournalWriter.py index 4b06c151..dfe4340a 100644 --- a/runtime/python/prompty/prompty/model/pipeline/_TraceWriter.py +++ b/runtime/python/prompty/prompty/model/pipeline/_EventJournalWriter.py @@ -12,17 +12,17 @@ @runtime_checkable -class TraceWriter(Protocol): - """Persists typed events to a replayable trace.""" +class EventJournalWriter(Protocol): + """Persists typed events to a durable replay journal.""" def append_turn(self, turn_event: TurnEvent) -> bool: - """Append a turn event to a replayable trace""" + """Append a turn event to a durable replay journal""" ... def append_session(self, session_event: SessionEvent) -> bool: - """Append a session event to a replayable trace""" + """Append a session event to a durable replay journal""" ... def close(self, summary: SessionSummary | None) -> bool: - """Finalize the trace with an optional session summary""" + """Finalize the journal with an optional session summary""" ... diff --git a/runtime/python/prompty/prompty/model/pipeline/__init__.py b/runtime/python/prompty/prompty/model/pipeline/__init__.py index 7f39f65a..d17de053 100644 --- a/runtime/python/prompty/prompty/model/pipeline/__init__.py +++ b/runtime/python/prompty/prompty/model/pipeline/__init__.py @@ -5,6 +5,7 @@ ########################################## from ._CheckpointStore import CheckpointStore from ._CompactionConfig import CompactionConfig +from ._EventJournalWriter import EventJournalWriter from ._EventSink import EventSink from ._Executor import Executor from ._HostToolExecutor import HostToolExecutor @@ -12,7 +13,6 @@ from ._PermissionResolver import PermissionResolver from ._Processor import Processor from ._Renderer import Renderer -from ._TraceWriter import TraceWriter from ._TurnOptions import TurnOptions __all__ = [ @@ -23,7 +23,7 @@ "Executor", "Processor", "EventSink", - "TraceWriter", + "EventJournalWriter", "PermissionResolver", "CheckpointStore", "HostToolExecutor", diff --git a/runtime/python/prompty/tests/test_harness_adapters.py b/runtime/python/prompty/tests/test_harness_adapters.py index 36d4e2cd..f9e9cae3 100644 --- a/runtime/python/prompty/tests/test_harness_adapters.py +++ b/runtime/python/prompty/tests/test_harness_adapters.py @@ -10,7 +10,7 @@ DenyAllPermissionResolver, FunctionHostToolExecutor, InMemoryCheckpointStore, - JsonlTraceWriter, + JsonlEventJournalWriter, ) from prompty.model import Checkpoint, HostToolRequest, PermissionRequest, SessionEvent, SessionSummary, TurnEvent @@ -39,9 +39,9 @@ def test_collecting_event_sink_captures_events() -> None: assert [event.id for event in sink.session_events] == ["session-event"] -def test_jsonl_trace_writer_writes_records(tmp_path) -> None: +def test_jsonl_event_journal_writer_writes_records(tmp_path) -> None: trace_path = tmp_path / "trace.jsonl" - writer = JsonlTraceWriter(trace_path) + writer = JsonlEventJournalWriter(trace_path) writer.append_turn(_turn_event()) writer.append_session(_session_event()) @@ -54,8 +54,8 @@ def test_jsonl_trace_writer_writes_records(tmp_path) -> None: assert lines[2]["summary"]["sessionId"] == "session-1" -def test_jsonl_trace_writer_returns_false_after_close(tmp_path) -> None: - writer = JsonlTraceWriter(tmp_path / "trace.jsonl") +def test_jsonl_event_journal_writer_returns_false_after_close(tmp_path) -> None: + writer = JsonlEventJournalWriter(tmp_path / "trace.jsonl") assert writer.close(None) is True assert writer.append_turn(_turn_event()) is False diff --git a/runtime/rust/prompty/src/harness.rs b/runtime/rust/prompty/src/harness.rs index 0e05dd99..6da1ad63 100644 --- a/runtime/rust/prompty/src/harness.rs +++ b/runtime/rust/prompty/src/harness.rs @@ -17,8 +17,8 @@ use crate::model::events::{ session_event::SessionEvent, session_summary::SessionSummary, turn_event::TurnEvent, }; use crate::model::pipeline::{ - checkpoint_store::CheckpointStore, event_sink::EventSink, host_tool_executor::HostToolExecutor, - permission_resolver::PermissionResolver, trace_writer::TraceWriter, + checkpoint_store::CheckpointStore, event_journal_writer::EventJournalWriter, event_sink::EventSink, + host_tool_executor::HostToolExecutor, permission_resolver::PermissionResolver, }; type AdapterError = Box; @@ -89,14 +89,14 @@ impl EventSink for CollectingEventSink { } } -/// Appends replayable trace records as newline-delimited JSON. +/// Appends replayable event journal records as newline-delimited JSON. #[derive(Debug)] -pub struct JsonlTraceWriter { +pub struct JsonlEventJournalWriter { path: PathBuf, closed: Mutex, } -impl JsonlTraceWriter { +impl JsonlEventJournalWriter { pub fn new(path: impl Into) -> Self { let path = path.into(); if let Some(parent) = path.parent() { @@ -129,7 +129,7 @@ impl JsonlTraceWriter { } } -impl TraceWriter for JsonlTraceWriter { +impl EventJournalWriter for JsonlEventJournalWriter { fn append_turn(&self, turn_event: &TurnEvent) -> bool { self.write(json!({ "kind": "turn", "event": turn_event.to_value(&SaveContext::new()) })) } diff --git a/runtime/rust/prompty/src/lib.rs b/runtime/rust/prompty/src/lib.rs index 177e1bb3..ec78c9a0 100644 --- a/runtime/rust/prompty/src/lib.rs +++ b/runtime/rust/prompty/src/lib.rs @@ -65,7 +65,7 @@ pub use guardrails::{ }; pub use harness::{ AllowAllPermissionResolver, CollectingEventSink, DenyAllPermissionResolver, - FunctionHostToolExecutor, InMemoryCheckpointStore, JsonlTraceWriter, + FunctionHostToolExecutor, InMemoryCheckpointStore, JsonlEventJournalWriter, }; pub use interfaces::{ExecuteError, Executor, InvokerError, Parser, Processor, Renderer}; pub use loader::{ diff --git a/runtime/rust/prompty/src/model/pipeline/trace_writer.rs b/runtime/rust/prompty/src/model/pipeline/event_journal_writer.rs similarity index 65% rename from runtime/rust/prompty/src/model/pipeline/trace_writer.rs rename to runtime/rust/prompty/src/model/pipeline/event_journal_writer.rs index d1734168..823f2adc 100644 --- a/runtime/rust/prompty/src/model/pipeline/trace_writer.rs +++ b/runtime/rust/prompty/src/model/pipeline/event_journal_writer.rs @@ -9,13 +9,13 @@ use super::super::events::session_summary::SessionSummary; use super::super::events::turn_event::TurnEvent; -/// Persists typed events to a replayable trace. +/// Persists typed events to a durable replay journal. #[async_trait::async_trait] -pub trait TraceWriter: Send + Sync { - /// Append a turn event to a replayable trace +pub trait EventJournalWriter: Send + Sync { + /// Append a turn event to a durable replay journal fn append_turn(&self, turn_event: &TurnEvent) -> bool; - /// Append a session event to a replayable trace + /// Append a session event to a durable replay journal fn append_session(&self, session_event: &SessionEvent) -> bool; - /// Finalize the trace with an optional session summary + /// Finalize the journal with an optional session summary fn close(&self, summary: &Option) -> bool; } diff --git a/runtime/rust/prompty/src/model/pipeline/mod.rs b/runtime/rust/prompty/src/model/pipeline/mod.rs index f2cbc64d..ab94dce0 100644 --- a/runtime/rust/prompty/src/model/pipeline/mod.rs +++ b/runtime/rust/prompty/src/model/pipeline/mod.rs @@ -23,8 +23,8 @@ pub use processor::*; pub mod event_sink; pub use event_sink::*; -pub mod trace_writer; -pub use trace_writer::*; +pub mod event_journal_writer; +pub use event_journal_writer::*; pub mod permission_resolver; pub use permission_resolver::*; diff --git a/runtime/rust/prompty/tests/harness_adapters.rs b/runtime/rust/prompty/tests/harness_adapters.rs index 59ac8644..82732ee9 100644 --- a/runtime/rust/prompty/tests/harness_adapters.rs +++ b/runtime/rust/prompty/tests/harness_adapters.rs @@ -5,7 +5,7 @@ use std::time::{SystemTime, UNIX_EPOCH}; use prompty::harness::{ AllowAllPermissionResolver, CollectingEventSink, DenyAllPermissionResolver, - FunctionHostToolExecutor, InMemoryCheckpointStore, JsonlTraceWriter, + FunctionHostToolExecutor, InMemoryCheckpointStore, JsonlEventJournalWriter, }; use prompty::model::events::{ checkpoint::Checkpoint, @@ -16,8 +16,8 @@ use prompty::model::events::{ turn_event::{TurnEvent, TurnEventType}, }; use prompty::model::pipeline::{ - checkpoint_store::CheckpointStore, event_sink::EventSink, host_tool_executor::HostToolExecutor, - permission_resolver::PermissionResolver, trace_writer::TraceWriter, + checkpoint_store::CheckpointStore, event_journal_writer::EventJournalWriter, event_sink::EventSink, + host_tool_executor::HostToolExecutor, permission_resolver::PermissionResolver, }; use serde_json::{Value, json}; @@ -54,7 +54,7 @@ fn collecting_event_sink_captures_events() { } #[test] -fn jsonl_trace_writer_writes_records() { +fn jsonl_event_journal_writer_writes_records() { let path = std::env::temp_dir().join(format!( "prompty-trace-{}.jsonl", SystemTime::now() @@ -62,7 +62,7 @@ fn jsonl_trace_writer_writes_records() { .unwrap() .as_nanos() )); - let writer = JsonlTraceWriter::new(&path); + let writer = JsonlEventJournalWriter::new(&path); assert!(writer.append_turn(&turn_event())); assert!(writer.append_session(&session_event())); @@ -88,7 +88,7 @@ fn jsonl_trace_writer_writes_records() { } #[test] -fn jsonl_trace_writer_returns_false_after_close() { +fn jsonl_event_journal_writer_returns_false_after_close() { let path = std::env::temp_dir().join(format!( "prompty-trace-closed-{}.jsonl", SystemTime::now() @@ -96,7 +96,7 @@ fn jsonl_trace_writer_returns_false_after_close() { .unwrap() .as_nanos() )); - let writer = JsonlTraceWriter::new(&path); + let writer = JsonlEventJournalWriter::new(&path); assert!(writer.close(&None)); assert!(!writer.append_turn(&turn_event())); diff --git a/runtime/typescript/packages/core/src/harness/adapters.ts b/runtime/typescript/packages/core/src/harness/adapters.ts index 1d8334f3..c00225b0 100644 --- a/runtime/typescript/packages/core/src/harness/adapters.ts +++ b/runtime/typescript/packages/core/src/harness/adapters.ts @@ -13,10 +13,10 @@ import { SessionSummary, TurnEvent, type CheckpointStore, + type EventJournalWriter, type EventSink, type HostToolExecutor, type PermissionResolver, - type TraceWriter, } from "../model/index.js"; type JsonRecord = Record; @@ -56,8 +56,8 @@ export class CollectingEventSink implements EventSink { } } -/** Appends replayable trace records as newline-delimited JSON. */ -export class JsonlTraceWriter implements TraceWriter { +/** Appends replayable event journal records as newline-delimited JSON. */ +export class JsonlEventJournalWriter implements EventJournalWriter { private closed = false; constructor(private readonly path: string) { diff --git a/runtime/typescript/packages/core/src/harness/index.ts b/runtime/typescript/packages/core/src/harness/index.ts index 10b4fbce..b3be9cbf 100644 --- a/runtime/typescript/packages/core/src/harness/index.ts +++ b/runtime/typescript/packages/core/src/harness/index.ts @@ -4,5 +4,5 @@ export { DenyAllPermissionResolver, FunctionHostToolExecutor, InMemoryCheckpointStore, - JsonlTraceWriter, + JsonlEventJournalWriter, } from "./adapters.js"; diff --git a/runtime/typescript/packages/core/src/index.ts b/runtime/typescript/packages/core/src/index.ts index c4b75b22..0d237ab1 100644 --- a/runtime/typescript/packages/core/src/index.ts +++ b/runtime/typescript/packages/core/src/index.ts @@ -123,7 +123,7 @@ export { DenyAllPermissionResolver, FunctionHostToolExecutor, InMemoryCheckpointStore, - JsonlTraceWriter, + JsonlEventJournalWriter, } from "./harness/index.js"; // --------------------------------------------------------------------------- @@ -187,8 +187,8 @@ export { PermissionDecision, HostToolRequest, HostToolResult, + type EventJournalWriter, type EventSink, - type TraceWriter, type PermissionResolver, type CheckpointStore, type HostToolExecutor, diff --git a/runtime/typescript/packages/core/src/model/index.ts b/runtime/typescript/packages/core/src/model/index.ts index 86ff1cd5..b1ffe1d3 100644 --- a/runtime/typescript/packages/core/src/model/index.ts +++ b/runtime/typescript/packages/core/src/model/index.ts @@ -97,7 +97,7 @@ export type { Parser } from "./pipeline/parser"; export type { Executor } from "./pipeline/executor"; export type { Processor } from "./pipeline/processor"; export type { EventSink } from "./pipeline/event-sink"; -export type { TraceWriter } from "./pipeline/trace-writer"; +export type { EventJournalWriter } from "./pipeline/event-journal-writer"; export type { PermissionResolver } from "./pipeline/permission-resolver"; export type { CheckpointStore } from "./pipeline/checkpoint-store"; export type { HostToolExecutor } from "./pipeline/host-tool-executor"; diff --git a/runtime/typescript/packages/core/src/model/pipeline/trace-writer.ts b/runtime/typescript/packages/core/src/model/pipeline/event-journal-writer.ts similarity index 61% rename from runtime/typescript/packages/core/src/model/pipeline/trace-writer.ts rename to runtime/typescript/packages/core/src/model/pipeline/event-journal-writer.ts index 05a69803..7d9a6723 100644 --- a/runtime/typescript/packages/core/src/model/pipeline/trace-writer.ts +++ b/runtime/typescript/packages/core/src/model/pipeline/event-journal-writer.ts @@ -5,12 +5,12 @@ import { SessionEvent } from "../events/session-event"; import { SessionSummary } from "../events/session-summary"; import { TurnEvent } from "../events/turn-event"; -/** Persists typed events to a replayable trace. */ -export interface TraceWriter { - /** Append a turn event to a replayable trace */ +/** Persists typed events to a durable replay journal. */ +export interface EventJournalWriter { + /** Append a turn event to a durable replay journal */ appendTurn(turnEvent: TurnEvent): boolean; - /** Append a session event to a replayable trace */ + /** Append a session event to a durable replay journal */ appendSession(sessionEvent: SessionEvent): boolean; - /** Finalize the trace with an optional session summary */ + /** Finalize the journal with an optional session summary */ close(summary: SessionSummary | null): boolean; } diff --git a/runtime/typescript/packages/core/src/model/pipeline/index.ts b/runtime/typescript/packages/core/src/model/pipeline/index.ts index c44e4018..8d01b4ea 100644 --- a/runtime/typescript/packages/core/src/model/pipeline/index.ts +++ b/runtime/typescript/packages/core/src/model/pipeline/index.ts @@ -8,7 +8,7 @@ export type { Parser } from "./parser"; export type { Executor } from "./executor"; export type { Processor } from "./processor"; export type { EventSink } from "./event-sink"; -export type { TraceWriter } from "./trace-writer"; +export type { EventJournalWriter } from "./event-journal-writer"; export type { PermissionResolver } from "./permission-resolver"; export type { CheckpointStore } from "./checkpoint-store"; export type { HostToolExecutor } from "./host-tool-executor"; diff --git a/runtime/typescript/packages/core/tests/harness/adapters.test.ts b/runtime/typescript/packages/core/tests/harness/adapters.test.ts index 2a824a61..013af758 100644 --- a/runtime/typescript/packages/core/tests/harness/adapters.test.ts +++ b/runtime/typescript/packages/core/tests/harness/adapters.test.ts @@ -10,7 +10,7 @@ import { FunctionHostToolExecutor, HostToolRequest, InMemoryCheckpointStore, - JsonlTraceWriter, + JsonlEventJournalWriter, PermissionRequest, SessionEvent, SessionSummary, @@ -47,11 +47,11 @@ describe("harness reference adapters", () => { expect(sink.sessionEvents.map((event) => event.id)).toEqual(["session-event"]); }); - it("writes JSONL trace records", () => { + it("writes JSONL event journal records", () => { const dir = mkdtempSync(join(tmpdir(), "prompty-trace-")); try { const path = join(dir, "trace.jsonl"); - const writer = new JsonlTraceWriter(path); + const writer = new JsonlEventJournalWriter(path); writer.appendTurn(turnEvent()); writer.appendSession(sessionEvent()); @@ -70,7 +70,7 @@ describe("harness reference adapters", () => { it("returns false when writing after trace close", () => { const dir = mkdtempSync(join(tmpdir(), "prompty-trace-")); try { - const writer = new JsonlTraceWriter(join(dir, "trace.jsonl")); + const writer = new JsonlEventJournalWriter(join(dir, "trace.jsonl")); expect(writer.close(null)).toBe(true); expect(writer.appendTurn(turnEvent())).toBe(false); diff --git a/schema/model/pipeline/harness.tsp b/schema/model/pipeline/harness.tsp index e33fe0b2..7bcc4681 100644 --- a/schema/model/pipeline/harness.tsp +++ b/schema/model/pipeline/harness.tsp @@ -25,34 +25,34 @@ namespace Prompty; /** Receives typed turn and session events from a harness. */ model EventSink {} -@@protocol(TraceWriter); -@@method(TraceWriter, +@@protocol(EventJournalWriter); +@@method(EventJournalWriter, "appendTurn", "boolean", - "Append a turn event to a replayable trace", + "Append a turn event to a durable replay journal", #{ turnEvent: "TurnEvent" }, false, true ); -@@method(TraceWriter, +@@method(EventJournalWriter, "appendSession", "boolean", - "Append a session event to a replayable trace", + "Append a session event to a durable replay journal", #{ sessionEvent: "SessionEvent" }, false, true ); -@@method(TraceWriter, +@@method(EventJournalWriter, "close", "boolean", - "Finalize the trace with an optional session summary", + "Finalize the journal with an optional session summary", #{ summary: "SessionSummary?" }, false, true ); -/** Persists typed events to a replayable trace. */ -model TraceWriter {} +/** Persists typed events to a durable replay journal. */ +model EventJournalWriter {} @@protocol(PermissionResolver); @@method(PermissionResolver, diff --git a/vscode/prompty/schemas/EventJournalWriter.yaml b/vscode/prompty/schemas/EventJournalWriter.yaml new file mode 100644 index 00000000..cb0b5665 --- /dev/null +++ b/vscode/prompty/schemas/EventJournalWriter.yaml @@ -0,0 +1,5 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: EventJournalWriter.yaml +type: object +properties: {} +description: Persists typed events to a durable replay journal. diff --git a/vscode/prompty/schemas/TraceWriter.yaml b/vscode/prompty/schemas/TraceWriter.yaml deleted file mode 100644 index 79156617..00000000 --- a/vscode/prompty/schemas/TraceWriter.yaml +++ /dev/null @@ -1,5 +0,0 @@ -$schema: https://json-schema.org/draft/2020-12/schema -$id: TraceWriter.yaml -type: object -properties: {} -description: Persists typed events to a replayable trace. diff --git a/web/src/content/docs/reference/TraceWriter.md b/web/src/content/docs/reference/EventJournalWriter.md similarity index 68% rename from web/src/content/docs/reference/TraceWriter.md rename to web/src/content/docs/reference/EventJournalWriter.md index 0af54705..c61d55ba 100644 --- a/web/src/content/docs/reference/TraceWriter.md +++ b/web/src/content/docs/reference/EventJournalWriter.md @@ -1,16 +1,16 @@ --- -title: "TraceWriter" -description: "Documentation for the TraceWriter type." -slug: "reference/tracewriter" +title: "EventJournalWriter" +description: "Documentation for the EventJournalWriter type." +slug: "reference/eventjournalwriter" --- -Persists typed events to a replayable trace. +Persists typed events to a durable replay journal. ## Class Diagram ```mermaid --- -title: TraceWriter +title: EventJournalWriter config: look: handDrawn theme: colorful @@ -18,7 +18,7 @@ config: hideEmptyMembersBox: true --- classDiagram - class TraceWriter { + class EventJournalWriter { <> +appendTurn(turnEvent: TurnEvent) boolean [sync] +appendSession(sessionEvent: SessionEvent) boolean [sync] @@ -32,6 +32,6 @@ The following helper methods are declared via `@method` and must be implemented | Name | Signature | Runtime shape | Description | | ---- | --------- | ------------- | ----------- | -| `appendTurn` | `appendTurn(turnEvent: TurnEvent) -> boolean` | sync | Append a turn event to a replayable trace | -| `appendSession` | `appendSession(sessionEvent: SessionEvent) -> boolean` | sync | Append a session event to a replayable trace | -| `close` | `close(summary: SessionSummary?) -> boolean` | sync | Finalize the trace with an optional session summary | +| `appendTurn` | `appendTurn(turnEvent: TurnEvent) -> boolean` | sync | Append a turn event to a durable replay journal | +| `appendSession` | `appendSession(sessionEvent: SessionEvent) -> boolean` | sync | Append a session event to a durable replay journal | +| `close` | `close(summary: SessionSummary?) -> boolean` | sync | Finalize the journal with an optional session summary | From db429b3eb19cfddeeb71c72cdeb49987da4cab0c Mon Sep 17 00:00:00 2001 From: Seth Juarez Date: Sat, 27 Jun 2026 16:11:15 -0700 Subject: [PATCH 06/22] Consume Typra emitter package Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../agent/GuardrailResultConversionTests.cs | 1 + .../Model/agent/PromptyConversionTests.cs | 1 + .../AnonymousConnectionConversionTests.cs | 1 + .../ApiKeyConnectionConversionTests.cs | 1 + .../connection/ConnectionConversionTests.cs | 1 + .../FoundryConnectionConversionTests.cs | 1 + .../OAuthConnectionConversionTests.cs | 1 + .../ReferenceConnectionConversionTests.cs | 1 + .../RemoteConnectionConversionTests.cs | 1 + .../conversation/AudioPartConversionTests.cs | 1 + .../ContentPartConversionTests.cs | 1 + .../conversation/FilePartConversionTests.cs | 1 + .../conversation/ImagePartConversionTests.cs | 1 + .../conversation/MessageConversionTests.cs | 1 + .../conversation/TextPartConversionTests.cs | 1 + .../ThreadMarkerConversionTests.cs | 1 + .../conversation/ToolCallConversionTests.cs | 1 + .../conversation/ToolResultConversionTests.cs | 1 + .../core/ArrayPropertyConversionTests.cs | 1 + .../core/FileNotFoundErrorConversionTests.cs | 1 + .../Model/core/InvokerErrorConversionTests.cs | 1 + .../core/ObjectPropertyConversionTests.cs | 1 + .../Model/core/PropertyConversionTests.cs | 1 + .../core/ValidationErrorConversionTests.cs | 1 + .../core/ValidationResultConversionTests.cs | 1 + .../Model/events/CheckpointConversionTests.cs | 1 + ...ompactionCompletePayloadConversionTests.cs | 1 + .../CompactionFailedPayloadConversionTests.cs | 1 + .../CompactionStartPayloadConversionTests.cs | 1 + .../events/DoneEventPayloadConversionTests.cs | 1 + .../Model/events/ErrorChunkConversionTests.cs | 1 + .../ErrorEventPayloadConversionTests.cs | 1 + .../events/HarnessContextConversionTests.cs | 1 + .../events/HookEndPayloadConversionTests.cs | 1 + .../events/HookStartPayloadConversionTests.cs | 1 + .../events/HostToolRequestConversionTests.cs | 1 + .../events/HostToolResultConversionTests.cs | 1 + .../LlmCompletePayloadConversionTests.cs | 1 + .../events/LlmStartPayloadConversionTests.cs | 1 + .../MessagesUpdatedPayloadConversionTests.cs | 1 + ...rmissionCompletedPayloadConversionTests.cs | 1 + .../PermissionDecisionConversionTests.cs | 1 + .../PermissionRequestConversionTests.cs | 1 + ...rmissionRequestedPayloadConversionTests.cs | 1 + .../events/RedactedFieldConversionTests.cs | 1 + .../RedactionMetadataConversionTests.cs | 1 + .../events/RetryPayloadConversionTests.cs | 1 + .../SessionEndPayloadConversionTests.cs | 1 + .../events/SessionEventConversionTests.cs | 1 + .../events/SessionFileRefConversionTests.cs | 1 + .../Model/events/SessionRefConversionTests.cs | 1 + .../SessionStartPayloadConversionTests.cs | 1 + .../events/SessionSummaryConversionTests.cs | 1 + .../events/SessionTraceConversionTests.cs | 1 + .../SessionWarningPayloadConversionTests.cs | 1 + .../StatusEventPayloadConversionTests.cs | 1 + .../events/StreamChunkConversionTests.cs | 1 + .../Model/events/TextChunkConversionTests.cs | 1 + .../events/ThinkingChunkConversionTests.cs | 1 + .../ThinkingEventPayloadConversionTests.cs | 1 + .../TokenEventPayloadConversionTests.cs | 1 + .../ToolCallCompletePayloadConversionTests.cs | 1 + .../ToolCallStartPayloadConversionTests.cs | 1 + .../Model/events/ToolChunkConversionTests.cs | 1 + ...ExecutionCompletePayloadConversionTests.cs | 1 + ...oolExecutionStartPayloadConversionTests.cs | 1 + .../ToolResultPayloadConversionTests.cs | 1 + .../events/TrajectoryEventConversionTests.cs | 1 + .../events/TurnEndPayloadConversionTests.cs | 1 + .../Model/events/TurnEventConversionTests.cs | 1 + .../events/TurnStartPayloadConversionTests.cs | 1 + .../events/TurnSummaryConversionTests.cs | 1 + .../Model/events/TurnTraceConversionTests.cs | 1 + .../Model/model/ModelConversionTests.cs | 1 + .../Model/model/ModelInfoConversionTests.cs | 1 + .../model/ModelOptionsConversionTests.cs | 1 + .../Model/model/TokenUsageConversionTests.cs | 1 + .../CompactionConfigConversionTests.cs | 1 + .../pipeline/TurnOptionsConversionTests.cs | 1 + .../streaming/StreamOptionsConversionTests.cs | 1 + .../template/FormatConfigConversionTests.cs | 1 + .../template/ParserConfigConversionTests.cs | 1 + .../Model/template/TemplateConversionTests.cs | 1 + .../Model/tools/BindingConversionTests.cs | 1 + .../Model/tools/CustomToolConversionTests.cs | 1 + .../tools/FunctionToolConversionTests.cs | 1 + .../tools/McpApprovalModeConversionTests.cs | 1 + .../Model/tools/McpToolConversionTests.cs | 1 + .../Model/tools/OpenApiToolConversionTests.cs | 1 + .../Model/tools/PromptyToolConversionTests.cs | 1 + .../Model/tools/ToolContextConversionTests.cs | 1 + .../Model/tools/ToolConversionTests.cs | 1 + .../ToolDispatchResultConversionTests.cs | 1 + .../Model/tracing/TraceFileConversionTests.cs | 1 + .../Model/tracing/TraceSpanConversionTests.cs | 1 + .../Model/tracing/TraceTimeConversionTests.cs | 1 + .../AnthropicImageBlockConversionTests.cs | 1 + .../AnthropicImageSourceConversionTests.cs | 1 + ...AnthropicMessagesRequestConversionTests.cs | 1 + ...nthropicMessagesResponseConversionTests.cs | 1 + .../wire/AnthropicTextBlockConversionTests.cs | 1 + .../AnthropicToolDefinitionConversionTests.cs | 1 + ...AnthropicToolResultBlockConversionTests.cs | 1 + .../AnthropicToolUseBlockConversionTests.cs | 1 + .../wire/AnthropicUsageConversionTests.cs | 1 + .../AnthropicWireMessageConversionTests.cs | 1 + runtime/csharp/Prompty.Core/Model/Context.cs | 1 + runtime/csharp/Prompty.Core/Model/Utils.cs | 1 + .../Model/agent/GuardrailResult.cs | 15 +- .../Prompty.Core/Model/agent/Prompty.cs | 43 +- .../Model/connection/AnonymousConnection.cs | 5 +- .../Model/connection/ApiKeyConnection.cs | 7 +- .../Model/connection/AuthenticationMode.cs | 3 +- .../Model/connection/Connection.cs | 15 +- .../Model/connection/FoundryConnection.cs | 15 +- .../Model/connection/OAuthConnection.cs | 15 +- .../Model/connection/ReferenceConnection.cs | 7 +- .../Model/connection/RemoteConnection.cs | 7 +- .../Model/conversation/AudioPart.cs | 7 +- .../Model/conversation/ContentPart.cs | 11 +- .../Model/conversation/FilePart.cs | 7 +- .../Model/conversation/ImagePart.cs | 7 +- .../Model/conversation/Message.cs | 11 +- .../Prompty.Core/Model/conversation/Role.cs | 3 +- .../Model/conversation/TextPart.cs | 7 +- .../Model/conversation/ThreadMarker.cs | 19 +- .../Model/conversation/ToolCall.cs | 11 +- .../Model/conversation/ToolResult.cs | 19 +- .../Model/conversation/ToolResultStatus.cs | 3 +- .../Prompty.Core/Model/core/ArrayProperty.cs | 11 +- .../Model/core/FileNotFoundError.cs | 11 +- .../Prompty.Core/Model/core/InvokerError.cs | 15 +- .../Prompty.Core/Model/core/ObjectProperty.cs | 11 +- .../Prompty.Core/Model/core/Property.cs | 23 +- .../Model/core/ValidationError.cs | 11 +- .../Model/core/ValidationResult.cs | 15 +- .../Prompty.Core/Model/events/Checkpoint.cs | 7 +- .../Model/events/CompactionCompletePayload.cs | 7 +- .../Model/events/CompactionFailedPayload.cs | 7 +- .../Model/events/CompactionStartPayload.cs | 7 +- .../Model/events/DoneEventPayload.cs | 7 +- .../Prompty.Core/Model/events/ErrorChunk.cs | 7 +- .../Model/events/ErrorEventPayload.cs | 7 +- .../Model/events/HarnessContext.cs | 15 +- .../Model/events/HookEndPayload.cs | 7 +- .../Prompty.Core/Model/events/HookEndScope.cs | 3 +- .../Model/events/HookStartPayload.cs | 7 +- .../Model/events/HookStartScope.cs | 3 +- .../Model/events/HostToolRequest.cs | 7 +- .../Model/events/HostToolResult.cs | 7 +- .../Model/events/LlmCompletePayload.cs | 7 +- .../Model/events/LlmStartPayload.cs | 7 +- .../Model/events/MessagesUpdatedPayload.cs | 7 +- .../events/PermissionCompletedPayload.cs | 7 +- .../Model/events/PermissionDecision.cs | 7 +- .../Model/events/PermissionRequest.cs | 11 +- .../events/PermissionRequestedPayload.cs | 7 +- .../Model/events/RedactedField.cs | 7 +- .../Model/events/RedactionMetadata.cs | 7 +- .../Model/events/RedactionMode.cs | 3 +- .../Prompty.Core/Model/events/RetryPayload.cs | 7 +- .../Model/events/SessionEndPayload.cs | 7 +- .../Model/events/SessionEndStatus.cs | 3 +- .../Prompty.Core/Model/events/SessionEvent.cs | 7 +- .../Model/events/SessionEventType.cs | 3 +- .../Model/events/SessionFileRef.cs | 7 +- .../Prompty.Core/Model/events/SessionRef.cs | 7 +- .../Model/events/SessionStartPayload.cs | 7 +- .../Model/events/SessionSummary.cs | 7 +- .../Model/events/SessionSummaryStatus.cs | 3 +- .../Prompty.Core/Model/events/SessionTrace.cs | 7 +- .../Model/events/SessionWarningPayload.cs | 7 +- .../Model/events/StatusEventPayload.cs | 7 +- .../Prompty.Core/Model/events/StreamChunk.cs | 11 +- .../Prompty.Core/Model/events/TextChunk.cs | 7 +- .../Model/events/ThinkingChunk.cs | 7 +- .../Model/events/ThinkingEventPayload.cs | 7 +- .../Model/events/TokenEventPayload.cs | 7 +- .../Model/events/ToolCallCompletePayload.cs | 7 +- .../Model/events/ToolCallStartPayload.cs | 7 +- .../Prompty.Core/Model/events/ToolChunk.cs | 7 +- .../events/ToolExecutionCompletePayload.cs | 7 +- .../Model/events/ToolExecutionStartPayload.cs | 15 +- .../Model/events/ToolResultPayload.cs | 7 +- .../Model/events/TrajectoryEvent.cs | 7 +- .../Model/events/TurnEndPayload.cs | 7 +- .../Prompty.Core/Model/events/TurnEvent.cs | 15 +- .../Model/events/TurnEventType.cs | 3 +- .../Model/events/TurnStartPayload.cs | 7 +- .../Prompty.Core/Model/events/TurnStatus.cs | 3 +- .../Prompty.Core/Model/events/TurnSummary.cs | 7 +- .../Prompty.Core/Model/events/TurnTrace.cs | 7 +- .../csharp/Prompty.Core/Model/model/Model.cs | 15 +- .../Prompty.Core/Model/model/ModelInfo.cs | 23 +- .../Prompty.Core/Model/model/ModelOptions.cs | 7 +- .../Prompty.Core/Model/model/TokenUsage.cs | 15 +- .../Model/pipeline/CheckpointStore.cs | 33 +- .../Model/pipeline/CompactionConfig.cs | 15 +- .../Model/pipeline/EventJournalWriter.cs | 33 +- .../Prompty.Core/Model/pipeline/EventSink.cs | 25 +- .../Prompty.Core/Model/pipeline/Executor.cs | 33 +- .../Model/pipeline/HostToolExecutor.cs | 17 +- .../Prompty.Core/Model/pipeline/Parser.cs | 25 +- .../Model/pipeline/PermissionResolver.cs | 17 +- .../Prompty.Core/Model/pipeline/Processor.cs | 25 +- .../Prompty.Core/Model/pipeline/Renderer.cs | 17 +- .../Model/pipeline/TurnOptions.cs | 23 +- .../Model/streaming/StreamOptions.cs | 11 +- .../Model/template/FormatConfig.cs | 7 +- .../Model/template/ParserConfig.cs | 7 +- .../Prompty.Core/Model/template/Template.cs | 27 +- .../Prompty.Core/Model/tools/Binding.cs | 7 +- .../Prompty.Core/Model/tools/CustomTool.cs | 23 +- .../Prompty.Core/Model/tools/FunctionTool.cs | 7 +- .../Model/tools/McpApprovalMode.cs | 15 +- .../Model/tools/McpApprovalModeKind.cs | 3 +- .../Prompty.Core/Model/tools/McpTool.cs | 7 +- .../Prompty.Core/Model/tools/OpenApiTool.cs | 5 +- .../Prompty.Core/Model/tools/PromptyTool.cs | 15 +- .../csharp/Prompty.Core/Model/tools/Tool.cs | 7 +- .../Prompty.Core/Model/tools/ToolContext.cs | 15 +- .../Model/tools/ToolDispatchResult.cs | 15 +- .../Prompty.Core/Model/tracing/TraceFile.cs | 7 +- .../Prompty.Core/Model/tracing/TraceSpan.cs | 15 +- .../Prompty.Core/Model/tracing/TraceTime.cs | 7 +- .../Model/wire/AnthropicImageBlock.cs | 11 +- .../Model/wire/AnthropicImageSource.cs | 7 +- .../Model/wire/AnthropicMessagesRequest.cs | 7 +- .../Model/wire/AnthropicMessagesResponse.cs | 7 +- .../Model/wire/AnthropicTextBlock.cs | 7 +- .../Model/wire/AnthropicToolDefinition.cs | 15 +- .../Model/wire/AnthropicToolResultBlock.cs | 7 +- .../Model/wire/AnthropicToolUseBlock.cs | 11 +- .../Prompty.Core/Model/wire/AnthropicUsage.cs | 7 +- .../Model/wire/AnthropicWireMessage.cs | 15 +- .../model/anonymous_connection_test.go | 3 +- .../go/prompty/model/anthropic_image_block.go | 3 +- .../model/anthropic_image_block_test.go | 3 +- .../prompty/model/anthropic_image_source.go | 3 +- .../model/anthropic_image_source_test.go | 3 +- .../model/anthropic_messages_request.go | 3 +- .../model/anthropic_messages_request_test.go | 3 +- .../model/anthropic_messages_response.go | 3 +- .../model/anthropic_messages_response_test.go | 3 +- .../go/prompty/model/anthropic_text_block.go | 3 +- .../model/anthropic_text_block_test.go | 3 +- .../model/anthropic_tool_definition.go | 3 +- .../model/anthropic_tool_definition_test.go | 3 +- .../model/anthropic_tool_result_block.go | 3 +- .../model/anthropic_tool_result_block_test.go | 3 +- .../prompty/model/anthropic_tool_use_block.go | 3 +- .../model/anthropic_tool_use_block_test.go | 3 +- runtime/go/prompty/model/anthropic_usage.go | 3 +- .../go/prompty/model/anthropic_usage_test.go | 3 +- .../prompty/model/anthropic_wire_message.go | 3 +- .../model/anthropic_wire_message_test.go | 3 +- .../prompty/model/api_key_connection_test.go | 3 +- .../go/prompty/model/array_property_test.go | 3 +- runtime/go/prompty/model/audio_part_test.go | 3 +- runtime/go/prompty/model/binding.go | 3 +- runtime/go/prompty/model/binding_test.go | 3 +- runtime/go/prompty/model/checkpoint.go | 3 +- runtime/go/prompty/model/checkpoint_store.go | 3 +- runtime/go/prompty/model/checkpoint_test.go | 3 +- .../model/compaction_complete_payload.go | 3 +- .../model/compaction_complete_payload_test.go | 3 +- runtime/go/prompty/model/compaction_config.go | 3 +- .../prompty/model/compaction_config_test.go | 3 +- .../model/compaction_failed_payload.go | 3 +- .../model/compaction_failed_payload_test.go | 3 +- .../prompty/model/compaction_start_payload.go | 3 +- .../model/compaction_start_payload_test.go | 3 +- runtime/go/prompty/model/connection.go | 3 +- runtime/go/prompty/model/connection_test.go | 3 +- runtime/go/prompty/model/content_part.go | 3 +- runtime/go/prompty/model/content_part_test.go | 3 +- runtime/go/prompty/model/context.go | 5 +- runtime/go/prompty/model/custom_tool_test.go | 3 +- .../go/prompty/model/done_event_payload.go | 3 +- .../prompty/model/done_event_payload_test.go | 3 +- runtime/go/prompty/model/error_chunk_test.go | 3 +- .../go/prompty/model/error_event_payload.go | 3 +- .../prompty/model/error_event_payload_test.go | 3 +- .../go/prompty/model/event_journal_writer.go | 3 +- runtime/go/prompty/model/event_sink.go | 3 +- runtime/go/prompty/model/executor.go | 3 +- .../go/prompty/model/file_not_found_error.go | 3 +- .../model/file_not_found_error_test.go | 3 +- runtime/go/prompty/model/file_part_test.go | 3 +- runtime/go/prompty/model/format_config.go | 3 +- .../go/prompty/model/format_config_test.go | 3 +- .../prompty/model/foundry_connection_test.go | 3 +- .../go/prompty/model/function_tool_test.go | 3 +- runtime/go/prompty/model/guardrail_result.go | 3 +- .../go/prompty/model/guardrail_result_test.go | 3 +- runtime/go/prompty/model/harness_context.go | 3 +- .../go/prompty/model/harness_context_test.go | 3 +- runtime/go/prompty/model/hook_end_payload.go | 3 +- .../go/prompty/model/hook_end_payload_test.go | 3 +- .../go/prompty/model/hook_start_payload.go | 3 +- .../prompty/model/hook_start_payload_test.go | 3 +- .../go/prompty/model/host_tool_executor.go | 3 +- runtime/go/prompty/model/host_tool_request.go | 3 +- .../prompty/model/host_tool_request_test.go | 3 +- runtime/go/prompty/model/host_tool_result.go | 3 +- .../go/prompty/model/host_tool_result_test.go | 3 +- runtime/go/prompty/model/image_part_test.go | 3 +- runtime/go/prompty/model/invoker_error.go | 3 +- .../go/prompty/model/invoker_error_test.go | 3 +- .../go/prompty/model/llm_complete_payload.go | 3 +- .../model/llm_complete_payload_test.go | 3 +- runtime/go/prompty/model/llm_start_payload.go | 3 +- .../prompty/model/llm_start_payload_test.go | 3 +- runtime/go/prompty/model/mcp_approval_mode.go | 3 +- .../prompty/model/mcp_approval_mode_test.go | 3 +- runtime/go/prompty/model/mcp_tool_test.go | 3 +- runtime/go/prompty/model/message.go | 3 +- runtime/go/prompty/model/message_test.go | 3 +- .../prompty/model/messages_updated_payload.go | 3 +- .../model/messages_updated_payload_test.go | 3 +- runtime/go/prompty/model/model.go | 3 +- runtime/go/prompty/model/model_info.go | 3 +- runtime/go/prompty/model/model_info_test.go | 3 +- runtime/go/prompty/model/model_options.go | 3 +- .../go/prompty/model/model_options_test.go | 3 +- runtime/go/prompty/model/model_test.go | 3 +- .../prompty/model/o_auth_connection_test.go | 3 +- .../go/prompty/model/object_property_test.go | 3 +- .../go/prompty/model/open_api_tool_test.go | 3 +- runtime/go/prompty/model/parser.go | 3 +- runtime/go/prompty/model/parser_config.go | 3 +- .../go/prompty/model/parser_config_test.go | 3 +- .../model/permission_completed_payload.go | 3 +- .../permission_completed_payload_test.go | 3 +- .../go/prompty/model/permission_decision.go | 3 +- .../prompty/model/permission_decision_test.go | 3 +- .../go/prompty/model/permission_request.go | 3 +- .../prompty/model/permission_request_test.go | 3 +- .../model/permission_requested_payload.go | 3 +- .../permission_requested_payload_test.go | 3 +- .../go/prompty/model/permission_resolver.go | 3 +- runtime/go/prompty/model/processor.go | 3 +- runtime/go/prompty/model/prompty.go | 3 +- runtime/go/prompty/model/prompty_test.go | 3 +- runtime/go/prompty/model/prompty_tool_test.go | 3 +- runtime/go/prompty/model/property.go | 3 +- runtime/go/prompty/model/property_test.go | 3 +- runtime/go/prompty/model/redacted_field.go | 3 +- .../go/prompty/model/redacted_field_test.go | 3 +- .../go/prompty/model/redaction_metadata.go | 3 +- .../prompty/model/redaction_metadata_test.go | 3 +- .../model/reference_connection_test.go | 3 +- .../prompty/model/remote_connection_test.go | 3 +- runtime/go/prompty/model/renderer.go | 3 +- runtime/go/prompty/model/retry_payload.go | 3 +- .../go/prompty/model/retry_payload_test.go | 3 +- .../go/prompty/model/session_end_payload.go | 3 +- .../prompty/model/session_end_payload_test.go | 3 +- runtime/go/prompty/model/session_event.go | 3 +- .../go/prompty/model/session_event_test.go | 3 +- runtime/go/prompty/model/session_file_ref.go | 3 +- .../go/prompty/model/session_file_ref_test.go | 3 +- runtime/go/prompty/model/session_ref.go | 3 +- runtime/go/prompty/model/session_ref_test.go | 3 +- .../go/prompty/model/session_start_payload.go | 3 +- .../model/session_start_payload_test.go | 3 +- runtime/go/prompty/model/session_summary.go | 3 +- .../go/prompty/model/session_summary_test.go | 3 +- runtime/go/prompty/model/session_trace.go | 3 +- .../go/prompty/model/session_trace_test.go | 3 +- .../prompty/model/session_warning_payload.go | 3 +- .../model/session_warning_payload_test.go | 3 +- .../go/prompty/model/status_event_payload.go | 3 +- .../model/status_event_payload_test.go | 3 +- runtime/go/prompty/model/stream_chunk.go | 3 +- runtime/go/prompty/model/stream_chunk_test.go | 3 +- runtime/go/prompty/model/stream_options.go | 3 +- .../go/prompty/model/stream_options_test.go | 3 +- runtime/go/prompty/model/template.go | 3 +- runtime/go/prompty/model/template_test.go | 3 +- runtime/go/prompty/model/text_chunk_test.go | 3 +- runtime/go/prompty/model/text_part_test.go | 3 +- .../go/prompty/model/thinking_chunk_test.go | 3 +- .../prompty/model/thinking_event_payload.go | 3 +- .../model/thinking_event_payload_test.go | 3 +- runtime/go/prompty/model/thread_marker.go | 3 +- .../go/prompty/model/thread_marker_test.go | 3 +- .../go/prompty/model/token_event_payload.go | 3 +- .../prompty/model/token_event_payload_test.go | 3 +- runtime/go/prompty/model/token_usage.go | 3 +- runtime/go/prompty/model/token_usage_test.go | 3 +- runtime/go/prompty/model/tool.go | 3 +- runtime/go/prompty/model/tool_call.go | 3 +- .../model/tool_call_complete_payload.go | 3 +- .../model/tool_call_complete_payload_test.go | 3 +- .../prompty/model/tool_call_start_payload.go | 3 +- .../model/tool_call_start_payload_test.go | 3 +- runtime/go/prompty/model/tool_call_test.go | 3 +- runtime/go/prompty/model/tool_chunk_test.go | 3 +- runtime/go/prompty/model/tool_context.go | 3 +- runtime/go/prompty/model/tool_context_test.go | 3 +- .../go/prompty/model/tool_dispatch_result.go | 3 +- .../model/tool_dispatch_result_test.go | 3 +- .../model/tool_execution_complete_payload.go | 3 +- .../tool_execution_complete_payload_test.go | 3 +- .../model/tool_execution_start_payload.go | 3 +- .../tool_execution_start_payload_test.go | 3 +- runtime/go/prompty/model/tool_result.go | 3 +- .../go/prompty/model/tool_result_payload.go | 3 +- .../prompty/model/tool_result_payload_test.go | 3 +- runtime/go/prompty/model/tool_result_test.go | 3 +- runtime/go/prompty/model/tool_test.go | 3 +- runtime/go/prompty/model/trace_file.go | 3 +- runtime/go/prompty/model/trace_file_test.go | 3 +- runtime/go/prompty/model/trace_span.go | 3 +- runtime/go/prompty/model/trace_span_test.go | 3 +- runtime/go/prompty/model/trace_time.go | 3 +- runtime/go/prompty/model/trace_time_test.go | 3 +- runtime/go/prompty/model/trajectory_event.go | 3 +- .../go/prompty/model/trajectory_event_test.go | 3 +- runtime/go/prompty/model/turn_end_payload.go | 3 +- .../go/prompty/model/turn_end_payload_test.go | 3 +- runtime/go/prompty/model/turn_event.go | 3 +- runtime/go/prompty/model/turn_event_test.go | 3 +- runtime/go/prompty/model/turn_options.go | 3 +- runtime/go/prompty/model/turn_options_test.go | 3 +- .../go/prompty/model/turn_start_payload.go | 3 +- .../prompty/model/turn_start_payload_test.go | 3 +- runtime/go/prompty/model/turn_summary.go | 3 +- runtime/go/prompty/model/turn_summary_test.go | 3 +- runtime/go/prompty/model/turn_trace.go | 3 +- runtime/go/prompty/model/turn_trace_test.go | 3 +- runtime/go/prompty/model/validation_error.go | 3 +- .../go/prompty/model/validation_error_test.go | 3 +- runtime/go/prompty/model/validation_result.go | 3 +- .../prompty/model/validation_result_test.go | 3 +- .../python/prompty/prompty/model/__init__.py | 1 + .../python/prompty/prompty/model/_context.py | 3 +- .../prompty/model/agent/_GuardrailResult.py | 1 + .../prompty/prompty/model/agent/_Prompty.py | 1 + .../prompty/prompty/model/agent/__init__.py | 1 + .../prompty/model/connection/_Connection.py | 1 + .../prompty/model/connection/__init__.py | 1 + .../model/conversation/_ContentPart.py | 1 + .../prompty/model/conversation/_Message.py | 1 + .../model/conversation/_ThreadMarker.py | 1 + .../prompty/model/conversation/_ToolCall.py | 1 + .../prompty/model/conversation/_ToolResult.py | 1 + .../prompty/model/conversation/__init__.py | 1 + .../prompty/model/core/_FileNotFoundError.py | 1 + .../prompty/model/core/_InvokerError.py | 1 + .../prompty/prompty/model/core/_Property.py | 1 + .../prompty/model/core/_ValidationError.py | 1 + .../prompty/model/core/_ValidationResult.py | 1 + .../prompty/prompty/model/core/__init__.py | 1 + .../prompty/model/events/_Checkpoint.py | 1 + .../events/_CompactionCompletePayload.py | 1 + .../model/events/_CompactionFailedPayload.py | 1 + .../model/events/_CompactionStartPayload.py | 1 + .../prompty/model/events/_DoneEventPayload.py | 1 + .../model/events/_ErrorEventPayload.py | 1 + .../prompty/model/events/_HarnessContext.py | 1 + .../prompty/model/events/_HookEndPayload.py | 1 + .../prompty/model/events/_HookStartPayload.py | 1 + .../prompty/model/events/_HostToolRequest.py | 1 + .../prompty/model/events/_HostToolResult.py | 1 + .../model/events/_LlmCompletePayload.py | 1 + .../prompty/model/events/_LlmStartPayload.py | 1 + .../model/events/_MessagesUpdatedPayload.py | 1 + .../events/_PermissionCompletedPayload.py | 1 + .../model/events/_PermissionDecision.py | 1 + .../model/events/_PermissionRequest.py | 1 + .../events/_PermissionRequestedPayload.py | 1 + .../prompty/model/events/_RedactedField.py | 1 + .../model/events/_RedactionMetadata.py | 1 + .../prompty/model/events/_RetryPayload.py | 1 + .../model/events/_SessionEndPayload.py | 1 + .../prompty/model/events/_SessionEvent.py | 1 + .../prompty/model/events/_SessionFileRef.py | 1 + .../prompty/model/events/_SessionRef.py | 1 + .../model/events/_SessionStartPayload.py | 1 + .../prompty/model/events/_SessionSummary.py | 1 + .../prompty/model/events/_SessionTrace.py | 1 + .../model/events/_SessionWarningPayload.py | 1 + .../model/events/_StatusEventPayload.py | 1 + .../prompty/model/events/_StreamChunk.py | 1 + .../model/events/_ThinkingEventPayload.py | 1 + .../model/events/_TokenEventPayload.py | 1 + .../model/events/_ToolCallCompletePayload.py | 1 + .../model/events/_ToolCallStartPayload.py | 1 + .../events/_ToolExecutionCompletePayload.py | 1 + .../events/_ToolExecutionStartPayload.py | 1 + .../model/events/_ToolResultPayload.py | 1 + .../prompty/model/events/_TrajectoryEvent.py | 1 + .../prompty/model/events/_TurnEndPayload.py | 1 + .../prompty/model/events/_TurnEvent.py | 1 + .../prompty/model/events/_TurnStartPayload.py | 1 + .../prompty/model/events/_TurnSummary.py | 1 + .../prompty/model/events/_TurnTrace.py | 1 + .../prompty/prompty/model/events/__init__.py | 1 + .../prompty/prompty/model/model/_Model.py | 1 + .../prompty/prompty/model/model/_ModelInfo.py | 1 + .../prompty/model/model/_ModelOptions.py | 1 + .../prompty/model/model/_TokenUsage.py | 1 + .../prompty/prompty/model/model/__init__.py | 1 + .../model/pipeline/_CheckpointStore.py | 1 + .../model/pipeline/_CompactionConfig.py | 1 + .../model/pipeline/_EventJournalWriter.py | 1 + .../prompty/model/pipeline/_EventSink.py | 1 + .../prompty/model/pipeline/_Executor.py | 1 + .../model/pipeline/_HostToolExecutor.py | 1 + .../prompty/prompty/model/pipeline/_Parser.py | 1 + .../model/pipeline/_PermissionResolver.py | 1 + .../prompty/model/pipeline/_Processor.py | 1 + .../prompty/model/pipeline/_Renderer.py | 1 + .../prompty/model/pipeline/_TurnOptions.py | 1 + .../prompty/model/pipeline/__init__.py | 1 + runtime/python/prompty/prompty/model/py.typed | 1 + .../prompty/model/streaming/_StreamOptions.py | 1 + .../prompty/model/streaming/__init__.py | 1 + .../prompty/model/template/_FormatConfig.py | 1 + .../prompty/model/template/_ParserConfig.py | 1 + .../prompty/model/template/_Template.py | 1 + .../prompty/model/template/__init__.py | 1 + .../prompty/prompty/model/tools/_Binding.py | 1 + .../prompty/model/tools/_McpApprovalMode.py | 1 + .../prompty/prompty/model/tools/_Tool.py | 1 + .../prompty/model/tools/_ToolContext.py | 1 + .../model/tools/_ToolDispatchResult.py | 1 + .../prompty/prompty/model/tools/__init__.py | 1 + .../prompty/model/tracing/_TraceFile.py | 1 + .../prompty/model/tracing/_TraceSpan.py | 1 + .../prompty/model/tracing/_TraceTime.py | 1 + .../prompty/prompty/model/tracing/__init__.py | 1 + .../model/wire/_AnthropicImageBlock.py | 1 + .../model/wire/_AnthropicImageSource.py | 1 + .../model/wire/_AnthropicMessagesRequest.py | 1 + .../model/wire/_AnthropicMessagesResponse.py | 1 + .../prompty/model/wire/_AnthropicTextBlock.py | 1 + .../model/wire/_AnthropicToolDefinition.py | 1 + .../model/wire/_AnthropicToolResultBlock.py | 1 + .../model/wire/_AnthropicToolUseBlock.py | 1 + .../prompty/model/wire/_AnthropicUsage.py | 1 + .../model/wire/_AnthropicWireMessage.py | 1 + .../prompty/prompty/model/wire/__init__.py | 1 + .../model/agent/test_guardrail_result.py | 1 + .../prompty/tests/model/agent/test_prompty.py | 1 + .../connection/test_anonymous_connection.py | 1 + .../connection/test_api_key_connection.py | 1 + .../tests/model/connection/test_connection.py | 1 + .../connection/test_foundry_connection.py | 1 + .../connection/test_o_auth_connection.py | 1 + .../connection/test_reference_connection.py | 1 + .../connection/test_remote_connection.py | 1 + .../model/conversation/test_audio_part.py | 1 + .../model/conversation/test_content_part.py | 1 + .../model/conversation/test_file_part.py | 1 + .../model/conversation/test_image_part.py | 1 + .../tests/model/conversation/test_message.py | 1 + .../model/conversation/test_text_part.py | 1 + .../model/conversation/test_thread_marker.py | 1 + .../model/conversation/test_tool_call.py | 1 + .../model/conversation/test_tool_result.py | 1 + .../tests/model/core/test_array_property.py | 1 + .../model/core/test_file_not_found_error.py | 1 + .../tests/model/core/test_invoker_error.py | 1 + .../tests/model/core/test_object_property.py | 1 + .../prompty/tests/model/core/test_property.py | 1 + .../tests/model/core/test_validation_error.py | 1 + .../model/core/test_validation_result.py | 1 + .../tests/model/events/test_checkpoint.py | 1 + .../test_compaction_complete_payload.py | 1 + .../events/test_compaction_failed_payload.py | 1 + .../events/test_compaction_start_payload.py | 1 + .../model/events/test_done_event_payload.py | 1 + .../tests/model/events/test_error_chunk.py | 1 + .../model/events/test_error_event_payload.py | 1 + .../model/events/test_harness_context.py | 1 + .../model/events/test_hook_end_payload.py | 1 + .../model/events/test_hook_start_payload.py | 1 + .../model/events/test_host_tool_request.py | 1 + .../model/events/test_host_tool_result.py | 1 + .../model/events/test_llm_complete_payload.py | 1 + .../model/events/test_llm_start_payload.py | 1 + .../events/test_messages_updated_payload.py | 1 + .../test_permission_completed_payload.py | 1 + .../model/events/test_permission_decision.py | 1 + .../model/events/test_permission_request.py | 1 + .../test_permission_requested_payload.py | 1 + .../tests/model/events/test_redacted_field.py | 1 + .../model/events/test_redaction_metadata.py | 1 + .../tests/model/events/test_retry_payload.py | 1 + .../model/events/test_session_end_payload.py | 1 + .../tests/model/events/test_session_event.py | 1 + .../model/events/test_session_file_ref.py | 1 + .../tests/model/events/test_session_ref.py | 1 + .../events/test_session_start_payload.py | 1 + .../model/events/test_session_summary.py | 1 + .../tests/model/events/test_session_trace.py | 1 + .../events/test_session_warning_payload.py | 1 + .../model/events/test_status_event_payload.py | 1 + .../tests/model/events/test_stream_chunk.py | 1 + .../tests/model/events/test_text_chunk.py | 1 + .../tests/model/events/test_thinking_chunk.py | 1 + .../events/test_thinking_event_payload.py | 1 + .../model/events/test_token_event_payload.py | 1 + .../events/test_tool_call_complete_payload.py | 1 + .../events/test_tool_call_start_payload.py | 1 + .../tests/model/events/test_tool_chunk.py | 1 + .../test_tool_execution_complete_payload.py | 1 + .../test_tool_execution_start_payload.py | 1 + .../model/events/test_tool_result_payload.py | 1 + .../model/events/test_trajectory_event.py | 1 + .../model/events/test_turn_end_payload.py | 1 + .../tests/model/events/test_turn_event.py | 1 + .../model/events/test_turn_start_payload.py | 1 + .../tests/model/events/test_turn_summary.py | 1 + .../tests/model/events/test_turn_trace.py | 1 + .../prompty/tests/model/model/test_model.py | 1 + .../tests/model/model/test_model_info.py | 1 + .../tests/model/model/test_model_options.py | 1 + .../tests/model/model/test_token_usage.py | 1 + .../model/pipeline/test_compaction_config.py | 1 + .../tests/model/pipeline/test_turn_options.py | 1 + .../model/streaming/test_stream_options.py | 1 + .../model/template/test_format_config.py | 1 + .../model/template/test_parser_config.py | 1 + .../tests/model/template/test_template.py | 1 + .../prompty/tests/model/test_context.py | 3 +- .../prompty/tests/model/tools/test_binding.py | 1 + .../tests/model/tools/test_custom_tool.py | 1 + .../tests/model/tools/test_function_tool.py | 1 + .../model/tools/test_mcp_approval_mode.py | 1 + .../tests/model/tools/test_mcp_tool.py | 1 + .../tests/model/tools/test_open_api_tool.py | 1 + .../tests/model/tools/test_prompty_tool.py | 1 + .../prompty/tests/model/tools/test_tool.py | 1 + .../tests/model/tools/test_tool_context.py | 1 + .../model/tools/test_tool_dispatch_result.py | 1 + .../tests/model/tracing/test_trace_file.py | 1 + .../tests/model/tracing/test_trace_span.py | 1 + .../tests/model/tracing/test_trace_time.py | 1 + .../model/wire/test_anthropic_image_block.py | 1 + .../model/wire/test_anthropic_image_source.py | 1 + .../wire/test_anthropic_messages_request.py | 1 + .../wire/test_anthropic_messages_response.py | 1 + .../model/wire/test_anthropic_text_block.py | 1 + .../wire/test_anthropic_tool_definition.py | 1 + .../wire/test_anthropic_tool_result_block.py | 1 + .../wire/test_anthropic_tool_use_block.py | 1 + .../tests/model/wire/test_anthropic_usage.py | 1 + .../model/wire/test_anthropic_wire_message.py | 1 + runtime/rust/prompty/src/harness.rs | 11 +- .../src/model/agent/guardrail_result.rs | 38 +- runtime/rust/prompty/src/model/agent/mod.rs | 11 +- .../rust/prompty/src/model/agent/prompty.rs | 219 +- .../src/model/connection/connection.rs | 205 +- .../rust/prompty/src/model/connection/mod.rs | 11 +- runtime/rust/prompty/src/model/context.rs | 17 +- .../src/model/conversation/content_part.rs | 117 +- .../prompty/src/model/conversation/message.rs | 77 +- .../prompty/src/model/conversation/mod.rs | 11 +- .../src/model/conversation/thread_marker.rs | 33 +- .../src/model/conversation/tool_call.rs | 39 +- .../src/model/conversation/tool_result.rs | 80 +- .../src/model/core/file_not_found_error.rs | 33 +- .../prompty/src/model/core/invoker_error.rs | 44 +- runtime/rust/prompty/src/model/core/mod.rs | 11 +- .../rust/prompty/src/model/core/property.rs | 113 +- .../src/model/core/validation_error.rs | 44 +- .../src/model/core/validation_result.rs | 38 +- .../prompty/src/model/events/checkpoint.rs | 98 +- .../events/compaction_complete_payload.rs | 31 +- .../model/events/compaction_failed_payload.rs | 22 +- .../model/events/compaction_start_payload.rs | 21 +- .../src/model/events/done_event_payload.rs | 43 +- .../src/model/events/error_event_payload.rs | 37 +- .../src/model/events/harness_context.rs | 32 +- .../src/model/events/hook_end_payload.rs | 71 +- .../src/model/events/hook_start_payload.rs | 54 +- .../src/model/events/host_tool_request.rs | 58 +- .../src/model/events/host_tool_result.rs | 80 +- .../src/model/events/llm_complete_payload.rs | 43 +- .../src/model/events/llm_start_payload.rs | 51 +- .../model/events/messages_updated_payload.rs | 80 +- runtime/rust/prompty/src/model/events/mod.rs | 13 +- .../events/permission_completed_payload.rs | 68 +- .../src/model/events/permission_decision.rs | 63 +- .../src/model/events/permission_request.rs | 68 +- .../events/permission_requested_payload.rs | 73 +- .../src/model/events/redacted_field.rs | 38 +- .../src/model/events/redaction_metadata.rs | 38 +- .../prompty/src/model/events/retry_payload.rs | 49 +- .../src/model/events/session_end_payload.rs | 43 +- .../prompty/src/model/events/session_event.rs | 80 +- .../src/model/events/session_file_ref.rs | 62 +- .../prompty/src/model/events/session_ref.rs | 63 +- .../src/model/events/session_start_payload.rs | 97 +- .../src/model/events/session_summary.rs | 64 +- .../prompty/src/model/events/session_trace.rs | 199 +- .../model/events/session_warning_payload.rs | 39 +- .../src/model/events/status_event_payload.rs | 22 +- .../prompty/src/model/events/stream_chunk.rs | 76 +- .../model/events/thinking_event_payload.rs | 22 +- .../src/model/events/token_event_payload.rs | 22 +- .../events/tool_call_complete_payload.rs | 54 +- .../model/events/tool_call_start_payload.rs | 38 +- .../events/tool_execution_complete_payload.rs | 85 +- .../events/tool_execution_start_payload.rs | 63 +- .../src/model/events/tool_result_payload.rs | 28 +- .../src/model/events/trajectory_event.rs | 83 +- .../src/model/events/turn_end_payload.rs | 38 +- .../prompty/src/model/events/turn_event.rs | 75 +- .../src/model/events/turn_start_payload.rs | 32 +- .../prompty/src/model/events/turn_summary.rs | 85 +- .../prompty/src/model/events/turn_trace.rs | 69 +- runtime/rust/prompty/src/model/mod.rs | 13 +- runtime/rust/prompty/src/model/model/mod.rs | 11 +- runtime/rust/prompty/src/model/model/model.rs | 52 +- .../prompty/src/model/model/model_info.rs | 90 +- .../prompty/src/model/model/model_options.rs | 177 +- .../prompty/src/model/model/token_usage.rs | 67 +- .../src/model/pipeline/checkpoint_store.rs | 28 +- .../src/model/pipeline/compaction_config.rs | 37 +- .../model/pipeline/event_journal_writer.rs | 12 +- .../prompty/src/model/pipeline/event_sink.rs | 12 +- .../prompty/src/model/pipeline/executor.rs | 32 +- .../src/model/pipeline/host_tool_executor.rs | 17 +- .../rust/prompty/src/model/pipeline/mod.rs | 13 +- .../rust/prompty/src/model/pipeline/parser.rs | 19 +- .../src/model/pipeline/permission_resolver.rs | 17 +- .../prompty/src/model/pipeline/processor.rs | 23 +- .../prompty/src/model/pipeline/renderer.rs | 19 +- .../src/model/pipeline/turn_options.rs | 56 +- .../rust/prompty/src/model/streaming/mod.rs | 11 +- .../src/model/streaming/stream_options.rs | 11 +- .../src/model/template/format_config.rs | 33 +- .../rust/prompty/src/model/template/mod.rs | 11 +- .../src/model/template/parser_config.rs | 33 +- .../prompty/src/model/template/template.rs | 23 +- .../rust/prompty/src/model/tools/binding.rs | 38 +- .../src/model/tools/mcp_approval_mode.rs | 56 +- runtime/rust/prompty/src/model/tools/mod.rs | 11 +- runtime/rust/prompty/src/model/tools/tool.rs | 248 +- .../prompty/src/model/tools/tool_context.rs | 44 +- .../src/model/tools/tool_dispatch_result.rs | 39 +- runtime/rust/prompty/src/model/tracing/mod.rs | 11 +- .../prompty/src/model/tracing/trace_file.rs | 39 +- .../prompty/src/model/tracing/trace_span.rs | 69 +- .../prompty/src/model/tracing/trace_time.rs | 45 +- .../src/model/wire/anthropic_image_block.rs | 28 +- .../src/model/wire/anthropic_image_source.rs | 44 +- .../model/wire/anthropic_messages_request.rs | 176 +- .../model/wire/anthropic_messages_response.rs | 78 +- .../src/model/wire/anthropic_text_block.rs | 33 +- .../model/wire/anthropic_tool_definition.rs | 38 +- .../model/wire/anthropic_tool_result_block.rs | 44 +- .../model/wire/anthropic_tool_use_block.rs | 45 +- .../prompty/src/model/wire/anthropic_usage.rs | 31 +- .../src/model/wire/anthropic_wire_message.rs | 33 +- runtime/rust/prompty/src/model/wire/mod.rs | 13 +- .../rust/prompty/tests/harness_adapters.rs | 5 +- .../model/agent/guardrail_result_test.rs | 29 +- runtime/rust/prompty/tests/model/agent/mod.rs | 13 +- .../prompty/tests/model/agent/prompty_test.rs | 475 ++- .../tests/model/connection/connection_test.rs | 25 +- .../prompty/tests/model/connection/mod.rs | 11 +- .../model/conversation/content_part_test.rs | 11 +- .../tests/model/conversation/message_test.rs | 29 +- .../prompty/tests/model/conversation/mod.rs | 15 +- .../model/conversation/thread_marker_test.rs | 29 +- .../model/conversation/tool_call_test.rs | 29 +- .../model/conversation/tool_result_test.rs | 64 +- .../model/core/file_not_found_error_test.rs | 29 +- .../tests/model/core/invoker_error_test.rs | 29 +- runtime/rust/prompty/tests/model/core/mod.rs | 15 +- .../prompty/tests/model/core/property_test.rs | 23 +- .../tests/model/core/validation_error_test.rs | 29 +- .../model/core/validation_result_test.rs | 29 +- .../tests/model/events/checkpoint_test.rs | 64 +- .../compaction_complete_payload_test.rs | 39 +- .../events/compaction_failed_payload_test.rs | 39 +- .../events/compaction_start_payload_test.rs | 29 +- .../model/events/done_event_payload_test.rs | 11 +- .../model/events/error_event_payload_test.rs | 39 +- .../model/events/harness_context_test.rs | 29 +- .../model/events/hook_end_payload_test.rs | 39 +- .../model/events/hook_start_payload_test.rs | 29 +- .../model/events/host_tool_request_test.rs | 64 +- .../model/events/host_tool_result_test.rs | 79 +- .../model/events/llm_complete_payload_test.rs | 59 +- .../model/events/llm_start_payload_test.rs | 39 +- .../events/messages_updated_payload_test.rs | 29 +- .../rust/prompty/tests/model/events/mod.rs | 79 +- .../permission_completed_payload_test.rs | 49 +- .../model/events/permission_decision_test.rs | 49 +- .../model/events/permission_request_test.rs | 64 +- .../permission_requested_payload_test.rs | 64 +- .../tests/model/events/redacted_field_test.rs | 29 +- .../model/events/redaction_metadata_test.rs | 39 +- .../tests/model/events/retry_payload_test.rs | 39 +- .../model/events/session_end_payload_test.rs | 54 +- .../tests/model/events/session_event_test.rs | 49 +- .../model/events/session_file_ref_test.rs | 74 +- .../tests/model/events/session_ref_test.rs | 64 +- .../events/session_start_payload_test.rs | 84 +- .../model/events/session_summary_test.rs | 54 +- .../tests/model/events/session_trace_test.rs | 49 +- .../events/session_warning_payload_test.rs | 29 +- .../model/events/status_event_payload_test.rs | 29 +- .../tests/model/events/stream_chunk_test.rs | 11 +- .../events/thinking_event_payload_test.rs | 29 +- .../model/events/token_event_payload_test.rs | 29 +- .../events/tool_call_complete_payload_test.rs | 49 +- .../events/tool_call_start_payload_test.rs | 29 +- .../tool_execution_complete_payload_test.rs | 79 +- .../tool_execution_start_payload_test.rs | 64 +- .../model/events/tool_result_payload_test.rs | 29 +- .../model/events/trajectory_event_test.rs | 74 +- .../model/events/turn_end_payload_test.rs | 49 +- .../tests/model/events/turn_event_test.rs | 49 +- .../model/events/turn_start_payload_test.rs | 39 +- .../tests/model/events/turn_summary_test.rs | 59 +- .../tests/model/events/turn_trace_test.rs | 39 +- runtime/rust/prompty/tests/model/main.rs | 11 +- runtime/rust/prompty/tests/model/model/mod.rs | 13 +- .../tests/model/model/model_info_test.rs | 49 +- .../tests/model/model/model_options_test.rs | 79 +- .../prompty/tests/model/model/model_test.rs | 29 +- .../tests/model/model/token_usage_test.rs | 59 +- .../model/pipeline/compaction_config_test.rs | 29 +- .../rust/prompty/tests/model/pipeline/mod.rs | 11 +- .../tests/model/pipeline/turn_options_test.rs | 69 +- .../rust/prompty/tests/model/streaming/mod.rs | 11 +- .../model/streaming/stream_options_test.rs | 39 +- .../model/template/format_config_test.rs | 23 +- .../rust/prompty/tests/model/template/mod.rs | 11 +- .../model/template/parser_config_test.rs | 23 +- .../tests/model/template/template_test.rs | 29 +- .../prompty/tests/model/tools/binding_test.rs | 29 +- .../model/tools/mcp_approval_mode_test.rs | 31 +- runtime/rust/prompty/tests/model/tools/mod.rs | 13 +- .../tests/model/tools/tool_context_test.rs | 29 +- .../model/tools/tool_dispatch_result_test.rs | 29 +- .../prompty/tests/model/tools/tool_test.rs | 23 +- .../rust/prompty/tests/model/tracing/mod.rs | 15 +- .../tests/model/tracing/trace_file_test.rs | 29 +- .../tests/model/tracing/trace_span_test.rs | 44 +- .../tests/model/tracing/trace_time_test.rs | 29 +- .../model/wire/anthropic_image_block_test.rs | 11 +- .../model/wire/anthropic_image_source_test.rs | 29 +- .../wire/anthropic_messages_request_test.rs | 44 +- .../wire/anthropic_messages_response_test.rs | 29 +- .../model/wire/anthropic_text_block_test.rs | 29 +- .../wire/anthropic_tool_definition_test.rs | 44 +- .../wire/anthropic_tool_result_block_test.rs | 29 +- .../wire/anthropic_tool_use_block_test.rs | 29 +- .../tests/model/wire/anthropic_usage_test.rs | 29 +- .../model/wire/anthropic_wire_message_test.rs | 29 +- runtime/rust/prompty/tests/model/wire/mod.rs | 25 +- .../core/src/model/agent/guardrail-result.ts | 1 + .../packages/core/src/model/agent/index.ts | 1 + .../packages/core/src/model/agent/prompty.ts | 1 + .../core/src/model/connection/connection.ts | 1 + .../core/src/model/connection/index.ts | 1 + .../packages/core/src/model/context.ts | 1 + .../src/model/conversation/content-part.ts | 1 + .../core/src/model/conversation/index.ts | 1 + .../core/src/model/conversation/message.ts | 1 + .../src/model/conversation/thread-marker.ts | 1 + .../core/src/model/conversation/tool-call.ts | 1 + .../src/model/conversation/tool-result.ts | 1 + .../src/model/core/file-not-found-error.ts | 1 + .../packages/core/src/model/core/index.ts | 1 + .../core/src/model/core/invoker-error.ts | 1 + .../packages/core/src/model/core/property.ts | 1 + .../core/src/model/core/validation-error.ts | 1 + .../core/src/model/core/validation-result.ts | 1 + .../core/src/model/events/checkpoint.ts | 1 + .../events/compaction-complete-payload.ts | 1 + .../model/events/compaction-failed-payload.ts | 1 + .../model/events/compaction-start-payload.ts | 1 + .../src/model/events/done-event-payload.ts | 1 + .../src/model/events/error-event-payload.ts | 1 + .../core/src/model/events/harness-context.ts | 1 + .../core/src/model/events/hook-end-payload.ts | 1 + .../src/model/events/hook-start-payload.ts | 1 + .../src/model/events/host-tool-request.ts | 1 + .../core/src/model/events/host-tool-result.ts | 1 + .../packages/core/src/model/events/index.ts | 1 + .../src/model/events/llm-complete-payload.ts | 1 + .../src/model/events/llm-start-payload.ts | 1 + .../model/events/messages-updated-payload.ts | 1 + .../events/permission-completed-payload.ts | 1 + .../src/model/events/permission-decision.ts | 1 + .../src/model/events/permission-request.ts | 1 + .../events/permission-requested-payload.ts | 1 + .../core/src/model/events/redacted-field.ts | 1 + .../src/model/events/redaction-metadata.ts | 1 + .../core/src/model/events/retry-payload.ts | 1 + .../src/model/events/session-end-payload.ts | 1 + .../core/src/model/events/session-event.ts | 1 + .../core/src/model/events/session-file-ref.ts | 1 + .../core/src/model/events/session-ref.ts | 1 + .../src/model/events/session-start-payload.ts | 1 + .../core/src/model/events/session-summary.ts | 1 + .../core/src/model/events/session-trace.ts | 1 + .../model/events/session-warning-payload.ts | 1 + .../src/model/events/status-event-payload.ts | 1 + .../core/src/model/events/stream-chunk.ts | 1 + .../model/events/thinking-event-payload.ts | 1 + .../src/model/events/token-event-payload.ts | 1 + .../events/tool-call-complete-payload.ts | 1 + .../model/events/tool-call-start-payload.ts | 1 + .../events/tool-execution-complete-payload.ts | 1 + .../events/tool-execution-start-payload.ts | 1 + .../src/model/events/tool-result-payload.ts | 1 + .../core/src/model/events/trajectory-event.ts | 1 + .../core/src/model/events/turn-end-payload.ts | 1 + .../core/src/model/events/turn-event.ts | 1 + .../src/model/events/turn-start-payload.ts | 1 + .../core/src/model/events/turn-summary.ts | 1 + .../core/src/model/events/turn-trace.ts | 1 + .../packages/core/src/model/index.ts | 1 + .../packages/core/src/model/model/index.ts | 1 + .../core/src/model/model/model-info.ts | 1 + .../core/src/model/model/model-options.ts | 1 + .../packages/core/src/model/model/model.ts | 1 + .../core/src/model/model/token-usage.ts | 1 + .../src/model/pipeline/checkpoint-store.ts | 1 + .../src/model/pipeline/compaction-config.ts | 1 + .../model/pipeline/event-journal-writer.ts | 1 + .../core/src/model/pipeline/event-sink.ts | 1 + .../core/src/model/pipeline/executor.ts | 1 + .../src/model/pipeline/host-tool-executor.ts | 1 + .../packages/core/src/model/pipeline/index.ts | 1 + .../core/src/model/pipeline/parser.ts | 1 + .../src/model/pipeline/permission-resolver.ts | 1 + .../core/src/model/pipeline/processor.ts | 1 + .../core/src/model/pipeline/renderer.ts | 1 + .../core/src/model/pipeline/turn-options.ts | 1 + .../core/src/model/streaming/index.ts | 1 + .../src/model/streaming/stream-options.ts | 1 + .../core/src/model/template/format-config.ts | 1 + .../packages/core/src/model/template/index.ts | 1 + .../core/src/model/template/parser-config.ts | 1 + .../core/src/model/template/template.ts | 1 + .../packages/core/src/model/tools/binding.ts | 1 + .../packages/core/src/model/tools/index.ts | 1 + .../core/src/model/tools/mcp-approval-mode.ts | 1 + .../core/src/model/tools/tool-context.ts | 1 + .../src/model/tools/tool-dispatch-result.ts | 1 + .../packages/core/src/model/tools/tool.ts | 1 + .../packages/core/src/model/tracing/index.ts | 1 + .../core/src/model/tracing/trace-file.ts | 1 + .../core/src/model/tracing/trace-span.ts | 1 + .../core/src/model/tracing/trace-time.ts | 1 + .../src/model/wire/anthropic-image-block.ts | 1 + .../src/model/wire/anthropic-image-source.ts | 1 + .../model/wire/anthropic-messages-request.ts | 1 + .../model/wire/anthropic-messages-response.ts | 1 + .../src/model/wire/anthropic-text-block.ts | 1 + .../model/wire/anthropic-tool-definition.ts | 1 + .../model/wire/anthropic-tool-result-block.ts | 1 + .../model/wire/anthropic-tool-use-block.ts | 1 + .../core/src/model/wire/anthropic-usage.ts | 1 + .../src/model/wire/anthropic-wire-message.ts | 1 + .../packages/core/src/model/wire/index.ts | 1 + .../model/agent/guardrail-result.test.ts | 1 + .../core/tests/model/agent/prompty.test.ts | 1 + .../connection/anonymous-connection.test.ts | 1 + .../connection/api-key-connection.test.ts | 1 + .../tests/model/connection/connection.test.ts | 1 + .../connection/foundry-connection.test.ts | 1 + .../connection/o-auth-connection.test.ts | 1 + .../connection/reference-connection.test.ts | 1 + .../connection/remote-connection.test.ts | 1 + .../model/conversation/audio-part.test.ts | 1 + .../model/conversation/content-part.test.ts | 1 + .../model/conversation/file-part.test.ts | 1 + .../model/conversation/image-part.test.ts | 1 + .../tests/model/conversation/message.test.ts | 1 + .../model/conversation/text-part.test.ts | 1 + .../model/conversation/thread-marker.test.ts | 1 + .../model/conversation/tool-call.test.ts | 1 + .../model/conversation/tool-result.test.ts | 1 + .../tests/model/core/array-property.test.ts | 1 + .../model/core/file-not-found-error.test.ts | 1 + .../tests/model/core/invoker-error.test.ts | 1 + .../tests/model/core/object-property.test.ts | 1 + .../core/tests/model/core/property.test.ts | 1 + .../tests/model/core/validation-error.test.ts | 1 + .../model/core/validation-result.test.ts | 1 + .../tests/model/events/checkpoint.test.ts | 1 + .../compaction-complete-payload.test.ts | 1 + .../events/compaction-failed-payload.test.ts | 1 + .../events/compaction-start-payload.test.ts | 1 + .../model/events/done-event-payload.test.ts | 1 + .../tests/model/events/error-chunk.test.ts | 1 + .../model/events/error-event-payload.test.ts | 1 + .../model/events/harness-context.test.ts | 1 + .../model/events/hook-end-payload.test.ts | 1 + .../model/events/hook-start-payload.test.ts | 1 + .../model/events/host-tool-request.test.ts | 1 + .../model/events/host-tool-result.test.ts | 1 + .../model/events/llm-complete-payload.test.ts | 1 + .../model/events/llm-start-payload.test.ts | 1 + .../events/messages-updated-payload.test.ts | 1 + .../permission-completed-payload.test.ts | 1 + .../model/events/permission-decision.test.ts | 1 + .../model/events/permission-request.test.ts | 1 + .../permission-requested-payload.test.ts | 1 + .../tests/model/events/redacted-field.test.ts | 1 + .../model/events/redaction-metadata.test.ts | 1 + .../tests/model/events/retry-payload.test.ts | 1 + .../model/events/session-end-payload.test.ts | 1 + .../tests/model/events/session-event.test.ts | 1 + .../model/events/session-file-ref.test.ts | 1 + .../tests/model/events/session-ref.test.ts | 1 + .../events/session-start-payload.test.ts | 1 + .../model/events/session-summary.test.ts | 1 + .../tests/model/events/session-trace.test.ts | 1 + .../events/session-warning-payload.test.ts | 1 + .../model/events/status-event-payload.test.ts | 1 + .../tests/model/events/stream-chunk.test.ts | 1 + .../tests/model/events/text-chunk.test.ts | 1 + .../tests/model/events/thinking-chunk.test.ts | 1 + .../events/thinking-event-payload.test.ts | 1 + .../model/events/token-event-payload.test.ts | 1 + .../events/tool-call-complete-payload.test.ts | 1 + .../events/tool-call-start-payload.test.ts | 1 + .../tests/model/events/tool-chunk.test.ts | 1 + .../tool-execution-complete-payload.test.ts | 1 + .../tool-execution-start-payload.test.ts | 1 + .../model/events/tool-result-payload.test.ts | 1 + .../model/events/trajectory-event.test.ts | 1 + .../model/events/turn-end-payload.test.ts | 1 + .../tests/model/events/turn-event.test.ts | 1 + .../model/events/turn-start-payload.test.ts | 1 + .../tests/model/events/turn-summary.test.ts | 1 + .../tests/model/events/turn-trace.test.ts | 1 + .../core/tests/model/model/model-info.test.ts | 1 + .../tests/model/model/model-options.test.ts | 1 + .../core/tests/model/model/model.test.ts | 1 + .../tests/model/model/token-usage.test.ts | 1 + .../model/pipeline/compaction-config.test.ts | 1 + .../tests/model/pipeline/turn-options.test.ts | 1 + .../model/streaming/stream-options.test.ts | 1 + .../model/template/format-config.test.ts | 1 + .../model/template/parser-config.test.ts | 1 + .../tests/model/template/template.test.ts | 1 + .../core/tests/model/tools/binding.test.ts | 1 + .../tests/model/tools/custom-tool.test.ts | 1 + .../tests/model/tools/function-tool.test.ts | 1 + .../model/tools/mcp-approval-mode.test.ts | 1 + .../core/tests/model/tools/mcp-tool.test.ts | 1 + .../tests/model/tools/open-api-tool.test.ts | 1 + .../tests/model/tools/prompty-tool.test.ts | 1 + .../tests/model/tools/tool-context.test.ts | 1 + .../model/tools/tool-dispatch-result.test.ts | 1 + .../core/tests/model/tools/tool.test.ts | 1 + .../tests/model/tracing/trace-file.test.ts | 1 + .../tests/model/tracing/trace-span.test.ts | 1 + .../tests/model/tracing/trace-time.test.ts | 1 + .../model/wire/anthropic-image-block.test.ts | 1 + .../model/wire/anthropic-image-source.test.ts | 1 + .../wire/anthropic-messages-request.test.ts | 1 + .../wire/anthropic-messages-response.test.ts | 1 + .../model/wire/anthropic-text-block.test.ts | 1 + .../wire/anthropic-tool-definition.test.ts | 1 + .../wire/anthropic-tool-result-block.test.ts | 1 + .../wire/anthropic-tool-use-block.test.ts | 1 + .../tests/model/wire/anthropic-usage.test.ts | 1 + .../model/wire/anthropic-wire-message.test.ts | 1 + schema/model/agent/agent.tsp | 2 +- schema/model/agent/guardrails.tsp | 2 +- schema/model/connection/connection.tsp | 2 +- schema/model/connection/foundry.tsp | 2 +- schema/model/connection/oauth.tsp | 2 +- schema/model/conversation/content.tsp | 2 +- schema/model/conversation/message.tsp | 2 +- schema/model/conversation/thread.tsp | 2 +- schema/model/conversation/tool-invocation.tsp | 2 +- schema/model/core/core.tsp | 2 +- schema/model/core/errors.tsp | 2 +- schema/model/core/properties.tsp | 2 +- schema/model/core/validation.tsp | 2 +- schema/model/events/payloads.tsp | 2 +- schema/model/events/session.tsp | 2 +- schema/model/events/stream-chunks.tsp | 2 +- schema/model/model/discovery.tsp | 2 +- schema/model/model/usage.tsp | 2 +- schema/model/pipeline/executor.tsp | 2 +- schema/model/pipeline/harness.tsp | 2 +- schema/model/pipeline/parser.tsp | 2 +- schema/model/pipeline/processor.tsp | 2 +- schema/model/pipeline/renderer.tsp | 2 +- schema/model/pipeline/turn.tsp | 2 +- schema/model/streaming/stream.tsp | 2 +- schema/model/template/template.tsp | 2 +- schema/model/tools/dispatch.tsp | 2 +- schema/model/tools/tool.tsp | 2 +- schema/model/tracing/tracer.tsp | 2 +- schema/model/wire/anthropic-types.tsp | 2 +- schema/model/wire/anthropic.tsp | 2 +- schema/model/wire/openai.tsp | 2 +- schema/package-lock.json | 3470 ++--------------- schema/package.json | 5 +- schema/tspconfig.yaml | 5 +- .../docs/reference/AnonymousConnection.md | 1 + .../docs/reference/AnthropicImageBlock.md | 1 + .../docs/reference/AnthropicImageSource.md | 1 + .../reference/AnthropicMessagesRequest.md | 1 + .../reference/AnthropicMessagesResponse.md | 1 + .../docs/reference/AnthropicTextBlock.md | 1 + .../docs/reference/AnthropicToolDefinition.md | 1 + .../reference/AnthropicToolResultBlock.md | 1 + .../docs/reference/AnthropicToolUseBlock.md | 1 + .../content/docs/reference/AnthropicUsage.md | 1 + .../docs/reference/AnthropicWireMessage.md | 1 + .../docs/reference/ApiKeyConnection.md | 1 + .../content/docs/reference/ArrayProperty.md | 1 + web/src/content/docs/reference/AudioPart.md | 1 + web/src/content/docs/reference/Binding.md | 1 + web/src/content/docs/reference/Checkpoint.md | 1 + .../content/docs/reference/CheckpointStore.md | 1 + .../reference/CompactionCompletePayload.md | 1 + .../docs/reference/CompactionConfig.md | 1 + .../docs/reference/CompactionFailedPayload.md | 1 + .../docs/reference/CompactionStartPayload.md | 1 + web/src/content/docs/reference/Connection.md | 1 + web/src/content/docs/reference/ContentPart.md | 1 + web/src/content/docs/reference/CustomTool.md | 1 + .../docs/reference/DoneEventPayload.md | 1 + web/src/content/docs/reference/ErrorChunk.md | 1 + .../docs/reference/ErrorEventPayload.md | 1 + .../docs/reference/EventJournalWriter.md | 1 + web/src/content/docs/reference/EventSink.md | 1 + web/src/content/docs/reference/Executor.md | 1 + .../docs/reference/FileNotFoundError.md | 1 + web/src/content/docs/reference/FilePart.md | 1 + .../content/docs/reference/FormatConfig.md | 1 + .../docs/reference/FoundryConnection.md | 1 + .../content/docs/reference/FunctionTool.md | 1 + .../content/docs/reference/GuardrailResult.md | 1 + .../content/docs/reference/HarnessContext.md | 1 + .../content/docs/reference/HookEndPayload.md | 1 + .../docs/reference/HookStartPayload.md | 1 + .../docs/reference/HostToolExecutor.md | 1 + .../content/docs/reference/HostToolRequest.md | 1 + .../content/docs/reference/HostToolResult.md | 1 + web/src/content/docs/reference/ImagePart.md | 1 + .../content/docs/reference/InvokerError.md | 1 + .../docs/reference/LlmCompletePayload.md | 1 + .../content/docs/reference/LlmStartPayload.md | 1 + .../content/docs/reference/McpApprovalMode.md | 1 + web/src/content/docs/reference/McpTool.md | 1 + web/src/content/docs/reference/Message.md | 1 + .../docs/reference/MessagesUpdatedPayload.md | 1 + web/src/content/docs/reference/Model.md | 1 + web/src/content/docs/reference/ModelInfo.md | 1 + .../content/docs/reference/ModelOptions.md | 1 + .../content/docs/reference/OAuthConnection.md | 1 + .../content/docs/reference/ObjectProperty.md | 1 + web/src/content/docs/reference/OpenApiTool.md | 1 + web/src/content/docs/reference/Parser.md | 1 + .../content/docs/reference/ParserConfig.md | 1 + .../reference/PermissionCompletedPayload.md | 1 + .../docs/reference/PermissionDecision.md | 1 + .../docs/reference/PermissionRequest.md | 1 + .../reference/PermissionRequestedPayload.md | 1 + .../docs/reference/PermissionResolver.md | 1 + web/src/content/docs/reference/Processor.md | 1 + web/src/content/docs/reference/Prompty.md | 1 + web/src/content/docs/reference/PromptyTool.md | 1 + web/src/content/docs/reference/Property.md | 1 + .../content/docs/reference/RedactedField.md | 1 + .../docs/reference/RedactionMetadata.md | 1 + .../docs/reference/ReferenceConnection.md | 1 + .../docs/reference/RemoteConnection.md | 1 + web/src/content/docs/reference/Renderer.md | 1 + .../content/docs/reference/RetryPayload.md | 1 + .../docs/reference/SessionEndPayload.md | 1 + .../content/docs/reference/SessionEvent.md | 1 + .../content/docs/reference/SessionFileRef.md | 1 + web/src/content/docs/reference/SessionRef.md | 1 + .../docs/reference/SessionStartPayload.md | 1 + .../content/docs/reference/SessionSummary.md | 1 + .../content/docs/reference/SessionTrace.md | 1 + .../docs/reference/SessionWarningPayload.md | 1 + .../docs/reference/StatusEventPayload.md | 1 + web/src/content/docs/reference/StreamChunk.md | 1 + .../content/docs/reference/StreamOptions.md | 1 + web/src/content/docs/reference/Template.md | 1 + web/src/content/docs/reference/TextChunk.md | 1 + web/src/content/docs/reference/TextPart.md | 1 + .../content/docs/reference/ThinkingChunk.md | 1 + .../docs/reference/ThinkingEventPayload.md | 1 + .../content/docs/reference/ThreadMarker.md | 1 + .../docs/reference/TokenEventPayload.md | 1 + web/src/content/docs/reference/TokenUsage.md | 1 + web/src/content/docs/reference/Tool.md | 1 + web/src/content/docs/reference/ToolCall.md | 1 + .../docs/reference/ToolCallCompletePayload.md | 1 + .../docs/reference/ToolCallStartPayload.md | 1 + web/src/content/docs/reference/ToolChunk.md | 1 + web/src/content/docs/reference/ToolContext.md | 1 + .../docs/reference/ToolDispatchResult.md | 1 + .../reference/ToolExecutionCompletePayload.md | 1 + .../reference/ToolExecutionStartPayload.md | 1 + web/src/content/docs/reference/ToolResult.md | 1 + .../docs/reference/ToolResultPayload.md | 1 + web/src/content/docs/reference/TraceFile.md | 1 + web/src/content/docs/reference/TraceSpan.md | 1 + web/src/content/docs/reference/TraceTime.md | 1 + .../content/docs/reference/TrajectoryEvent.md | 1 + .../content/docs/reference/TurnEndPayload.md | 1 + web/src/content/docs/reference/TurnEvent.md | 1 + web/src/content/docs/reference/TurnOptions.md | 1 + .../docs/reference/TurnStartPayload.md | 1 + web/src/content/docs/reference/TurnSummary.md | 1 + web/src/content/docs/reference/TurnTrace.md | 1 + .../content/docs/reference/ValidationError.md | 1 + .../docs/reference/ValidationResult.md | 1 + web/src/content/docs/reference/index.md | 1 + 1225 files changed, 9881 insertions(+), 6057 deletions(-) diff --git a/runtime/csharp/Prompty.Core.Tests/Model/agent/GuardrailResultConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/agent/GuardrailResultConversionTests.cs index 1f5aa6e3..8417ac6f 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/agent/GuardrailResultConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/agent/GuardrailResultConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/agent/PromptyConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/agent/PromptyConversionTests.cs index 9b6b2548..677aae3a 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/agent/PromptyConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/agent/PromptyConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/connection/AnonymousConnectionConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/connection/AnonymousConnectionConversionTests.cs index 874f9da2..f7213647 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/connection/AnonymousConnectionConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/connection/AnonymousConnectionConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/connection/ApiKeyConnectionConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/connection/ApiKeyConnectionConversionTests.cs index 08653272..c6c0e930 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/connection/ApiKeyConnectionConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/connection/ApiKeyConnectionConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/connection/ConnectionConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/connection/ConnectionConversionTests.cs index a7a2d46d..ec537940 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/connection/ConnectionConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/connection/ConnectionConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/connection/FoundryConnectionConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/connection/FoundryConnectionConversionTests.cs index e8b36bf4..273154e6 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/connection/FoundryConnectionConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/connection/FoundryConnectionConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/connection/OAuthConnectionConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/connection/OAuthConnectionConversionTests.cs index de6b3f4f..01f2f8c6 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/connection/OAuthConnectionConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/connection/OAuthConnectionConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/connection/ReferenceConnectionConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/connection/ReferenceConnectionConversionTests.cs index 09c63f41..35ea856e 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/connection/ReferenceConnectionConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/connection/ReferenceConnectionConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/connection/RemoteConnectionConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/connection/RemoteConnectionConversionTests.cs index 8468e835..b5ddf396 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/connection/RemoteConnectionConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/connection/RemoteConnectionConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/conversation/AudioPartConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/conversation/AudioPartConversionTests.cs index f30c32f9..fbdacb65 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/conversation/AudioPartConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/conversation/AudioPartConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/conversation/ContentPartConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/conversation/ContentPartConversionTests.cs index 148e1f1d..b06bb557 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/conversation/ContentPartConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/conversation/ContentPartConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/conversation/FilePartConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/conversation/FilePartConversionTests.cs index 9d5e98dd..7db42fa5 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/conversation/FilePartConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/conversation/FilePartConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/conversation/ImagePartConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/conversation/ImagePartConversionTests.cs index cbca1f7a..1fb3d388 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/conversation/ImagePartConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/conversation/ImagePartConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/conversation/MessageConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/conversation/MessageConversionTests.cs index aeecbcbd..7fcb2de5 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/conversation/MessageConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/conversation/MessageConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/conversation/TextPartConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/conversation/TextPartConversionTests.cs index 43932a86..8fc11359 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/conversation/TextPartConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/conversation/TextPartConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/conversation/ThreadMarkerConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/conversation/ThreadMarkerConversionTests.cs index 04d59ff4..c5edf1d8 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/conversation/ThreadMarkerConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/conversation/ThreadMarkerConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/conversation/ToolCallConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/conversation/ToolCallConversionTests.cs index d21b2191..9b7fc0f7 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/conversation/ToolCallConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/conversation/ToolCallConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/conversation/ToolResultConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/conversation/ToolResultConversionTests.cs index 2e3d8a99..aaee6c25 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/conversation/ToolResultConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/conversation/ToolResultConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/core/ArrayPropertyConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/core/ArrayPropertyConversionTests.cs index f5c0bd95..0a685540 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/core/ArrayPropertyConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/core/ArrayPropertyConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/core/FileNotFoundErrorConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/core/FileNotFoundErrorConversionTests.cs index 6e7b73a9..e0b6294d 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/core/FileNotFoundErrorConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/core/FileNotFoundErrorConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/core/InvokerErrorConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/core/InvokerErrorConversionTests.cs index f57d39f7..3e1b3a87 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/core/InvokerErrorConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/core/InvokerErrorConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/core/ObjectPropertyConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/core/ObjectPropertyConversionTests.cs index c09c7338..1a7098e2 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/core/ObjectPropertyConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/core/ObjectPropertyConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/core/PropertyConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/core/PropertyConversionTests.cs index 0119ddf9..6ff19c31 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/core/PropertyConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/core/PropertyConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/core/ValidationErrorConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/core/ValidationErrorConversionTests.cs index 99d9e33b..9cb2602c 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/core/ValidationErrorConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/core/ValidationErrorConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/core/ValidationResultConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/core/ValidationResultConversionTests.cs index f8157812..11d70897 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/core/ValidationResultConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/core/ValidationResultConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/CheckpointConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/CheckpointConversionTests.cs index acc514d5..93a9d499 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/CheckpointConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/CheckpointConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/CompactionCompletePayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/CompactionCompletePayloadConversionTests.cs index d9f7f19b..63c74abc 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/CompactionCompletePayloadConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/CompactionCompletePayloadConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/CompactionFailedPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/CompactionFailedPayloadConversionTests.cs index 23093a66..d0dbd17c 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/CompactionFailedPayloadConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/CompactionFailedPayloadConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/CompactionStartPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/CompactionStartPayloadConversionTests.cs index b5cd6584..f7694b70 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/CompactionStartPayloadConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/CompactionStartPayloadConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/DoneEventPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/DoneEventPayloadConversionTests.cs index db467680..e35c00c1 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/DoneEventPayloadConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/DoneEventPayloadConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/ErrorChunkConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/ErrorChunkConversionTests.cs index 16153964..31b0f8a9 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/ErrorChunkConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/ErrorChunkConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/ErrorEventPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/ErrorEventPayloadConversionTests.cs index 4ff13000..86ed0e37 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/ErrorEventPayloadConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/ErrorEventPayloadConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/HarnessContextConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/HarnessContextConversionTests.cs index 456b09e6..d5a60b40 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/HarnessContextConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/HarnessContextConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/HookEndPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/HookEndPayloadConversionTests.cs index 1db0fbf4..aa269b82 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/HookEndPayloadConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/HookEndPayloadConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/HookStartPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/HookStartPayloadConversionTests.cs index eea9705f..5bfed060 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/HookStartPayloadConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/HookStartPayloadConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/HostToolRequestConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/HostToolRequestConversionTests.cs index 1aa26c39..d58ddf87 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/HostToolRequestConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/HostToolRequestConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/HostToolResultConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/HostToolResultConversionTests.cs index babf8990..e503660f 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/HostToolResultConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/HostToolResultConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/LlmCompletePayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/LlmCompletePayloadConversionTests.cs index c9ac152b..8766f3e4 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/LlmCompletePayloadConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/LlmCompletePayloadConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/LlmStartPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/LlmStartPayloadConversionTests.cs index 822ca842..35fde0a5 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/LlmStartPayloadConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/LlmStartPayloadConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/MessagesUpdatedPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/MessagesUpdatedPayloadConversionTests.cs index 5bd6b3f7..8b08f6c1 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/MessagesUpdatedPayloadConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/MessagesUpdatedPayloadConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/PermissionCompletedPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/PermissionCompletedPayloadConversionTests.cs index a99391bd..0571c51f 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/PermissionCompletedPayloadConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/PermissionCompletedPayloadConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/PermissionDecisionConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/PermissionDecisionConversionTests.cs index 4b7c5d0f..559a177a 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/PermissionDecisionConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/PermissionDecisionConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/PermissionRequestConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/PermissionRequestConversionTests.cs index b12e6dcb..34c744c9 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/PermissionRequestConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/PermissionRequestConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/PermissionRequestedPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/PermissionRequestedPayloadConversionTests.cs index 64cd5d0d..5a7018aa 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/PermissionRequestedPayloadConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/PermissionRequestedPayloadConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/RedactedFieldConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/RedactedFieldConversionTests.cs index 64bedd49..4bfe1f7f 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/RedactedFieldConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/RedactedFieldConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/RedactionMetadataConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/RedactionMetadataConversionTests.cs index 26ad0a68..ed02a096 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/RedactionMetadataConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/RedactionMetadataConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/RetryPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/RetryPayloadConversionTests.cs index 0e5cb1d4..8a65c910 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/RetryPayloadConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/RetryPayloadConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/SessionEndPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/SessionEndPayloadConversionTests.cs index 81e97c98..704cead5 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/SessionEndPayloadConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/SessionEndPayloadConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/SessionEventConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/SessionEventConversionTests.cs index 5dfc5057..3998e042 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/SessionEventConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/SessionEventConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/SessionFileRefConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/SessionFileRefConversionTests.cs index 87ade592..34cb804c 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/SessionFileRefConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/SessionFileRefConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/SessionRefConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/SessionRefConversionTests.cs index 7ce209fa..f074aee7 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/SessionRefConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/SessionRefConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/SessionStartPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/SessionStartPayloadConversionTests.cs index 160fc3b3..1816aab7 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/SessionStartPayloadConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/SessionStartPayloadConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/SessionSummaryConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/SessionSummaryConversionTests.cs index e491a160..211e92e4 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/SessionSummaryConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/SessionSummaryConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/SessionTraceConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/SessionTraceConversionTests.cs index 48e12014..fea885d8 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/SessionTraceConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/SessionTraceConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/SessionWarningPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/SessionWarningPayloadConversionTests.cs index fecbf3b0..8cdfdcb2 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/SessionWarningPayloadConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/SessionWarningPayloadConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/StatusEventPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/StatusEventPayloadConversionTests.cs index 1b5ac43e..ec617bb1 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/StatusEventPayloadConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/StatusEventPayloadConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/StreamChunkConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/StreamChunkConversionTests.cs index 16733bb8..2f68fa7d 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/StreamChunkConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/StreamChunkConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/TextChunkConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/TextChunkConversionTests.cs index 97c129ad..fb7a2b63 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/TextChunkConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/TextChunkConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/ThinkingChunkConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/ThinkingChunkConversionTests.cs index 3d2495a8..5b7977e4 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/ThinkingChunkConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/ThinkingChunkConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/ThinkingEventPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/ThinkingEventPayloadConversionTests.cs index 3731ba7d..2916d38b 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/ThinkingEventPayloadConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/ThinkingEventPayloadConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/TokenEventPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/TokenEventPayloadConversionTests.cs index cff968d0..5f8f3e1b 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/TokenEventPayloadConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/TokenEventPayloadConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/ToolCallCompletePayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/ToolCallCompletePayloadConversionTests.cs index b3641edd..256ab85a 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/ToolCallCompletePayloadConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/ToolCallCompletePayloadConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/ToolCallStartPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/ToolCallStartPayloadConversionTests.cs index f4db36e4..b8d098a6 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/ToolCallStartPayloadConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/ToolCallStartPayloadConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/ToolChunkConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/ToolChunkConversionTests.cs index ef3b3c8c..41861996 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/ToolChunkConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/ToolChunkConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/ToolExecutionCompletePayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/ToolExecutionCompletePayloadConversionTests.cs index d4186cd9..8cd34fd9 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/ToolExecutionCompletePayloadConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/ToolExecutionCompletePayloadConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/ToolExecutionStartPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/ToolExecutionStartPayloadConversionTests.cs index 57da4380..64a6adfb 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/ToolExecutionStartPayloadConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/ToolExecutionStartPayloadConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/ToolResultPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/ToolResultPayloadConversionTests.cs index adf10d5e..d0307262 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/ToolResultPayloadConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/ToolResultPayloadConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/TrajectoryEventConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/TrajectoryEventConversionTests.cs index 95fc31de..7c5bf570 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/TrajectoryEventConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/TrajectoryEventConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/TurnEndPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/TurnEndPayloadConversionTests.cs index 133b98e9..ec38407d 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/TurnEndPayloadConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/TurnEndPayloadConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/TurnEventConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/TurnEventConversionTests.cs index fe82defc..9aabec4e 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/TurnEventConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/TurnEventConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/TurnStartPayloadConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/TurnStartPayloadConversionTests.cs index 57a7bcff..e832830d 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/TurnStartPayloadConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/TurnStartPayloadConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/TurnSummaryConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/TurnSummaryConversionTests.cs index 148d264d..829809e6 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/TurnSummaryConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/TurnSummaryConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/events/TurnTraceConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/events/TurnTraceConversionTests.cs index 306c9b43..8494ef20 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/events/TurnTraceConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/events/TurnTraceConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/model/ModelConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/model/ModelConversionTests.cs index 8caf5761..ed993e2a 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/model/ModelConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/model/ModelConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/model/ModelInfoConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/model/ModelInfoConversionTests.cs index 61f89034..3873758e 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/model/ModelInfoConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/model/ModelInfoConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/model/ModelOptionsConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/model/ModelOptionsConversionTests.cs index dc497430..34cbea93 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/model/ModelOptionsConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/model/ModelOptionsConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/model/TokenUsageConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/model/TokenUsageConversionTests.cs index 13605019..4e57f030 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/model/TokenUsageConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/model/TokenUsageConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/pipeline/CompactionConfigConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/pipeline/CompactionConfigConversionTests.cs index 31c383c3..041b2ea4 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/pipeline/CompactionConfigConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/pipeline/CompactionConfigConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/pipeline/TurnOptionsConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/pipeline/TurnOptionsConversionTests.cs index 901a5bc2..6df3c3d4 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/pipeline/TurnOptionsConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/pipeline/TurnOptionsConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/streaming/StreamOptionsConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/streaming/StreamOptionsConversionTests.cs index ddf23e47..bc96f118 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/streaming/StreamOptionsConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/streaming/StreamOptionsConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/template/FormatConfigConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/template/FormatConfigConversionTests.cs index b93f51bf..e2a2d0c4 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/template/FormatConfigConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/template/FormatConfigConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/template/ParserConfigConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/template/ParserConfigConversionTests.cs index 1f2edafe..89322a25 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/template/ParserConfigConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/template/ParserConfigConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/template/TemplateConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/template/TemplateConversionTests.cs index 695bbc8c..d2d8ac67 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/template/TemplateConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/template/TemplateConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/tools/BindingConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/tools/BindingConversionTests.cs index 5ae77e47..225c3d16 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/tools/BindingConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/tools/BindingConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/tools/CustomToolConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/tools/CustomToolConversionTests.cs index 9586ab5e..3c76ef2e 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/tools/CustomToolConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/tools/CustomToolConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/tools/FunctionToolConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/tools/FunctionToolConversionTests.cs index 079b3c9c..a62d759a 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/tools/FunctionToolConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/tools/FunctionToolConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/tools/McpApprovalModeConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/tools/McpApprovalModeConversionTests.cs index 0ccda745..98a09769 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/tools/McpApprovalModeConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/tools/McpApprovalModeConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/tools/McpToolConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/tools/McpToolConversionTests.cs index 5fec1d09..fc10a3a5 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/tools/McpToolConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/tools/McpToolConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/tools/OpenApiToolConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/tools/OpenApiToolConversionTests.cs index e1678895..b9df13c5 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/tools/OpenApiToolConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/tools/OpenApiToolConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/tools/PromptyToolConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/tools/PromptyToolConversionTests.cs index 15745977..99f20b42 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/tools/PromptyToolConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/tools/PromptyToolConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/tools/ToolContextConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/tools/ToolContextConversionTests.cs index beee477a..76a8d83d 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/tools/ToolContextConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/tools/ToolContextConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/tools/ToolConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/tools/ToolConversionTests.cs index 3ffb95e5..b08fec57 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/tools/ToolConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/tools/ToolConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/tools/ToolDispatchResultConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/tools/ToolDispatchResultConversionTests.cs index f442e5d8..387b7018 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/tools/ToolDispatchResultConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/tools/ToolDispatchResultConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/tracing/TraceFileConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/tracing/TraceFileConversionTests.cs index 67ae4d98..66dac13a 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/tracing/TraceFileConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/tracing/TraceFileConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/tracing/TraceSpanConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/tracing/TraceSpanConversionTests.cs index 23b18fca..249576ed 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/tracing/TraceSpanConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/tracing/TraceSpanConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/tracing/TraceTimeConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/tracing/TraceTimeConversionTests.cs index 00cbd26e..b851d49a 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/tracing/TraceTimeConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/tracing/TraceTimeConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicImageBlockConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicImageBlockConversionTests.cs index dee7235c..1784c108 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicImageBlockConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicImageBlockConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicImageSourceConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicImageSourceConversionTests.cs index c5cedd30..4a223505 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicImageSourceConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicImageSourceConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicMessagesRequestConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicMessagesRequestConversionTests.cs index a425a7d5..3a823573 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicMessagesRequestConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicMessagesRequestConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicMessagesResponseConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicMessagesResponseConversionTests.cs index 47d6e93a..7b252b09 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicMessagesResponseConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicMessagesResponseConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicTextBlockConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicTextBlockConversionTests.cs index e516e507..ca4336d4 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicTextBlockConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicTextBlockConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicToolDefinitionConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicToolDefinitionConversionTests.cs index 9a1b9960..5851652f 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicToolDefinitionConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicToolDefinitionConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicToolResultBlockConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicToolResultBlockConversionTests.cs index 8de7c2c9..c048595a 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicToolResultBlockConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicToolResultBlockConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicToolUseBlockConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicToolUseBlockConversionTests.cs index 114774c5..9340190c 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicToolUseBlockConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicToolUseBlockConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicUsageConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicUsageConversionTests.cs index 4c54a2ed..66bced5a 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicUsageConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicUsageConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicWireMessageConversionTests.cs b/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicWireMessageConversionTests.cs index 57806912..2999434b 100644 --- a/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicWireMessageConversionTests.cs +++ b/runtime/csharp/Prompty.Core.Tests/Model/wire/AnthropicWireMessageConversionTests.cs @@ -1,3 +1,4 @@ +// using Xunit; #pragma warning disable IDE0130 diff --git a/runtime/csharp/Prompty.Core/Model/Context.cs b/runtime/csharp/Prompty.Core/Model/Context.cs index c1eb3c26..6182b68e 100644 --- a/runtime/csharp/Prompty.Core/Model/Context.cs +++ b/runtime/csharp/Prompty.Core/Model/Context.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; diff --git a/runtime/csharp/Prompty.Core/Model/Utils.cs b/runtime/csharp/Prompty.Core/Model/Utils.cs index 484b34b9..5d2e7d07 100644 --- a/runtime/csharp/Prompty.Core/Model/Utils.cs +++ b/runtime/csharp/Prompty.Core/Model/Utils.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Collections; using System.Reflection; diff --git a/runtime/csharp/Prompty.Core/Model/agent/GuardrailResult.cs b/runtime/csharp/Prompty.Core/Model/agent/GuardrailResult.cs index 582e492d..6b115776 100644 --- a/runtime/csharp/Prompty.Core/Model/agent/GuardrailResult.cs +++ b/runtime/csharp/Prompty.Core/Model/agent/GuardrailResult.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,13 +7,13 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// The result of a guardrail evaluation. Guardrails are safety checks that -/// -/// run at specific phases of the agent loop and can allow, deny, or rewrite -/// -/// content. -/// + /// + /// The result of a guardrail evaluation. Guardrails are safety checks that + /// + /// run at specific phases of the agent loop and can allow, deny, or rewrite + /// + /// content. + /// public partial class GuardrailResult { /// diff --git a/runtime/csharp/Prompty.Core/Model/agent/Prompty.cs b/runtime/csharp/Prompty.Core/Model/agent/Prompty.cs index 65a967fa..ff0f7910 100644 --- a/runtime/csharp/Prompty.Core/Model/agent/Prompty.cs +++ b/runtime/csharp/Prompty.Core/Model/agent/Prompty.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,27 +7,27 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// A Prompty is a markdown file format for LLM prompts. The frontmatter defines -/// -/// structured metadata including model configuration, input/output schemas, tools, -/// -/// and template settings. The markdown body becomes the instructions. -/// -/// This is the single root type for the Prompty schema — there is no abstract base -/// -/// class or kind discriminator. A .prompty file always produces a Prompty instance. -/// -/// Runtime loaders may resolve frontmatter references such as `${env:VAR}` and -/// -/// `${file:relative/path}`. File references must be treated as a host-controlled -/// -/// capability: by default they are scoped to the containing .prompty file's -/// -/// directory tree after canonicalization, and any additional allowed roots must -/// -/// be supplied by the host application's load options rather than frontmatter. -/// + /// + /// A Prompty is a markdown file format for LLM prompts. The frontmatter defines + /// + /// structured metadata including model configuration, input/output schemas, tools, + /// + /// and template settings. The markdown body becomes the instructions. + /// + /// This is the single root type for the Prompty schema — there is no abstract base + /// + /// class or kind discriminator. A .prompty file always produces a Prompty instance. + /// + /// Runtime loaders may resolve frontmatter references such as `${env:VAR}` and + /// + /// `${file:relative/path}`. File references must be treated as a host-controlled + /// + /// capability: by default they are scoped to the containing .prompty file's + /// + /// directory tree after canonicalization, and any additional allowed roots must + /// + /// be supplied by the host application's load options rather than frontmatter. + /// public partial class Prompty { /// diff --git a/runtime/csharp/Prompty.Core/Model/connection/AnonymousConnection.cs b/runtime/csharp/Prompty.Core/Model/connection/AnonymousConnection.cs index 67da5fec..8e3a42fe 100644 --- a/runtime/csharp/Prompty.Core/Model/connection/AnonymousConnection.cs +++ b/runtime/csharp/Prompty.Core/Model/connection/AnonymousConnection.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,8 +7,8 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// + /// + /// public partial class AnonymousConnection : Connection { /// diff --git a/runtime/csharp/Prompty.Core/Model/connection/ApiKeyConnection.cs b/runtime/csharp/Prompty.Core/Model/connection/ApiKeyConnection.cs index c103ea25..edd36572 100644 --- a/runtime/csharp/Prompty.Core/Model/connection/ApiKeyConnection.cs +++ b/runtime/csharp/Prompty.Core/Model/connection/ApiKeyConnection.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Connection configuration for AI services using API keys. -/// + /// + /// Connection configuration for AI services using API keys. + /// public partial class ApiKeyConnection : Connection { /// diff --git a/runtime/csharp/Prompty.Core/Model/connection/AuthenticationMode.cs b/runtime/csharp/Prompty.Core/Model/connection/AuthenticationMode.cs index d21331c1..0b1821ab 100644 --- a/runtime/csharp/Prompty.Core/Model/connection/AuthenticationMode.cs +++ b/runtime/csharp/Prompty.Core/Model/connection/AuthenticationMode.cs @@ -1,5 +1,6 @@ +// // -// Code generated by Prompty emitter; DO NOT EDIT. +// Code generated by Typra emitter; DO NOT EDIT. using System.Text.Json.Serialization; diff --git a/runtime/csharp/Prompty.Core/Model/connection/Connection.cs b/runtime/csharp/Prompty.Core/Model/connection/Connection.cs index 2c8fb282..5b538496 100644 --- a/runtime/csharp/Prompty.Core/Model/connection/Connection.cs +++ b/runtime/csharp/Prompty.Core/Model/connection/Connection.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,13 +7,13 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Connection configuration for AI agents. -/// -/// `provider`, `kind`, and `endpoint` are required properties here, -/// -/// but this section can accept additional via options. -/// + /// + /// Connection configuration for AI agents. + /// + /// `provider`, `kind`, and `endpoint` are required properties here, + /// + /// but this section can accept additional via options. + /// public abstract partial class Connection { /// diff --git a/runtime/csharp/Prompty.Core/Model/connection/FoundryConnection.cs b/runtime/csharp/Prompty.Core/Model/connection/FoundryConnection.cs index d52e9219..7e427c77 100644 --- a/runtime/csharp/Prompty.Core/Model/connection/FoundryConnection.cs +++ b/runtime/csharp/Prompty.Core/Model/connection/FoundryConnection.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,13 +7,13 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Connection configuration for Microsoft Foundry projects. -/// -/// Provides project-scoped access to models, tools, and services -/// -/// via Entra ID (DefaultAzureCredential) authentication. -/// + /// + /// Connection configuration for Microsoft Foundry projects. + /// + /// Provides project-scoped access to models, tools, and services + /// + /// via Entra ID (DefaultAzureCredential) authentication. + /// public partial class FoundryConnection : Connection { /// diff --git a/runtime/csharp/Prompty.Core/Model/connection/OAuthConnection.cs b/runtime/csharp/Prompty.Core/Model/connection/OAuthConnection.cs index a576abf7..cef46b2d 100644 --- a/runtime/csharp/Prompty.Core/Model/connection/OAuthConnection.cs +++ b/runtime/csharp/Prompty.Core/Model/connection/OAuthConnection.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,13 +7,13 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Connection configuration using OAuth 2.0 client credentials. -/// -/// Useful for tools and services that require OAuth authentication, -/// -/// such as MCP servers, OpenAPI endpoints, or other REST APIs. -/// + /// + /// Connection configuration using OAuth 2.0 client credentials. + /// + /// Useful for tools and services that require OAuth authentication, + /// + /// such as MCP servers, OpenAPI endpoints, or other REST APIs. + /// public partial class OAuthConnection : Connection { /// diff --git a/runtime/csharp/Prompty.Core/Model/connection/ReferenceConnection.cs b/runtime/csharp/Prompty.Core/Model/connection/ReferenceConnection.cs index 6df6fe5a..861ef369 100644 --- a/runtime/csharp/Prompty.Core/Model/connection/ReferenceConnection.cs +++ b/runtime/csharp/Prompty.Core/Model/connection/ReferenceConnection.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Connection configuration for AI services using named connections. -/// + /// + /// Connection configuration for AI services using named connections. + /// public partial class ReferenceConnection : Connection { /// diff --git a/runtime/csharp/Prompty.Core/Model/connection/RemoteConnection.cs b/runtime/csharp/Prompty.Core/Model/connection/RemoteConnection.cs index d94c4763..89d7c71a 100644 --- a/runtime/csharp/Prompty.Core/Model/connection/RemoteConnection.cs +++ b/runtime/csharp/Prompty.Core/Model/connection/RemoteConnection.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Connection configuration for AI services using named connections. -/// + /// + /// Connection configuration for AI services using named connections. + /// public partial class RemoteConnection : Connection { /// diff --git a/runtime/csharp/Prompty.Core/Model/conversation/AudioPart.cs b/runtime/csharp/Prompty.Core/Model/conversation/AudioPart.cs index 8e31fdf6..79b69e4f 100644 --- a/runtime/csharp/Prompty.Core/Model/conversation/AudioPart.cs +++ b/runtime/csharp/Prompty.Core/Model/conversation/AudioPart.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// An audio content part. The source may be a URL or base64-encoded data. -/// + /// + /// An audio content part. The source may be a URL or base64-encoded data. + /// public partial class AudioPart : ContentPart { /// diff --git a/runtime/csharp/Prompty.Core/Model/conversation/ContentPart.cs b/runtime/csharp/Prompty.Core/Model/conversation/ContentPart.cs index 47f3e900..04d7e6cc 100644 --- a/runtime/csharp/Prompty.Core/Model/conversation/ContentPart.cs +++ b/runtime/csharp/Prompty.Core/Model/conversation/ContentPart.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,11 +7,11 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// A part of a message's content. Content parts are discriminated on the `kind` -/// -/// field and represent the different modalities that can appear in a message. -/// + /// + /// A part of a message's content. Content parts are discriminated on the `kind` + /// + /// field and represent the different modalities that can appear in a message. + /// public abstract partial class ContentPart { /// diff --git a/runtime/csharp/Prompty.Core/Model/conversation/FilePart.cs b/runtime/csharp/Prompty.Core/Model/conversation/FilePart.cs index 14082700..ef9d3dad 100644 --- a/runtime/csharp/Prompty.Core/Model/conversation/FilePart.cs +++ b/runtime/csharp/Prompty.Core/Model/conversation/FilePart.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// A file content part. The source may be a URL or base64-encoded data. -/// + /// + /// A file content part. The source may be a URL or base64-encoded data. + /// public partial class FilePart : ContentPart { /// diff --git a/runtime/csharp/Prompty.Core/Model/conversation/ImagePart.cs b/runtime/csharp/Prompty.Core/Model/conversation/ImagePart.cs index db67e64e..8d131e52 100644 --- a/runtime/csharp/Prompty.Core/Model/conversation/ImagePart.cs +++ b/runtime/csharp/Prompty.Core/Model/conversation/ImagePart.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// An image content part. The source may be a URL or base64-encoded data. -/// + /// + /// An image content part. The source may be a URL or base64-encoded data. + /// public partial class ImagePart : ContentPart { /// diff --git a/runtime/csharp/Prompty.Core/Model/conversation/Message.cs b/runtime/csharp/Prompty.Core/Model/conversation/Message.cs index 1e99408b..683b594c 100644 --- a/runtime/csharp/Prompty.Core/Model/conversation/Message.cs +++ b/runtime/csharp/Prompty.Core/Model/conversation/Message.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,11 +7,11 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// A message in a conversation. Messages have a role and a list of content parts -/// -/// representing the different modalities of the message content. -/// + /// + /// A message in a conversation. Messages have a role and a list of content parts + /// + /// representing the different modalities of the message content. + /// public partial class Message : IMessageHelpers { /// diff --git a/runtime/csharp/Prompty.Core/Model/conversation/Role.cs b/runtime/csharp/Prompty.Core/Model/conversation/Role.cs index d215649e..9e6ca991 100644 --- a/runtime/csharp/Prompty.Core/Model/conversation/Role.cs +++ b/runtime/csharp/Prompty.Core/Model/conversation/Role.cs @@ -1,5 +1,6 @@ +// // -// Code generated by Prompty emitter; DO NOT EDIT. +// Code generated by Typra emitter; DO NOT EDIT. using System.Text.Json.Serialization; diff --git a/runtime/csharp/Prompty.Core/Model/conversation/TextPart.cs b/runtime/csharp/Prompty.Core/Model/conversation/TextPart.cs index ef0d1dc3..009ecc41 100644 --- a/runtime/csharp/Prompty.Core/Model/conversation/TextPart.cs +++ b/runtime/csharp/Prompty.Core/Model/conversation/TextPart.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// A text content part. -/// + /// + /// A text content part. + /// public partial class TextPart : ContentPart { /// diff --git a/runtime/csharp/Prompty.Core/Model/conversation/ThreadMarker.cs b/runtime/csharp/Prompty.Core/Model/conversation/ThreadMarker.cs index 1912303c..6671442d 100644 --- a/runtime/csharp/Prompty.Core/Model/conversation/ThreadMarker.cs +++ b/runtime/csharp/Prompty.Core/Model/conversation/ThreadMarker.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,15 +7,15 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Positional marker for conversation history insertion during template rendering. -/// -/// During `prepare()`, nonce strings in rendered text are replaced with -/// -/// ThreadMarker objects. The pipeline then replaces them with actual -/// -/// conversation messages from the inputs. -/// + /// + /// Positional marker for conversation history insertion during template rendering. + /// + /// During `prepare()`, nonce strings in rendered text are replaced with + /// + /// ThreadMarker objects. The pipeline then replaces them with actual + /// + /// conversation messages from the inputs. + /// public partial class ThreadMarker { /// diff --git a/runtime/csharp/Prompty.Core/Model/conversation/ToolCall.cs b/runtime/csharp/Prompty.Core/Model/conversation/ToolCall.cs index 201ae840..e63d86c9 100644 --- a/runtime/csharp/Prompty.Core/Model/conversation/ToolCall.cs +++ b/runtime/csharp/Prompty.Core/Model/conversation/ToolCall.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,11 +7,11 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// A tool call requested by the LLM. Contains the function name and serialized -/// -/// arguments that should be dispatched to the appropriate tool handler. -/// + /// + /// A tool call requested by the LLM. Contains the function name and serialized + /// + /// arguments that should be dispatched to the appropriate tool handler. + /// public partial class ToolCall { /// diff --git a/runtime/csharp/Prompty.Core/Model/conversation/ToolResult.cs b/runtime/csharp/Prompty.Core/Model/conversation/ToolResult.cs index b8ebce9d..d64bc34a 100644 --- a/runtime/csharp/Prompty.Core/Model/conversation/ToolResult.cs +++ b/runtime/csharp/Prompty.Core/Model/conversation/ToolResult.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,15 +7,15 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// The result of a tool execution. Contains a list of content parts, enabling -/// -/// rich tool results (text, images, files, audio) rather than just strings. -/// -/// Implementations MUST support conversion from a plain string to a ToolResult -/// -/// containing a single TextPart for backward compatibility. -/// + /// + /// The result of a tool execution. Contains a list of content parts, enabling + /// + /// rich tool results (text, images, files, audio) rather than just strings. + /// + /// Implementations MUST support conversion from a plain string to a ToolResult + /// + /// containing a single TextPart for backward compatibility. + /// public partial class ToolResult : IToolResultHelpers { /// diff --git a/runtime/csharp/Prompty.Core/Model/conversation/ToolResultStatus.cs b/runtime/csharp/Prompty.Core/Model/conversation/ToolResultStatus.cs index 9a659b88..3230cfd7 100644 --- a/runtime/csharp/Prompty.Core/Model/conversation/ToolResultStatus.cs +++ b/runtime/csharp/Prompty.Core/Model/conversation/ToolResultStatus.cs @@ -1,5 +1,6 @@ +// // -// Code generated by Prompty emitter; DO NOT EDIT. +// Code generated by Typra emitter; DO NOT EDIT. using System.Text.Json.Serialization; diff --git a/runtime/csharp/Prompty.Core/Model/core/ArrayProperty.cs b/runtime/csharp/Prompty.Core/Model/core/ArrayProperty.cs index 8d38bc04..b1b3caeb 100644 --- a/runtime/csharp/Prompty.Core/Model/core/ArrayProperty.cs +++ b/runtime/csharp/Prompty.Core/Model/core/ArrayProperty.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,11 +7,11 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Represents an array property. -/// -/// This extends the base Property model to represent an array of items. -/// + /// + /// Represents an array property. + /// + /// This extends the base Property model to represent an array of items. + /// public partial class ArrayProperty : Property { /// diff --git a/runtime/csharp/Prompty.Core/Model/core/FileNotFoundError.cs b/runtime/csharp/Prompty.Core/Model/core/FileNotFoundError.cs index 381a1f36..083dc759 100644 --- a/runtime/csharp/Prompty.Core/Model/core/FileNotFoundError.cs +++ b/runtime/csharp/Prompty.Core/Model/core/FileNotFoundError.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,11 +7,11 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Raised when a referenced file cannot be found. This applies to both -/// -/// .prompty files and ${file:path} references in frontmatter. -/// + /// + /// Raised when a referenced file cannot be found. This applies to both + /// + /// .prompty files and ${file:path} references in frontmatter. + /// public partial class FileNotFoundError { /// diff --git a/runtime/csharp/Prompty.Core/Model/core/InvokerError.cs b/runtime/csharp/Prompty.Core/Model/core/InvokerError.cs index 1b05784c..4cb68a7c 100644 --- a/runtime/csharp/Prompty.Core/Model/core/InvokerError.cs +++ b/runtime/csharp/Prompty.Core/Model/core/InvokerError.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,13 +7,13 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Raised when no invoker implementation is registered for a given component -/// -/// and key. For example, if no renderer is registered for the key "jinja2", -/// -/// an InvokerError is raised. -/// + /// + /// Raised when no invoker implementation is registered for a given component + /// + /// and key. For example, if no renderer is registered for the key "jinja2", + /// + /// an InvokerError is raised. + /// public partial class InvokerError { /// diff --git a/runtime/csharp/Prompty.Core/Model/core/ObjectProperty.cs b/runtime/csharp/Prompty.Core/Model/core/ObjectProperty.cs index d6a5c9b7..097174f5 100644 --- a/runtime/csharp/Prompty.Core/Model/core/ObjectProperty.cs +++ b/runtime/csharp/Prompty.Core/Model/core/ObjectProperty.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,11 +7,11 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Represents an object property. -/// -/// This extends the base Property model to represent a structured object. -/// + /// + /// Represents an object property. + /// + /// This extends the base Property model to represent a structured object. + /// public partial class ObjectProperty : Property { /// diff --git a/runtime/csharp/Prompty.Core/Model/core/Property.cs b/runtime/csharp/Prompty.Core/Model/core/Property.cs index ace0e867..41d15002 100644 --- a/runtime/csharp/Prompty.Core/Model/core/Property.cs +++ b/runtime/csharp/Prompty.Core/Model/core/Property.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,17 +7,17 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Represents a single property. -/// -/// - This model defines the structure of properties that can be used in prompts, -/// -/// including their type, description, whether they are required, and other attributes. -/// -/// - It allows for the definition of dynamic inputs that can be filled with data -/// -/// and processed to generate prompts for AI models. -/// + /// + /// Represents a single property. + /// + /// - This model defines the structure of properties that can be used in prompts, + /// + /// including their type, description, whether they are required, and other attributes. + /// + /// - It allows for the definition of dynamic inputs that can be filled with data + /// + /// and processed to generate prompts for AI models. + /// public partial class Property { /// diff --git a/runtime/csharp/Prompty.Core/Model/core/ValidationError.cs b/runtime/csharp/Prompty.Core/Model/core/ValidationError.cs index b7a6b650..aaab609d 100644 --- a/runtime/csharp/Prompty.Core/Model/core/ValidationError.cs +++ b/runtime/csharp/Prompty.Core/Model/core/ValidationError.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,11 +7,11 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Raised when input validation fails. Each ValidationError describes a -/// -/// single property that did not satisfy its constraint. -/// + /// + /// Raised when input validation fails. Each ValidationError describes a + /// + /// single property that did not satisfy its constraint. + /// public partial class ValidationError { /// diff --git a/runtime/csharp/Prompty.Core/Model/core/ValidationResult.cs b/runtime/csharp/Prompty.Core/Model/core/ValidationResult.cs index beabf0e6..9694a60c 100644 --- a/runtime/csharp/Prompty.Core/Model/core/ValidationResult.cs +++ b/runtime/csharp/Prompty.Core/Model/core/ValidationResult.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,13 +7,13 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// The result of validating inputs against a Prompty's inputs. -/// -/// Returned by `validate_inputs` (§12.2) to indicate whether all -/// -/// required inputs are present and satisfy their constraints. -/// + /// + /// The result of validating inputs against a Prompty's inputs. + /// + /// Returned by `validate_inputs` (§12.2) to indicate whether all + /// + /// required inputs are present and satisfy their constraints. + /// public partial class ValidationResult { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/Checkpoint.cs b/runtime/csharp/Prompty.Core/Model/events/Checkpoint.cs index 4c74ad8c..858754c8 100644 --- a/runtime/csharp/Prompty.Core/Model/events/Checkpoint.cs +++ b/runtime/csharp/Prompty.Core/Model/events/Checkpoint.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// A persisted handoff point for a harness session. -/// + /// + /// A persisted handoff point for a harness session. + /// public partial class Checkpoint { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/CompactionCompletePayload.cs b/runtime/csharp/Prompty.Core/Model/events/CompactionCompletePayload.cs index 0f283935..58226e29 100644 --- a/runtime/csharp/Prompty.Core/Model/events/CompactionCompletePayload.cs +++ b/runtime/csharp/Prompty.Core/Model/events/CompactionCompletePayload.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Payload for "compaction_complete" events — context compaction finished. -/// + /// + /// Payload for "compaction_complete" events — context compaction finished. + /// public partial class CompactionCompletePayload { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/CompactionFailedPayload.cs b/runtime/csharp/Prompty.Core/Model/events/CompactionFailedPayload.cs index b6f8693c..7afec04b 100644 --- a/runtime/csharp/Prompty.Core/Model/events/CompactionFailedPayload.cs +++ b/runtime/csharp/Prompty.Core/Model/events/CompactionFailedPayload.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Payload for "compaction_failed" events — compaction could not be completed. -/// + /// + /// Payload for "compaction_failed" events — compaction could not be completed. + /// public partial class CompactionFailedPayload { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/CompactionStartPayload.cs b/runtime/csharp/Prompty.Core/Model/events/CompactionStartPayload.cs index 3990bc19..97631ba5 100644 --- a/runtime/csharp/Prompty.Core/Model/events/CompactionStartPayload.cs +++ b/runtime/csharp/Prompty.Core/Model/events/CompactionStartPayload.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Payload for "compaction_start" events — context compaction is beginning. -/// + /// + /// Payload for "compaction_start" events — context compaction is beginning. + /// public partial class CompactionStartPayload { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/DoneEventPayload.cs b/runtime/csharp/Prompty.Core/Model/events/DoneEventPayload.cs index fc193aac..3640a80c 100644 --- a/runtime/csharp/Prompty.Core/Model/events/DoneEventPayload.cs +++ b/runtime/csharp/Prompty.Core/Model/events/DoneEventPayload.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Payload for "done" events — the agent loop completed successfully. -/// + /// + /// Payload for "done" events — the agent loop completed successfully. + /// public partial class DoneEventPayload { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/ErrorChunk.cs b/runtime/csharp/Prompty.Core/Model/events/ErrorChunk.cs index 430616bf..2982e77f 100644 --- a/runtime/csharp/Prompty.Core/Model/events/ErrorChunk.cs +++ b/runtime/csharp/Prompty.Core/Model/events/ErrorChunk.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// An error chunk from the LLM response stream. -/// + /// + /// An error chunk from the LLM response stream. + /// public partial class ErrorChunk : StreamChunk { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/ErrorEventPayload.cs b/runtime/csharp/Prompty.Core/Model/events/ErrorEventPayload.cs index 3c72a13a..72210e05 100644 --- a/runtime/csharp/Prompty.Core/Model/events/ErrorEventPayload.cs +++ b/runtime/csharp/Prompty.Core/Model/events/ErrorEventPayload.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Payload for "error" events — an error occurred during the loop. -/// + /// + /// Payload for "error" events — an error occurred during the loop. + /// public partial class ErrorEventPayload { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/HarnessContext.cs b/runtime/csharp/Prompty.Core/Model/events/HarnessContext.cs index 9371853b..e406aa2d 100644 --- a/runtime/csharp/Prompty.Core/Model/events/HarnessContext.cs +++ b/runtime/csharp/Prompty.Core/Model/events/HarnessContext.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,13 +7,13 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Execution context associated with a harness session. Host-specific -/// -/// environments can store detailed profiles in metadata without making the core -/// -/// contract depend on one source-control provider or workspace shape. -/// + /// + /// Execution context associated with a harness session. Host-specific + /// + /// environments can store detailed profiles in metadata without making the core + /// + /// contract depend on one source-control provider or workspace shape. + /// public partial class HarnessContext { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/HookEndPayload.cs b/runtime/csharp/Prompty.Core/Model/events/HookEndPayload.cs index 42f6c80a..e67f0025 100644 --- a/runtime/csharp/Prompty.Core/Model/events/HookEndPayload.cs +++ b/runtime/csharp/Prompty.Core/Model/events/HookEndPayload.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Payload for "hook_end" events — a host lifecycle hook finished. -/// + /// + /// Payload for "hook_end" events — a host lifecycle hook finished. + /// public partial class HookEndPayload { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/HookEndScope.cs b/runtime/csharp/Prompty.Core/Model/events/HookEndScope.cs index 0133e67b..d307eca7 100644 --- a/runtime/csharp/Prompty.Core/Model/events/HookEndScope.cs +++ b/runtime/csharp/Prompty.Core/Model/events/HookEndScope.cs @@ -1,5 +1,6 @@ +// // -// Code generated by Prompty emitter; DO NOT EDIT. +// Code generated by Typra emitter; DO NOT EDIT. using System.Text.Json.Serialization; diff --git a/runtime/csharp/Prompty.Core/Model/events/HookStartPayload.cs b/runtime/csharp/Prompty.Core/Model/events/HookStartPayload.cs index f6637e9a..f3986367 100644 --- a/runtime/csharp/Prompty.Core/Model/events/HookStartPayload.cs +++ b/runtime/csharp/Prompty.Core/Model/events/HookStartPayload.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Payload for "hook_start" events — a host lifecycle hook is beginning. -/// + /// + /// Payload for "hook_start" events — a host lifecycle hook is beginning. + /// public partial class HookStartPayload { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/HookStartScope.cs b/runtime/csharp/Prompty.Core/Model/events/HookStartScope.cs index 3b987870..3731bad3 100644 --- a/runtime/csharp/Prompty.Core/Model/events/HookStartScope.cs +++ b/runtime/csharp/Prompty.Core/Model/events/HookStartScope.cs @@ -1,5 +1,6 @@ +// // -// Code generated by Prompty emitter; DO NOT EDIT. +// Code generated by Typra emitter; DO NOT EDIT. using System.Text.Json.Serialization; diff --git a/runtime/csharp/Prompty.Core/Model/events/HostToolRequest.cs b/runtime/csharp/Prompty.Core/Model/events/HostToolRequest.cs index a69feca2..c487f609 100644 --- a/runtime/csharp/Prompty.Core/Model/events/HostToolRequest.cs +++ b/runtime/csharp/Prompty.Core/Model/events/HostToolRequest.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Request passed to a host tool executor after policy and permission checks. -/// + /// + /// Request passed to a host tool executor after policy and permission checks. + /// public partial class HostToolRequest { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/HostToolResult.cs b/runtime/csharp/Prompty.Core/Model/events/HostToolResult.cs index b8aa3459..d909c5e9 100644 --- a/runtime/csharp/Prompty.Core/Model/events/HostToolResult.cs +++ b/runtime/csharp/Prompty.Core/Model/events/HostToolResult.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Result returned by a host tool executor. -/// + /// + /// Result returned by a host tool executor. + /// public partial class HostToolResult { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/LlmCompletePayload.cs b/runtime/csharp/Prompty.Core/Model/events/LlmCompletePayload.cs index 755ff31a..7465de8d 100644 --- a/runtime/csharp/Prompty.Core/Model/events/LlmCompletePayload.cs +++ b/runtime/csharp/Prompty.Core/Model/events/LlmCompletePayload.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Payload for "llm_complete" events — an LLM request completed. -/// + /// + /// Payload for "llm_complete" events — an LLM request completed. + /// public partial class LlmCompletePayload { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/LlmStartPayload.cs b/runtime/csharp/Prompty.Core/Model/events/LlmStartPayload.cs index 7fce71e5..7fb7b206 100644 --- a/runtime/csharp/Prompty.Core/Model/events/LlmStartPayload.cs +++ b/runtime/csharp/Prompty.Core/Model/events/LlmStartPayload.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Payload for "llm_start" events — an LLM request is about to be sent. -/// + /// + /// Payload for "llm_start" events — an LLM request is about to be sent. + /// public partial class LlmStartPayload { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/MessagesUpdatedPayload.cs b/runtime/csharp/Prompty.Core/Model/events/MessagesUpdatedPayload.cs index a42c325c..a1266b6c 100644 --- a/runtime/csharp/Prompty.Core/Model/events/MessagesUpdatedPayload.cs +++ b/runtime/csharp/Prompty.Core/Model/events/MessagesUpdatedPayload.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Payload for "messages_updated" events — the conversation state has changed. -/// + /// + /// Payload for "messages_updated" events — the conversation state has changed. + /// public partial class MessagesUpdatedPayload { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/PermissionCompletedPayload.cs b/runtime/csharp/Prompty.Core/Model/events/PermissionCompletedPayload.cs index b2eef078..3793084e 100644 --- a/runtime/csharp/Prompty.Core/Model/events/PermissionCompletedPayload.cs +++ b/runtime/csharp/Prompty.Core/Model/events/PermissionCompletedPayload.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Payload for permission completion events — an approval decision was made. -/// + /// + /// Payload for permission completion events — an approval decision was made. + /// public partial class PermissionCompletedPayload { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/PermissionDecision.cs b/runtime/csharp/Prompty.Core/Model/events/PermissionDecision.cs index bbb78351..74b6d83b 100644 --- a/runtime/csharp/Prompty.Core/Model/events/PermissionDecision.cs +++ b/runtime/csharp/Prompty.Core/Model/events/PermissionDecision.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Decision returned by a permission resolver. -/// + /// + /// Decision returned by a permission resolver. + /// public partial class PermissionDecision { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/PermissionRequest.cs b/runtime/csharp/Prompty.Core/Model/events/PermissionRequest.cs index 41a0f2e5..6cf407a0 100644 --- a/runtime/csharp/Prompty.Core/Model/events/PermissionRequest.cs +++ b/runtime/csharp/Prompty.Core/Model/events/PermissionRequest.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,11 +7,11 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Request passed to a permission resolver. This is the live protocol shape; the -/// -/// event payloads above can include trace-only metadata such as redaction state. -/// + /// + /// Request passed to a permission resolver. This is the live protocol shape; the + /// + /// event payloads above can include trace-only metadata such as redaction state. + /// public partial class PermissionRequest { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/PermissionRequestedPayload.cs b/runtime/csharp/Prompty.Core/Model/events/PermissionRequestedPayload.cs index c9a576d4..55b927cc 100644 --- a/runtime/csharp/Prompty.Core/Model/events/PermissionRequestedPayload.cs +++ b/runtime/csharp/Prompty.Core/Model/events/PermissionRequestedPayload.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Payload for permission request events — a host is asked to approve an action. -/// + /// + /// Payload for permission request events — a host is asked to approve an action. + /// public partial class PermissionRequestedPayload { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/RedactedField.cs b/runtime/csharp/Prompty.Core/Model/events/RedactedField.cs index 76563869..cc338e23 100644 --- a/runtime/csharp/Prompty.Core/Model/events/RedactedField.cs +++ b/runtime/csharp/Prompty.Core/Model/events/RedactedField.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Redaction handling for one JSON-shaped field path. -/// + /// + /// Redaction handling for one JSON-shaped field path. + /// public partial class RedactedField { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/RedactionMetadata.cs b/runtime/csharp/Prompty.Core/Model/events/RedactionMetadata.cs index 5bcf7720..c43813a3 100644 --- a/runtime/csharp/Prompty.Core/Model/events/RedactionMetadata.cs +++ b/runtime/csharp/Prompty.Core/Model/events/RedactionMetadata.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Metadata describing whether and how a payload was sanitized. -/// + /// + /// Metadata describing whether and how a payload was sanitized. + /// public partial class RedactionMetadata { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/RedactionMode.cs b/runtime/csharp/Prompty.Core/Model/events/RedactionMode.cs index fb5bdcca..7aa9455b 100644 --- a/runtime/csharp/Prompty.Core/Model/events/RedactionMode.cs +++ b/runtime/csharp/Prompty.Core/Model/events/RedactionMode.cs @@ -1,5 +1,6 @@ +// // -// Code generated by Prompty emitter; DO NOT EDIT. +// Code generated by Typra emitter; DO NOT EDIT. using System.Text.Json.Serialization; diff --git a/runtime/csharp/Prompty.Core/Model/events/RetryPayload.cs b/runtime/csharp/Prompty.Core/Model/events/RetryPayload.cs index c3b9f67b..bbdc575e 100644 --- a/runtime/csharp/Prompty.Core/Model/events/RetryPayload.cs +++ b/runtime/csharp/Prompty.Core/Model/events/RetryPayload.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Payload for "retry" events — a transient operation will be retried. -/// + /// + /// Payload for "retry" events — a transient operation will be retried. + /// public partial class RetryPayload { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/SessionEndPayload.cs b/runtime/csharp/Prompty.Core/Model/events/SessionEndPayload.cs index abe74a0f..4c80ef08 100644 --- a/runtime/csharp/Prompty.Core/Model/events/SessionEndPayload.cs +++ b/runtime/csharp/Prompty.Core/Model/events/SessionEndPayload.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Payload for "session_end" events. -/// + /// + /// Payload for "session_end" events. + /// public partial class SessionEndPayload { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/SessionEndStatus.cs b/runtime/csharp/Prompty.Core/Model/events/SessionEndStatus.cs index 2294745a..01ddca6c 100644 --- a/runtime/csharp/Prompty.Core/Model/events/SessionEndStatus.cs +++ b/runtime/csharp/Prompty.Core/Model/events/SessionEndStatus.cs @@ -1,5 +1,6 @@ +// // -// Code generated by Prompty emitter; DO NOT EDIT. +// Code generated by Typra emitter; DO NOT EDIT. using System.Text.Json.Serialization; diff --git a/runtime/csharp/Prompty.Core/Model/events/SessionEvent.cs b/runtime/csharp/Prompty.Core/Model/events/SessionEvent.cs index 953c332c..3847c7bd 100644 --- a/runtime/csharp/Prompty.Core/Model/events/SessionEvent.cs +++ b/runtime/csharp/Prompty.Core/Model/events/SessionEvent.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// A canonical event envelope emitted by an outer harness session. -/// + /// + /// A canonical event envelope emitted by an outer harness session. + /// public partial class SessionEvent { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/SessionEventType.cs b/runtime/csharp/Prompty.Core/Model/events/SessionEventType.cs index 14e57015..41bf379d 100644 --- a/runtime/csharp/Prompty.Core/Model/events/SessionEventType.cs +++ b/runtime/csharp/Prompty.Core/Model/events/SessionEventType.cs @@ -1,5 +1,6 @@ +// // -// Code generated by Prompty emitter; DO NOT EDIT. +// Code generated by Typra emitter; DO NOT EDIT. using System.Text.Json.Serialization; diff --git a/runtime/csharp/Prompty.Core/Model/events/SessionFileRef.cs b/runtime/csharp/Prompty.Core/Model/events/SessionFileRef.cs index 3348def8..0dcf68fe 100644 --- a/runtime/csharp/Prompty.Core/Model/events/SessionFileRef.cs +++ b/runtime/csharp/Prompty.Core/Model/events/SessionFileRef.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// A file observed or touched by a harness session. -/// + /// + /// A file observed or touched by a harness session. + /// public partial class SessionFileRef { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/SessionRef.cs b/runtime/csharp/Prompty.Core/Model/events/SessionRef.cs index 4594a137..8468fb5d 100644 --- a/runtime/csharp/Prompty.Core/Model/events/SessionRef.cs +++ b/runtime/csharp/Prompty.Core/Model/events/SessionRef.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// A non-file reference observed by a harness session. -/// + /// + /// A non-file reference observed by a harness session. + /// public partial class SessionRef { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/SessionStartPayload.cs b/runtime/csharp/Prompty.Core/Model/events/SessionStartPayload.cs index 3ec79122..c4270514 100644 --- a/runtime/csharp/Prompty.Core/Model/events/SessionStartPayload.cs +++ b/runtime/csharp/Prompty.Core/Model/events/SessionStartPayload.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Payload for "session_start" events. -/// + /// + /// Payload for "session_start" events. + /// public partial class SessionStartPayload { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/SessionSummary.cs b/runtime/csharp/Prompty.Core/Model/events/SessionSummary.cs index ce388ae7..b1189c1e 100644 --- a/runtime/csharp/Prompty.Core/Model/events/SessionSummary.cs +++ b/runtime/csharp/Prompty.Core/Model/events/SessionSummary.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Summary statistics for a completed session trace. -/// + /// + /// Summary statistics for a completed session trace. + /// public partial class SessionSummary { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/SessionSummaryStatus.cs b/runtime/csharp/Prompty.Core/Model/events/SessionSummaryStatus.cs index 69f17e79..9f34f219 100644 --- a/runtime/csharp/Prompty.Core/Model/events/SessionSummaryStatus.cs +++ b/runtime/csharp/Prompty.Core/Model/events/SessionSummaryStatus.cs @@ -1,5 +1,6 @@ +// // -// Code generated by Prompty emitter; DO NOT EDIT. +// Code generated by Typra emitter; DO NOT EDIT. using System.Text.Json.Serialization; diff --git a/runtime/csharp/Prompty.Core/Model/events/SessionTrace.cs b/runtime/csharp/Prompty.Core/Model/events/SessionTrace.cs index 4886a099..2f96a080 100644 --- a/runtime/csharp/Prompty.Core/Model/events/SessionTrace.cs +++ b/runtime/csharp/Prompty.Core/Model/events/SessionTrace.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Portable replay container for an outer harness session. -/// + /// + /// Portable replay container for an outer harness session. + /// public partial class SessionTrace { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/SessionWarningPayload.cs b/runtime/csharp/Prompty.Core/Model/events/SessionWarningPayload.cs index 3456a18c..55b498da 100644 --- a/runtime/csharp/Prompty.Core/Model/events/SessionWarningPayload.cs +++ b/runtime/csharp/Prompty.Core/Model/events/SessionWarningPayload.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Payload for "session_warning" events. -/// + /// + /// Payload for "session_warning" events. + /// public partial class SessionWarningPayload { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/StatusEventPayload.cs b/runtime/csharp/Prompty.Core/Model/events/StatusEventPayload.cs index a1372eaf..dee6783b 100644 --- a/runtime/csharp/Prompty.Core/Model/events/StatusEventPayload.cs +++ b/runtime/csharp/Prompty.Core/Model/events/StatusEventPayload.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Payload for "status" events — informational messages about loop progress. -/// + /// + /// Payload for "status" events — informational messages about loop progress. + /// public partial class StatusEventPayload { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/StreamChunk.cs b/runtime/csharp/Prompty.Core/Model/events/StreamChunk.cs index 56a8091d..ff32d3b5 100644 --- a/runtime/csharp/Prompty.Core/Model/events/StreamChunk.cs +++ b/runtime/csharp/Prompty.Core/Model/events/StreamChunk.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,11 +7,11 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// A chunk of data from a streaming LLM response. Stream chunks are -/// -/// discriminated on the `kind` field. -/// + /// + /// A chunk of data from a streaming LLM response. Stream chunks are + /// + /// discriminated on the `kind` field. + /// public abstract partial class StreamChunk { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/TextChunk.cs b/runtime/csharp/Prompty.Core/Model/events/TextChunk.cs index 12cce412..4f233e92 100644 --- a/runtime/csharp/Prompty.Core/Model/events/TextChunk.cs +++ b/runtime/csharp/Prompty.Core/Model/events/TextChunk.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// A text content chunk from the LLM response stream. -/// + /// + /// A text content chunk from the LLM response stream. + /// public partial class TextChunk : StreamChunk { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/ThinkingChunk.cs b/runtime/csharp/Prompty.Core/Model/events/ThinkingChunk.cs index a75d4497..a9ea48dd 100644 --- a/runtime/csharp/Prompty.Core/Model/events/ThinkingChunk.cs +++ b/runtime/csharp/Prompty.Core/Model/events/ThinkingChunk.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// A thinking/reasoning content chunk from the LLM response stream. -/// + /// + /// A thinking/reasoning content chunk from the LLM response stream. + /// public partial class ThinkingChunk : StreamChunk { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/ThinkingEventPayload.cs b/runtime/csharp/Prompty.Core/Model/events/ThinkingEventPayload.cs index 15ec5cbc..67c71038 100644 --- a/runtime/csharp/Prompty.Core/Model/events/ThinkingEventPayload.cs +++ b/runtime/csharp/Prompty.Core/Model/events/ThinkingEventPayload.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Payload for "thinking" events — reasoning/chain-of-thought tokens. -/// + /// + /// Payload for "thinking" events — reasoning/chain-of-thought tokens. + /// public partial class ThinkingEventPayload { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/TokenEventPayload.cs b/runtime/csharp/Prompty.Core/Model/events/TokenEventPayload.cs index 46d720e0..b8f1430c 100644 --- a/runtime/csharp/Prompty.Core/Model/events/TokenEventPayload.cs +++ b/runtime/csharp/Prompty.Core/Model/events/TokenEventPayload.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Payload for "token" events — a single text token streamed from the LLM. -/// + /// + /// Payload for "token" events — a single text token streamed from the LLM. + /// public partial class TokenEventPayload { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/ToolCallCompletePayload.cs b/runtime/csharp/Prompty.Core/Model/events/ToolCallCompletePayload.cs index 7d5f7cf9..3dad5288 100644 --- a/runtime/csharp/Prompty.Core/Model/events/ToolCallCompletePayload.cs +++ b/runtime/csharp/Prompty.Core/Model/events/ToolCallCompletePayload.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Payload for "tool_call_complete" events — a tool dispatch finished. -/// + /// + /// Payload for "tool_call_complete" events — a tool dispatch finished. + /// public partial class ToolCallCompletePayload { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/ToolCallStartPayload.cs b/runtime/csharp/Prompty.Core/Model/events/ToolCallStartPayload.cs index de04a1da..6ec361ce 100644 --- a/runtime/csharp/Prompty.Core/Model/events/ToolCallStartPayload.cs +++ b/runtime/csharp/Prompty.Core/Model/events/ToolCallStartPayload.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Payload for "tool_call_start" events — the LLM has requested a tool call. -/// + /// + /// Payload for "tool_call_start" events — the LLM has requested a tool call. + /// public partial class ToolCallStartPayload { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/ToolChunk.cs b/runtime/csharp/Prompty.Core/Model/events/ToolChunk.cs index ec25e197..34e3f203 100644 --- a/runtime/csharp/Prompty.Core/Model/events/ToolChunk.cs +++ b/runtime/csharp/Prompty.Core/Model/events/ToolChunk.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// A tool call chunk from the LLM response stream. -/// + /// + /// A tool call chunk from the LLM response stream. + /// public partial class ToolChunk : StreamChunk { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/ToolExecutionCompletePayload.cs b/runtime/csharp/Prompty.Core/Model/events/ToolExecutionCompletePayload.cs index 20a92ac7..74a7a9fd 100644 --- a/runtime/csharp/Prompty.Core/Model/events/ToolExecutionCompletePayload.cs +++ b/runtime/csharp/Prompty.Core/Model/events/ToolExecutionCompletePayload.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Payload for "tool_execution_complete" events — a concrete host tool execution finished. -/// + /// + /// Payload for "tool_execution_complete" events — a concrete host tool execution finished. + /// public partial class ToolExecutionCompletePayload { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/ToolExecutionStartPayload.cs b/runtime/csharp/Prompty.Core/Model/events/ToolExecutionStartPayload.cs index c9c8c66f..a7aade30 100644 --- a/runtime/csharp/Prompty.Core/Model/events/ToolExecutionStartPayload.cs +++ b/runtime/csharp/Prompty.Core/Model/events/ToolExecutionStartPayload.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,13 +7,13 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Payload for "tool_execution_start" events — the host is about to execute a concrete tool request. -/// -/// This is distinct from "tool_call_start", which records the model requesting a tool. -/// -/// Tool execution events capture the harness-side action after policy and permission checks. -/// + /// + /// Payload for "tool_execution_start" events — the host is about to execute a concrete tool request. + /// + /// This is distinct from "tool_call_start", which records the model requesting a tool. + /// + /// Tool execution events capture the harness-side action after policy and permission checks. + /// public partial class ToolExecutionStartPayload { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/ToolResultPayload.cs b/runtime/csharp/Prompty.Core/Model/events/ToolResultPayload.cs index 07e378be..b9c2bce2 100644 --- a/runtime/csharp/Prompty.Core/Model/events/ToolResultPayload.cs +++ b/runtime/csharp/Prompty.Core/Model/events/ToolResultPayload.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Payload for "tool_result" events — a tool has returned its result. -/// + /// + /// Payload for "tool_result" events — a tool has returned its result. + /// public partial class ToolResultPayload { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/TrajectoryEvent.cs b/runtime/csharp/Prompty.Core/Model/events/TrajectoryEvent.cs index 9f8f106c..b860c3fd 100644 --- a/runtime/csharp/Prompty.Core/Model/events/TrajectoryEvent.cs +++ b/runtime/csharp/Prompty.Core/Model/events/TrajectoryEvent.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// A compact, replay-oriented record of one harness-side action or observation. -/// + /// + /// A compact, replay-oriented record of one harness-side action or observation. + /// public partial class TrajectoryEvent { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/TurnEndPayload.cs b/runtime/csharp/Prompty.Core/Model/events/TurnEndPayload.cs index 645f7b8d..5bbcc983 100644 --- a/runtime/csharp/Prompty.Core/Model/events/TurnEndPayload.cs +++ b/runtime/csharp/Prompty.Core/Model/events/TurnEndPayload.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Payload for "turn_end" events — a turn has completed. -/// + /// + /// Payload for "turn_end" events — a turn has completed. + /// public partial class TurnEndPayload { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/TurnEvent.cs b/runtime/csharp/Prompty.Core/Model/events/TurnEvent.cs index 24378f31..0d630858 100644 --- a/runtime/csharp/Prompty.Core/Model/events/TurnEvent.cs +++ b/runtime/csharp/Prompty.Core/Model/events/TurnEvent.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,13 +7,13 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// A canonical event envelope emitted by the turn harness. The payload is kept -/// -/// JSON-shaped so runtimes can load all events even when newer payload types are -/// -/// added; event-specific typed payload models below define the canonical shapes. -/// + /// + /// A canonical event envelope emitted by the turn harness. The payload is kept + /// + /// JSON-shaped so runtimes can load all events even when newer payload types are + /// + /// added; event-specific typed payload models below define the canonical shapes. + /// public partial class TurnEvent { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/TurnEventType.cs b/runtime/csharp/Prompty.Core/Model/events/TurnEventType.cs index 21121af7..50cd0fce 100644 --- a/runtime/csharp/Prompty.Core/Model/events/TurnEventType.cs +++ b/runtime/csharp/Prompty.Core/Model/events/TurnEventType.cs @@ -1,5 +1,6 @@ +// // -// Code generated by Prompty emitter; DO NOT EDIT. +// Code generated by Typra emitter; DO NOT EDIT. using System.Text.Json.Serialization; diff --git a/runtime/csharp/Prompty.Core/Model/events/TurnStartPayload.cs b/runtime/csharp/Prompty.Core/Model/events/TurnStartPayload.cs index 45e59348..53390b3b 100644 --- a/runtime/csharp/Prompty.Core/Model/events/TurnStartPayload.cs +++ b/runtime/csharp/Prompty.Core/Model/events/TurnStartPayload.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Payload for "turn_start" events — a turn is beginning. -/// + /// + /// Payload for "turn_start" events — a turn is beginning. + /// public partial class TurnStartPayload { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/TurnStatus.cs b/runtime/csharp/Prompty.Core/Model/events/TurnStatus.cs index 9e12bed8..79cad0fd 100644 --- a/runtime/csharp/Prompty.Core/Model/events/TurnStatus.cs +++ b/runtime/csharp/Prompty.Core/Model/events/TurnStatus.cs @@ -1,5 +1,6 @@ +// // -// Code generated by Prompty emitter; DO NOT EDIT. +// Code generated by Typra emitter; DO NOT EDIT. using System.Text.Json.Serialization; diff --git a/runtime/csharp/Prompty.Core/Model/events/TurnSummary.cs b/runtime/csharp/Prompty.Core/Model/events/TurnSummary.cs index 1dd28893..0b8732ca 100644 --- a/runtime/csharp/Prompty.Core/Model/events/TurnSummary.cs +++ b/runtime/csharp/Prompty.Core/Model/events/TurnSummary.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Summary statistics for a completed turn trace. -/// + /// + /// Summary statistics for a completed turn trace. + /// public partial class TurnSummary { /// diff --git a/runtime/csharp/Prompty.Core/Model/events/TurnTrace.cs b/runtime/csharp/Prompty.Core/Model/events/TurnTrace.cs index ab7e8703..4834e03e 100644 --- a/runtime/csharp/Prompty.Core/Model/events/TurnTrace.cs +++ b/runtime/csharp/Prompty.Core/Model/events/TurnTrace.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Portable JSONL/replay container for a recorded turn harness run. -/// + /// + /// Portable JSONL/replay container for a recorded turn harness run. + /// public partial class TurnTrace { /// diff --git a/runtime/csharp/Prompty.Core/Model/model/Model.cs b/runtime/csharp/Prompty.Core/Model/model/Model.cs index 4aa15d9b..8b1dd4cf 100644 --- a/runtime/csharp/Prompty.Core/Model/model/Model.cs +++ b/runtime/csharp/Prompty.Core/Model/model/Model.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,13 +7,13 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Model for defining the structure and behavior of AI agents. -/// -/// This model includes properties for specifying the model's provider, connection details, and various options. -/// -/// It allows for flexible configuration of AI models to suit different use cases and requirements. -/// + /// + /// Model for defining the structure and behavior of AI agents. + /// + /// This model includes properties for specifying the model's provider, connection details, and various options. + /// + /// It allows for flexible configuration of AI models to suit different use cases and requirements. + /// public partial class Model { /// diff --git a/runtime/csharp/Prompty.Core/Model/model/ModelInfo.cs b/runtime/csharp/Prompty.Core/Model/model/ModelInfo.cs index 4ff4a573..efda9bb0 100644 --- a/runtime/csharp/Prompty.Core/Model/model/ModelInfo.cs +++ b/runtime/csharp/Prompty.Core/Model/model/ModelInfo.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,17 +7,17 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Information about a model available from a provider. Used by provider-level -/// -/// model discovery to report which models are available and their capabilities. -/// -/// Not all providers return all fields — implementations SHOULD populate as -/// -/// many fields as the provider's API supports and MAY enrich sparse results -/// -/// from a built-in lookup table of known models. -/// + /// + /// Information about a model available from a provider. Used by provider-level + /// + /// model discovery to report which models are available and their capabilities. + /// + /// Not all providers return all fields — implementations SHOULD populate as + /// + /// many fields as the provider's API supports and MAY enrich sparse results + /// + /// from a built-in lookup table of known models. + /// public partial class ModelInfo { /// diff --git a/runtime/csharp/Prompty.Core/Model/model/ModelOptions.cs b/runtime/csharp/Prompty.Core/Model/model/ModelOptions.cs index a2a9e173..8842fb92 100644 --- a/runtime/csharp/Prompty.Core/Model/model/ModelOptions.cs +++ b/runtime/csharp/Prompty.Core/Model/model/ModelOptions.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Options for configuring the behavior of the AI model. -/// + /// + /// Options for configuring the behavior of the AI model. + /// public partial class ModelOptions { /// diff --git a/runtime/csharp/Prompty.Core/Model/model/TokenUsage.cs b/runtime/csharp/Prompty.Core/Model/model/TokenUsage.cs index 1395b9eb..aec8a533 100644 --- a/runtime/csharp/Prompty.Core/Model/model/TokenUsage.cs +++ b/runtime/csharp/Prompty.Core/Model/model/TokenUsage.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,13 +7,13 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Tracks token consumption for a single LLM call. Provider-specific field -/// -/// names (e.g., OpenAI's `prompt_tokens` vs Anthropic's `input_tokens`) -/// -/// are mapped via `knownAs` augments in the wire directory. -/// + /// + /// Tracks token consumption for a single LLM call. Provider-specific field + /// + /// names (e.g., OpenAI's `prompt_tokens` vs Anthropic's `input_tokens`) + /// + /// are mapped via `knownAs` augments in the wire directory. + /// public partial class TokenUsage { /// diff --git a/runtime/csharp/Prompty.Core/Model/pipeline/CheckpointStore.cs b/runtime/csharp/Prompty.Core/Model/pipeline/CheckpointStore.cs index 6c787c4d..89a41b65 100644 --- a/runtime/csharp/Prompty.Core/Model/pipeline/CheckpointStore.cs +++ b/runtime/csharp/Prompty.Core/Model/pipeline/CheckpointStore.cs @@ -1,24 +1,25 @@ +// // Copyright (c) Microsoft. All rights reserved. #pragma warning disable IDE0130 namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Stores and retrieves resumable session checkpoints. -/// -public interface ICheckpointStore -{ /// - /// Persist a session checkpoint and return the stored checkpoint + /// Stores and retrieves resumable session checkpoints. /// - Task SaveAsync(Checkpoint checkpoint); - /// - /// Load a checkpoint by session and checkpoint identifier - /// - Task LoadAsync(string sessionId, string checkpointId); - /// - /// List checkpoints for a session - /// - Task> ListCheckpointsAsync(string sessionId); -} + public interface ICheckpointStore + { + /// + /// Persist a session checkpoint and return the stored checkpoint + /// + Task SaveAsync(Checkpoint checkpoint); + /// + /// Load a checkpoint by session and checkpoint identifier + /// + Task LoadAsync(string sessionId, string checkpointId); + /// + /// List checkpoints for a session + /// + Task> ListCheckpointsAsync(string sessionId); + } diff --git a/runtime/csharp/Prompty.Core/Model/pipeline/CompactionConfig.cs b/runtime/csharp/Prompty.Core/Model/pipeline/CompactionConfig.cs index ae7cc9b1..438375d9 100644 --- a/runtime/csharp/Prompty.Core/Model/pipeline/CompactionConfig.cs +++ b/runtime/csharp/Prompty.Core/Model/pipeline/CompactionConfig.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,13 +7,13 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Configuration for context window compaction. When the message history -/// -/// exceeds the context budget, the compaction strategy is applied to -/// -/// reduce the message list while preserving essential information. -/// + /// + /// Configuration for context window compaction. When the message history + /// + /// exceeds the context budget, the compaction strategy is applied to + /// + /// reduce the message list while preserving essential information. + /// public partial class CompactionConfig { /// diff --git a/runtime/csharp/Prompty.Core/Model/pipeline/EventJournalWriter.cs b/runtime/csharp/Prompty.Core/Model/pipeline/EventJournalWriter.cs index ac698266..7f4c5dd3 100644 --- a/runtime/csharp/Prompty.Core/Model/pipeline/EventJournalWriter.cs +++ b/runtime/csharp/Prompty.Core/Model/pipeline/EventJournalWriter.cs @@ -1,24 +1,25 @@ +// // Copyright (c) Microsoft. All rights reserved. #pragma warning disable IDE0130 namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Persists typed events to a durable replay journal. -/// -public interface IEventJournalWriter -{ /// - /// Append a turn event to a durable replay journal + /// Persists typed events to a durable replay journal. /// - bool AppendTurn(TurnEvent turnEvent); - /// - /// Append a session event to a durable replay journal - /// - bool AppendSession(SessionEvent sessionEvent); - /// - /// Finalize the journal with an optional session summary - /// - bool Close(SessionSummary? summary); -} + public interface IEventJournalWriter + { + /// + /// Append a turn event to a durable replay journal + /// + bool AppendTurn(TurnEvent turnEvent); + /// + /// Append a session event to a durable replay journal + /// + bool AppendSession(SessionEvent sessionEvent); + /// + /// Finalize the journal with an optional session summary + /// + bool Close(SessionSummary? summary); + } diff --git a/runtime/csharp/Prompty.Core/Model/pipeline/EventSink.cs b/runtime/csharp/Prompty.Core/Model/pipeline/EventSink.cs index 8e3f9187..fb58472c 100644 --- a/runtime/csharp/Prompty.Core/Model/pipeline/EventSink.cs +++ b/runtime/csharp/Prompty.Core/Model/pipeline/EventSink.cs @@ -1,20 +1,21 @@ +// // Copyright (c) Microsoft. All rights reserved. #pragma warning disable IDE0130 namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Receives typed turn and session events from a harness. -/// -public interface IEventSink -{ /// - /// Emit a typed turn event to a host sink + /// Receives typed turn and session events from a harness. /// - bool EmitTurn(TurnEvent turnEvent); - /// - /// Emit a typed session event to a host sink - /// - bool EmitSession(SessionEvent sessionEvent); -} + public interface IEventSink + { + /// + /// Emit a typed turn event to a host sink + /// + bool EmitTurn(TurnEvent turnEvent); + /// + /// Emit a typed session event to a host sink + /// + bool EmitSession(SessionEvent sessionEvent); + } diff --git a/runtime/csharp/Prompty.Core/Model/pipeline/Executor.cs b/runtime/csharp/Prompty.Core/Model/pipeline/Executor.cs index 730bbc48..b641b4f5 100644 --- a/runtime/csharp/Prompty.Core/Model/pipeline/Executor.cs +++ b/runtime/csharp/Prompty.Core/Model/pipeline/Executor.cs @@ -1,24 +1,25 @@ +// // Copyright (c) Microsoft. All rights reserved. #pragma warning disable IDE0130 namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Calls an LLM provider with messages and returns the raw provider response. -/// -public interface IExecutor -{ /// - /// Call an LLM provider with messages and return the raw response + /// Calls an LLM provider with messages and returns the raw provider response. /// - Task ExecuteAsync(Prompty agent, List messages); - /// - /// Call an LLM provider and return a streaming response. Returns a language-specific async iterable/stream of raw chunks. Not all providers support streaming; the default implementation should signal lack of support. - /// - Task ExecuteStreamAsync(Prompty agent, List messages) => Task.FromResult(default!); - /// - /// Format tool call results into messages for the next iteration - /// - List FormatToolMessages(object rawResponse, List toolCalls, List toolResults, string? textContent); -} + public interface IExecutor + { + /// + /// Call an LLM provider with messages and return the raw response + /// + Task ExecuteAsync(Prompty agent, List messages); + /// + /// Call an LLM provider and return a streaming response. Returns a language-specific async iterable/stream of raw chunks. Not all providers support streaming; the default implementation should signal lack of support. + /// + Task ExecuteStreamAsync(Prompty agent, List messages) => Task.FromResult(default!); + /// + /// Format tool call results into messages for the next iteration + /// + List FormatToolMessages(object rawResponse, List toolCalls, List toolResults, string? textContent); + } diff --git a/runtime/csharp/Prompty.Core/Model/pipeline/HostToolExecutor.cs b/runtime/csharp/Prompty.Core/Model/pipeline/HostToolExecutor.cs index d82751e9..e51f2c34 100644 --- a/runtime/csharp/Prompty.Core/Model/pipeline/HostToolExecutor.cs +++ b/runtime/csharp/Prompty.Core/Model/pipeline/HostToolExecutor.cs @@ -1,16 +1,17 @@ +// // Copyright (c) Microsoft. All rights reserved. #pragma warning disable IDE0130 namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Executes host tools after policy and permission checks. -/// -public interface IHostToolExecutor -{ /// - /// Execute a concrete host tool request and return its completion payload + /// Executes host tools after policy and permission checks. /// - Task ExecuteAsync(HostToolRequest request); -} + public interface IHostToolExecutor + { + /// + /// Execute a concrete host tool request and return its completion payload + /// + Task ExecuteAsync(HostToolRequest request); + } diff --git a/runtime/csharp/Prompty.Core/Model/pipeline/Parser.cs b/runtime/csharp/Prompty.Core/Model/pipeline/Parser.cs index a50f65c4..46167af1 100644 --- a/runtime/csharp/Prompty.Core/Model/pipeline/Parser.cs +++ b/runtime/csharp/Prompty.Core/Model/pipeline/Parser.cs @@ -1,20 +1,21 @@ +// // Copyright (c) Microsoft. All rights reserved. #pragma warning disable IDE0130 namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Parses rendered prompt text into an array of structured messages with role markers. -/// -public interface IParser -{ /// - /// Pre-process a template before rendering, returning modified template and context + /// Parses rendered prompt text into an array of structured messages with role markers. /// - object? PreRender(string template) => default!; - /// - /// Parse rendered text into a structured message array - /// - Task> ParseAsync(Prompty agent, string rendered, Dictionary? context); -} + public interface IParser + { + /// + /// Pre-process a template before rendering, returning modified template and context + /// + object? PreRender(string template) => default!; + /// + /// Parse rendered text into a structured message array + /// + Task> ParseAsync(Prompty agent, string rendered, Dictionary? context); + } diff --git a/runtime/csharp/Prompty.Core/Model/pipeline/PermissionResolver.cs b/runtime/csharp/Prompty.Core/Model/pipeline/PermissionResolver.cs index 13e8d026..721178ff 100644 --- a/runtime/csharp/Prompty.Core/Model/pipeline/PermissionResolver.cs +++ b/runtime/csharp/Prompty.Core/Model/pipeline/PermissionResolver.cs @@ -1,16 +1,17 @@ +// // Copyright (c) Microsoft. All rights reserved. #pragma warning disable IDE0130 namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Resolves host permission requests for potentially sensitive actions. -/// -public interface IPermissionResolver -{ /// - /// Resolve a host permission request + /// Resolves host permission requests for potentially sensitive actions. /// - Task RequestAsync(PermissionRequest request); -} + public interface IPermissionResolver + { + /// + /// Resolve a host permission request + /// + Task RequestAsync(PermissionRequest request); + } diff --git a/runtime/csharp/Prompty.Core/Model/pipeline/Processor.cs b/runtime/csharp/Prompty.Core/Model/pipeline/Processor.cs index aa82e37d..8153b828 100644 --- a/runtime/csharp/Prompty.Core/Model/pipeline/Processor.cs +++ b/runtime/csharp/Prompty.Core/Model/pipeline/Processor.cs @@ -1,20 +1,21 @@ +// // Copyright (c) Microsoft. All rights reserved. #pragma warning disable IDE0130 namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Extracts a clean, typed result from a raw LLM provider response. -/// -public interface IProcessor -{ /// - /// Extract a clean result from a raw LLM response + /// Extracts a clean, typed result from a raw LLM provider response. /// - Task ProcessAsync(Prompty agent, object response); - /// - /// Process a streaming response into a stream of StreamChunk items. Takes raw chunks from the executor and yields processed text, thinking, tool, or error chunks. Not all providers support streaming; the default implementation should signal lack of support. - /// - Task ProcessStreamAsync(object stream) => Task.FromResult(default!); -} + public interface IProcessor + { + /// + /// Extract a clean result from a raw LLM response + /// + Task ProcessAsync(Prompty agent, object response); + /// + /// Process a streaming response into a stream of StreamChunk items. Takes raw chunks from the executor and yields processed text, thinking, tool, or error chunks. Not all providers support streaming; the default implementation should signal lack of support. + /// + Task ProcessStreamAsync(object stream) => Task.FromResult(default!); + } diff --git a/runtime/csharp/Prompty.Core/Model/pipeline/Renderer.cs b/runtime/csharp/Prompty.Core/Model/pipeline/Renderer.cs index 67682679..232d42c7 100644 --- a/runtime/csharp/Prompty.Core/Model/pipeline/Renderer.cs +++ b/runtime/csharp/Prompty.Core/Model/pipeline/Renderer.cs @@ -1,16 +1,17 @@ +// // Copyright (c) Microsoft. All rights reserved. #pragma warning disable IDE0130 namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Renders a template string with input values to produce the final prompt text. -/// -public interface IRenderer -{ /// - /// Render the template string with input values + /// Renders a template string with input values to produce the final prompt text. /// - Task RenderAsync(Prompty agent, string template, Dictionary inputs); -} + public interface IRenderer + { + /// + /// Render the template string with input values + /// + Task RenderAsync(Prompty agent, string template, Dictionary inputs); + } diff --git a/runtime/csharp/Prompty.Core/Model/pipeline/TurnOptions.cs b/runtime/csharp/Prompty.Core/Model/pipeline/TurnOptions.cs index 5a001022..ae61154b 100644 --- a/runtime/csharp/Prompty.Core/Model/pipeline/TurnOptions.cs +++ b/runtime/csharp/Prompty.Core/Model/pipeline/TurnOptions.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,17 +7,17 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Configuration for the agent loop's turn() function. Controls iteration -/// -/// limits, retry policy, context management, and execution behavior. -/// -/// Runtimes accept these as either a TurnOptions object or individual -/// -/// keyword/named parameters — the TypeSpec model defines the canonical -/// -/// field set. -/// + /// + /// Configuration for the agent loop's turn() function. Controls iteration + /// + /// limits, retry policy, context management, and execution behavior. + /// + /// Runtimes accept these as either a TurnOptions object or individual + /// + /// keyword/named parameters — the TypeSpec model defines the canonical + /// + /// field set. + /// public partial class TurnOptions { /// diff --git a/runtime/csharp/Prompty.Core/Model/streaming/StreamOptions.cs b/runtime/csharp/Prompty.Core/Model/streaming/StreamOptions.cs index dfccd58e..200c46e7 100644 --- a/runtime/csharp/Prompty.Core/Model/streaming/StreamOptions.cs +++ b/runtime/csharp/Prompty.Core/Model/streaming/StreamOptions.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,11 +7,11 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Options controlling streaming behavior for LLM API calls. -/// -/// Passed alongside the model options when streaming is enabled. -/// + /// + /// Options controlling streaming behavior for LLM API calls. + /// + /// Passed alongside the model options when streaming is enabled. + /// public partial class StreamOptions { /// diff --git a/runtime/csharp/Prompty.Core/Model/template/FormatConfig.cs b/runtime/csharp/Prompty.Core/Model/template/FormatConfig.cs index 7eeab289..ee231d0a 100644 --- a/runtime/csharp/Prompty.Core/Model/template/FormatConfig.cs +++ b/runtime/csharp/Prompty.Core/Model/template/FormatConfig.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Template format definition -/// + /// + /// Template format definition + /// public partial class FormatConfig { /// diff --git a/runtime/csharp/Prompty.Core/Model/template/ParserConfig.cs b/runtime/csharp/Prompty.Core/Model/template/ParserConfig.cs index 04616f9d..5ffceb02 100644 --- a/runtime/csharp/Prompty.Core/Model/template/ParserConfig.cs +++ b/runtime/csharp/Prompty.Core/Model/template/ParserConfig.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Template parser definition -/// + /// + /// Template parser definition + /// public partial class ParserConfig { /// diff --git a/runtime/csharp/Prompty.Core/Model/template/Template.cs b/runtime/csharp/Prompty.Core/Model/template/Template.cs index b33d35cf..e35e379e 100644 --- a/runtime/csharp/Prompty.Core/Model/template/Template.cs +++ b/runtime/csharp/Prompty.Core/Model/template/Template.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,19 +7,19 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Template model for defining prompt templates. -/// -/// This model specifies the rendering engine used for slot filling prompts, -/// -/// the parser used to process the rendered template into API-compatible format, -/// -/// and additional options for the template engine. -/// -/// It allows for the creation of reusable templates that can be filled with dynamic data -/// -/// and processed to generate prompts for AI models. -/// + /// + /// Template model for defining prompt templates. + /// + /// This model specifies the rendering engine used for slot filling prompts, + /// + /// the parser used to process the rendered template into API-compatible format, + /// + /// and additional options for the template engine. + /// + /// It allows for the creation of reusable templates that can be filled with dynamic data + /// + /// and processed to generate prompts for AI models. + /// public partial class Template { /// diff --git a/runtime/csharp/Prompty.Core/Model/tools/Binding.cs b/runtime/csharp/Prompty.Core/Model/tools/Binding.cs index 1990e8f3..65e896f4 100644 --- a/runtime/csharp/Prompty.Core/Model/tools/Binding.cs +++ b/runtime/csharp/Prompty.Core/Model/tools/Binding.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Represents a binding between an input property and a tool parameter. -/// + /// + /// Represents a binding between an input property and a tool parameter. + /// public partial class Binding { /// diff --git a/runtime/csharp/Prompty.Core/Model/tools/CustomTool.cs b/runtime/csharp/Prompty.Core/Model/tools/CustomTool.cs index d7f10e50..f6b0ff8f 100644 --- a/runtime/csharp/Prompty.Core/Model/tools/CustomTool.cs +++ b/runtime/csharp/Prompty.Core/Model/tools/CustomTool.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,17 +7,17 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Represents a generic server tool that runs on a server -/// -/// This tool kind is designed for operations that require server-side execution -/// -/// It may include features such as authentication, data storage, and long-running processes -/// -/// This tool kind is ideal for tasks that involve complex computations or access to secure resources -/// -/// Server tools can be used to offload heavy processing from client applications -/// + /// + /// Represents a generic server tool that runs on a server + /// + /// This tool kind is designed for operations that require server-side execution + /// + /// It may include features such as authentication, data storage, and long-running processes + /// + /// This tool kind is ideal for tasks that involve complex computations or access to secure resources + /// + /// Server tools can be used to offload heavy processing from client applications + /// public partial class CustomTool : Tool { /// diff --git a/runtime/csharp/Prompty.Core/Model/tools/FunctionTool.cs b/runtime/csharp/Prompty.Core/Model/tools/FunctionTool.cs index 6a8bb165..9d2a5e69 100644 --- a/runtime/csharp/Prompty.Core/Model/tools/FunctionTool.cs +++ b/runtime/csharp/Prompty.Core/Model/tools/FunctionTool.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Represents a local function tool. -/// + /// + /// Represents a local function tool. + /// public partial class FunctionTool : Tool { /// diff --git a/runtime/csharp/Prompty.Core/Model/tools/McpApprovalMode.cs b/runtime/csharp/Prompty.Core/Model/tools/McpApprovalMode.cs index 4379da7b..bd69fd5c 100644 --- a/runtime/csharp/Prompty.Core/Model/tools/McpApprovalMode.cs +++ b/runtime/csharp/Prompty.Core/Model/tools/McpApprovalMode.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,13 +7,13 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// The approval mode for MCP server tools. -/// -/// When kind is "specify", use alwaysRequireApprovalTools and neverRequireApprovalTools -/// -/// to control per-tool approval. For "always" and "never", those fields are ignored. -/// + /// + /// The approval mode for MCP server tools. + /// + /// When kind is "specify", use alwaysRequireApprovalTools and neverRequireApprovalTools + /// + /// to control per-tool approval. For "always" and "never", those fields are ignored. + /// public partial class McpApprovalMode { /// diff --git a/runtime/csharp/Prompty.Core/Model/tools/McpApprovalModeKind.cs b/runtime/csharp/Prompty.Core/Model/tools/McpApprovalModeKind.cs index e1c2a5cc..fb978c8e 100644 --- a/runtime/csharp/Prompty.Core/Model/tools/McpApprovalModeKind.cs +++ b/runtime/csharp/Prompty.Core/Model/tools/McpApprovalModeKind.cs @@ -1,5 +1,6 @@ +// // -// Code generated by Prompty emitter; DO NOT EDIT. +// Code generated by Typra emitter; DO NOT EDIT. using System.Text.Json.Serialization; diff --git a/runtime/csharp/Prompty.Core/Model/tools/McpTool.cs b/runtime/csharp/Prompty.Core/Model/tools/McpTool.cs index 8ce8e077..b8e3cb6d 100644 --- a/runtime/csharp/Prompty.Core/Model/tools/McpTool.cs +++ b/runtime/csharp/Prompty.Core/Model/tools/McpTool.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// The MCP Server tool. -/// + /// + /// The MCP Server tool. + /// public partial class McpTool : Tool { /// diff --git a/runtime/csharp/Prompty.Core/Model/tools/OpenApiTool.cs b/runtime/csharp/Prompty.Core/Model/tools/OpenApiTool.cs index b895d92b..6cc42578 100644 --- a/runtime/csharp/Prompty.Core/Model/tools/OpenApiTool.cs +++ b/runtime/csharp/Prompty.Core/Model/tools/OpenApiTool.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,8 +7,8 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// + /// + /// public partial class OpenApiTool : Tool { /// diff --git a/runtime/csharp/Prompty.Core/Model/tools/PromptyTool.cs b/runtime/csharp/Prompty.Core/Model/tools/PromptyTool.cs index 3b9135b5..02dec593 100644 --- a/runtime/csharp/Prompty.Core/Model/tools/PromptyTool.cs +++ b/runtime/csharp/Prompty.Core/Model/tools/PromptyTool.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,13 +7,13 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// A tool that references another .prompty file to be invoked as a tool. -/// -/// The child prompty is executed as a single prompt invocation. Nested agent -/// -/// loops are intentionally not started from PromptyTool. -/// + /// + /// A tool that references another .prompty file to be invoked as a tool. + /// + /// The child prompty is executed as a single prompt invocation. Nested agent + /// + /// loops are intentionally not started from PromptyTool. + /// public partial class PromptyTool : Tool { /// diff --git a/runtime/csharp/Prompty.Core/Model/tools/Tool.cs b/runtime/csharp/Prompty.Core/Model/tools/Tool.cs index 3a19125c..f37e9ca0 100644 --- a/runtime/csharp/Prompty.Core/Model/tools/Tool.cs +++ b/runtime/csharp/Prompty.Core/Model/tools/Tool.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Represents a tool that can be used in prompts. -/// + /// + /// Represents a tool that can be used in prompts. + /// public abstract partial class Tool { /// diff --git a/runtime/csharp/Prompty.Core/Model/tools/ToolContext.cs b/runtime/csharp/Prompty.Core/Model/tools/ToolContext.cs index 22d4b9da..e94becdd 100644 --- a/runtime/csharp/Prompty.Core/Model/tools/ToolContext.cs +++ b/runtime/csharp/Prompty.Core/Model/tools/ToolContext.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,13 +7,13 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Context passed to tool handlers during agent loop execution. Provides -/// -/// access to the agent configuration, current conversation state, and -/// -/// arbitrary metadata for tool implementations that need broader context. -/// + /// + /// Context passed to tool handlers during agent loop execution. Provides + /// + /// access to the agent configuration, current conversation state, and + /// + /// arbitrary metadata for tool implementations that need broader context. + /// public partial class ToolContext { /// diff --git a/runtime/csharp/Prompty.Core/Model/tools/ToolDispatchResult.cs b/runtime/csharp/Prompty.Core/Model/tools/ToolDispatchResult.cs index 730411ce..6508ef0c 100644 --- a/runtime/csharp/Prompty.Core/Model/tools/ToolDispatchResult.cs +++ b/runtime/csharp/Prompty.Core/Model/tools/ToolDispatchResult.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,13 +7,13 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// The result of dispatching a single tool call. Pairs the tool call -/// -/// identifier with the tool's name and result for correlation in the -/// -/// agent loop's message assembly. -/// + /// + /// The result of dispatching a single tool call. Pairs the tool call + /// + /// identifier with the tool's name and result for correlation in the + /// + /// agent loop's message assembly. + /// public partial class ToolDispatchResult { /// diff --git a/runtime/csharp/Prompty.Core/Model/tracing/TraceFile.cs b/runtime/csharp/Prompty.Core/Model/tracing/TraceFile.cs index e931d2c5..841aef88 100644 --- a/runtime/csharp/Prompty.Core/Model/tracing/TraceFile.cs +++ b/runtime/csharp/Prompty.Core/Model/tracing/TraceFile.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// The top-level .tracy file structure written by the file backend (§3.6.1). -/// + /// + /// The top-level .tracy file structure written by the file backend (§3.6.1). + /// public partial class TraceFile { /// diff --git a/runtime/csharp/Prompty.Core/Model/tracing/TraceSpan.cs b/runtime/csharp/Prompty.Core/Model/tracing/TraceSpan.cs index c7bd178d..5136543f 100644 --- a/runtime/csharp/Prompty.Core/Model/tracing/TraceSpan.cs +++ b/runtime/csharp/Prompty.Core/Model/tracing/TraceSpan.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,13 +7,13 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// A single trace span capturing one pipeline stage or function invocation. -/// -/// Spans nest via the `__frames` field to form a tree representing the -/// -/// full execution (§3.6.1). -/// + /// + /// A single trace span capturing one pipeline stage or function invocation. + /// + /// Spans nest via the `__frames` field to form a tree representing the + /// + /// full execution (§3.6.1). + /// public partial class TraceSpan { /// diff --git a/runtime/csharp/Prompty.Core/Model/tracing/TraceTime.cs b/runtime/csharp/Prompty.Core/Model/tracing/TraceTime.cs index a33015c5..ff77d50c 100644 --- a/runtime/csharp/Prompty.Core/Model/tracing/TraceTime.cs +++ b/runtime/csharp/Prompty.Core/Model/tracing/TraceTime.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Timing information for a trace span. -/// + /// + /// Timing information for a trace span. + /// public partial class TraceTime { /// diff --git a/runtime/csharp/Prompty.Core/Model/wire/AnthropicImageBlock.cs b/runtime/csharp/Prompty.Core/Model/wire/AnthropicImageBlock.cs index 140d05f8..6b4f6294 100644 --- a/runtime/csharp/Prompty.Core/Model/wire/AnthropicImageBlock.cs +++ b/runtime/csharp/Prompty.Core/Model/wire/AnthropicImageBlock.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,11 +7,11 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// An image content block using base64-encoded data. -/// -/// Anthropic requires images as base64 with an explicit media type. -/// + /// + /// An image content block using base64-encoded data. + /// + /// Anthropic requires images as base64 with an explicit media type. + /// public partial class AnthropicImageBlock { /// diff --git a/runtime/csharp/Prompty.Core/Model/wire/AnthropicImageSource.cs b/runtime/csharp/Prompty.Core/Model/wire/AnthropicImageSource.cs index 70daff2d..f535d756 100644 --- a/runtime/csharp/Prompty.Core/Model/wire/AnthropicImageSource.cs +++ b/runtime/csharp/Prompty.Core/Model/wire/AnthropicImageSource.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Source descriptor for an Anthropic base64 image. -/// + /// + /// Source descriptor for an Anthropic base64 image. + /// public partial class AnthropicImageSource { /// diff --git a/runtime/csharp/Prompty.Core/Model/wire/AnthropicMessagesRequest.cs b/runtime/csharp/Prompty.Core/Model/wire/AnthropicMessagesRequest.cs index d17002d2..cbf44f5b 100644 --- a/runtime/csharp/Prompty.Core/Model/wire/AnthropicMessagesRequest.cs +++ b/runtime/csharp/Prompty.Core/Model/wire/AnthropicMessagesRequest.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// The full request body for the Anthropic Messages API (§7.5). -/// + /// + /// The full request body for the Anthropic Messages API (§7.5). + /// public partial class AnthropicMessagesRequest { /// diff --git a/runtime/csharp/Prompty.Core/Model/wire/AnthropicMessagesResponse.cs b/runtime/csharp/Prompty.Core/Model/wire/AnthropicMessagesResponse.cs index 5fce011e..d1229006 100644 --- a/runtime/csharp/Prompty.Core/Model/wire/AnthropicMessagesResponse.cs +++ b/runtime/csharp/Prompty.Core/Model/wire/AnthropicMessagesResponse.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// The response body from the Anthropic Messages API. -/// + /// + /// The response body from the Anthropic Messages API. + /// public partial class AnthropicMessagesResponse { /// diff --git a/runtime/csharp/Prompty.Core/Model/wire/AnthropicTextBlock.cs b/runtime/csharp/Prompty.Core/Model/wire/AnthropicTextBlock.cs index 2dd16faa..3c9b4b14 100644 --- a/runtime/csharp/Prompty.Core/Model/wire/AnthropicTextBlock.cs +++ b/runtime/csharp/Prompty.Core/Model/wire/AnthropicTextBlock.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// A text content block in Anthropic's array-of-blocks message format. -/// + /// + /// A text content block in Anthropic's array-of-blocks message format. + /// public partial class AnthropicTextBlock { /// diff --git a/runtime/csharp/Prompty.Core/Model/wire/AnthropicToolDefinition.cs b/runtime/csharp/Prompty.Core/Model/wire/AnthropicToolDefinition.cs index e1aa5ac9..e747210c 100644 --- a/runtime/csharp/Prompty.Core/Model/wire/AnthropicToolDefinition.cs +++ b/runtime/csharp/Prompty.Core/Model/wire/AnthropicToolDefinition.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,13 +7,13 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// A tool definition in Anthropic's format. Unlike OpenAI which wraps -/// -/// tools in `{type: "function", function: {...}}`, Anthropic uses a -/// -/// flat structure with `input_schema` (§7.5). -/// + /// + /// A tool definition in Anthropic's format. Unlike OpenAI which wraps + /// + /// tools in `{type: "function", function: {...}}`, Anthropic uses a + /// + /// flat structure with `input_schema` (§7.5). + /// public partial class AnthropicToolDefinition { /// diff --git a/runtime/csharp/Prompty.Core/Model/wire/AnthropicToolResultBlock.cs b/runtime/csharp/Prompty.Core/Model/wire/AnthropicToolResultBlock.cs index 7a2d9f97..0e9f86a2 100644 --- a/runtime/csharp/Prompty.Core/Model/wire/AnthropicToolResultBlock.cs +++ b/runtime/csharp/Prompty.Core/Model/wire/AnthropicToolResultBlock.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// A tool result content block sent back to the API with the tool's output. -/// + /// + /// A tool result content block sent back to the API with the tool's output. + /// public partial class AnthropicToolResultBlock { /// diff --git a/runtime/csharp/Prompty.Core/Model/wire/AnthropicToolUseBlock.cs b/runtime/csharp/Prompty.Core/Model/wire/AnthropicToolUseBlock.cs index 574e8f2e..b32d3b10 100644 --- a/runtime/csharp/Prompty.Core/Model/wire/AnthropicToolUseBlock.cs +++ b/runtime/csharp/Prompty.Core/Model/wire/AnthropicToolUseBlock.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,11 +7,11 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// A tool use content block returned in an assistant message when -/// -/// the model wants to invoke a tool. -/// + /// + /// A tool use content block returned in an assistant message when + /// + /// the model wants to invoke a tool. + /// public partial class AnthropicToolUseBlock { /// diff --git a/runtime/csharp/Prompty.Core/Model/wire/AnthropicUsage.cs b/runtime/csharp/Prompty.Core/Model/wire/AnthropicUsage.cs index 6b5a92e0..ae1c3087 100644 --- a/runtime/csharp/Prompty.Core/Model/wire/AnthropicUsage.cs +++ b/runtime/csharp/Prompty.Core/Model/wire/AnthropicUsage.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,9 +7,9 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// Usage statistics returned in an Anthropic Messages API response. -/// + /// + /// Usage statistics returned in an Anthropic Messages API response. + /// public partial class AnthropicUsage { /// diff --git a/runtime/csharp/Prompty.Core/Model/wire/AnthropicWireMessage.cs b/runtime/csharp/Prompty.Core/Model/wire/AnthropicWireMessage.cs index 4dfe2332..edc93a2b 100644 --- a/runtime/csharp/Prompty.Core/Model/wire/AnthropicWireMessage.cs +++ b/runtime/csharp/Prompty.Core/Model/wire/AnthropicWireMessage.cs @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using YamlDotNet.Serialization; @@ -6,13 +7,13 @@ namespace Prompty.Core; #pragma warning restore IDE0130 -/// -/// A single message in the Anthropic Messages API wire format. -/// -/// Anthropic always uses the array-of-blocks form for content, -/// -/// even when there is only one text block (§7.5). -/// + /// + /// A single message in the Anthropic Messages API wire format. + /// + /// Anthropic always uses the array-of-blocks form for content, + /// + /// even when there is only one text block (§7.5). + /// public partial class AnthropicWireMessage { /// diff --git a/runtime/go/prompty/model/anonymous_connection_test.go b/runtime/go/prompty/model/anonymous_connection_test.go index 9fa7748d..053b28dc 100644 --- a/runtime/go/prompty/model/anonymous_connection_test.go +++ b/runtime/go/prompty/model/anonymous_connection_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/anthropic_image_block.go b/runtime/go/prompty/model/anthropic_image_block.go index 78dce7bd..2e357896 100644 --- a/runtime/go/prompty/model/anthropic_image_block.go +++ b/runtime/go/prompty/model/anthropic_image_block.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: wire package prompty diff --git a/runtime/go/prompty/model/anthropic_image_block_test.go b/runtime/go/prompty/model/anthropic_image_block_test.go index 3df1459b..9cc5440c 100644 --- a/runtime/go/prompty/model/anthropic_image_block_test.go +++ b/runtime/go/prompty/model/anthropic_image_block_test.go @@ -1,3 +1,4 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/anthropic_image_source.go b/runtime/go/prompty/model/anthropic_image_source.go index 4ac704ec..6d049e9d 100644 --- a/runtime/go/prompty/model/anthropic_image_source.go +++ b/runtime/go/prompty/model/anthropic_image_source.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: wire package prompty diff --git a/runtime/go/prompty/model/anthropic_image_source_test.go b/runtime/go/prompty/model/anthropic_image_source_test.go index 3e847ad4..019efb04 100644 --- a/runtime/go/prompty/model/anthropic_image_source_test.go +++ b/runtime/go/prompty/model/anthropic_image_source_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/anthropic_messages_request.go b/runtime/go/prompty/model/anthropic_messages_request.go index fcf8cf84..9f6f58e0 100644 --- a/runtime/go/prompty/model/anthropic_messages_request.go +++ b/runtime/go/prompty/model/anthropic_messages_request.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: wire package prompty diff --git a/runtime/go/prompty/model/anthropic_messages_request_test.go b/runtime/go/prompty/model/anthropic_messages_request_test.go index b8bffe53..c2ac945d 100644 --- a/runtime/go/prompty/model/anthropic_messages_request_test.go +++ b/runtime/go/prompty/model/anthropic_messages_request_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/anthropic_messages_response.go b/runtime/go/prompty/model/anthropic_messages_response.go index 05642b13..03aac94b 100644 --- a/runtime/go/prompty/model/anthropic_messages_response.go +++ b/runtime/go/prompty/model/anthropic_messages_response.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: wire package prompty diff --git a/runtime/go/prompty/model/anthropic_messages_response_test.go b/runtime/go/prompty/model/anthropic_messages_response_test.go index 9401e2c6..08f6d66c 100644 --- a/runtime/go/prompty/model/anthropic_messages_response_test.go +++ b/runtime/go/prompty/model/anthropic_messages_response_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/anthropic_text_block.go b/runtime/go/prompty/model/anthropic_text_block.go index d2e51a71..cfd40fef 100644 --- a/runtime/go/prompty/model/anthropic_text_block.go +++ b/runtime/go/prompty/model/anthropic_text_block.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: wire package prompty diff --git a/runtime/go/prompty/model/anthropic_text_block_test.go b/runtime/go/prompty/model/anthropic_text_block_test.go index df466eac..857054e7 100644 --- a/runtime/go/prompty/model/anthropic_text_block_test.go +++ b/runtime/go/prompty/model/anthropic_text_block_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/anthropic_tool_definition.go b/runtime/go/prompty/model/anthropic_tool_definition.go index dac8c6b8..f75e7939 100644 --- a/runtime/go/prompty/model/anthropic_tool_definition.go +++ b/runtime/go/prompty/model/anthropic_tool_definition.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: wire package prompty diff --git a/runtime/go/prompty/model/anthropic_tool_definition_test.go b/runtime/go/prompty/model/anthropic_tool_definition_test.go index 363de7ce..cd293aec 100644 --- a/runtime/go/prompty/model/anthropic_tool_definition_test.go +++ b/runtime/go/prompty/model/anthropic_tool_definition_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/anthropic_tool_result_block.go b/runtime/go/prompty/model/anthropic_tool_result_block.go index ca544225..63f088ae 100644 --- a/runtime/go/prompty/model/anthropic_tool_result_block.go +++ b/runtime/go/prompty/model/anthropic_tool_result_block.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: wire package prompty diff --git a/runtime/go/prompty/model/anthropic_tool_result_block_test.go b/runtime/go/prompty/model/anthropic_tool_result_block_test.go index 0dfacc78..92f699ee 100644 --- a/runtime/go/prompty/model/anthropic_tool_result_block_test.go +++ b/runtime/go/prompty/model/anthropic_tool_result_block_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/anthropic_tool_use_block.go b/runtime/go/prompty/model/anthropic_tool_use_block.go index c6eaa502..63852350 100644 --- a/runtime/go/prompty/model/anthropic_tool_use_block.go +++ b/runtime/go/prompty/model/anthropic_tool_use_block.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: wire package prompty diff --git a/runtime/go/prompty/model/anthropic_tool_use_block_test.go b/runtime/go/prompty/model/anthropic_tool_use_block_test.go index 8f4c14ef..88f049a5 100644 --- a/runtime/go/prompty/model/anthropic_tool_use_block_test.go +++ b/runtime/go/prompty/model/anthropic_tool_use_block_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/anthropic_usage.go b/runtime/go/prompty/model/anthropic_usage.go index 67581468..a03e3bcd 100644 --- a/runtime/go/prompty/model/anthropic_usage.go +++ b/runtime/go/prompty/model/anthropic_usage.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: wire package prompty diff --git a/runtime/go/prompty/model/anthropic_usage_test.go b/runtime/go/prompty/model/anthropic_usage_test.go index 2269d991..c6c31a6d 100644 --- a/runtime/go/prompty/model/anthropic_usage_test.go +++ b/runtime/go/prompty/model/anthropic_usage_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/anthropic_wire_message.go b/runtime/go/prompty/model/anthropic_wire_message.go index 232fb159..4b988eac 100644 --- a/runtime/go/prompty/model/anthropic_wire_message.go +++ b/runtime/go/prompty/model/anthropic_wire_message.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: wire package prompty diff --git a/runtime/go/prompty/model/anthropic_wire_message_test.go b/runtime/go/prompty/model/anthropic_wire_message_test.go index 825ca03d..6facf18a 100644 --- a/runtime/go/prompty/model/anthropic_wire_message_test.go +++ b/runtime/go/prompty/model/anthropic_wire_message_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/api_key_connection_test.go b/runtime/go/prompty/model/api_key_connection_test.go index 704e1116..fdf030a7 100644 --- a/runtime/go/prompty/model/api_key_connection_test.go +++ b/runtime/go/prompty/model/api_key_connection_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/array_property_test.go b/runtime/go/prompty/model/array_property_test.go index c487ac94..5438638a 100644 --- a/runtime/go/prompty/model/array_property_test.go +++ b/runtime/go/prompty/model/array_property_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/audio_part_test.go b/runtime/go/prompty/model/audio_part_test.go index 0d102fe6..85f74fbd 100644 --- a/runtime/go/prompty/model/audio_part_test.go +++ b/runtime/go/prompty/model/audio_part_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/binding.go b/runtime/go/prompty/model/binding.go index 26db55e4..bc578f25 100644 --- a/runtime/go/prompty/model/binding.go +++ b/runtime/go/prompty/model/binding.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: tools package prompty diff --git a/runtime/go/prompty/model/binding_test.go b/runtime/go/prompty/model/binding_test.go index dcb5032e..87f8362b 100644 --- a/runtime/go/prompty/model/binding_test.go +++ b/runtime/go/prompty/model/binding_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/checkpoint.go b/runtime/go/prompty/model/checkpoint.go index 5e9b22d6..a7a1f13a 100644 --- a/runtime/go/prompty/model/checkpoint.go +++ b/runtime/go/prompty/model/checkpoint.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/checkpoint_store.go b/runtime/go/prompty/model/checkpoint_store.go index fad18bd8..8d52f2c1 100644 --- a/runtime/go/prompty/model/checkpoint_store.go +++ b/runtime/go/prompty/model/checkpoint_store.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: pipeline package prompty diff --git a/runtime/go/prompty/model/checkpoint_test.go b/runtime/go/prompty/model/checkpoint_test.go index efb4db95..a1a646a2 100644 --- a/runtime/go/prompty/model/checkpoint_test.go +++ b/runtime/go/prompty/model/checkpoint_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/compaction_complete_payload.go b/runtime/go/prompty/model/compaction_complete_payload.go index 200fc406..1ff077c1 100644 --- a/runtime/go/prompty/model/compaction_complete_payload.go +++ b/runtime/go/prompty/model/compaction_complete_payload.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/compaction_complete_payload_test.go b/runtime/go/prompty/model/compaction_complete_payload_test.go index 48857482..29a0eb73 100644 --- a/runtime/go/prompty/model/compaction_complete_payload_test.go +++ b/runtime/go/prompty/model/compaction_complete_payload_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/compaction_config.go b/runtime/go/prompty/model/compaction_config.go index 7247164d..ba121403 100644 --- a/runtime/go/prompty/model/compaction_config.go +++ b/runtime/go/prompty/model/compaction_config.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: pipeline package prompty diff --git a/runtime/go/prompty/model/compaction_config_test.go b/runtime/go/prompty/model/compaction_config_test.go index 9f65c6f7..c70a452c 100644 --- a/runtime/go/prompty/model/compaction_config_test.go +++ b/runtime/go/prompty/model/compaction_config_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/compaction_failed_payload.go b/runtime/go/prompty/model/compaction_failed_payload.go index c04c0757..0d902cf0 100644 --- a/runtime/go/prompty/model/compaction_failed_payload.go +++ b/runtime/go/prompty/model/compaction_failed_payload.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/compaction_failed_payload_test.go b/runtime/go/prompty/model/compaction_failed_payload_test.go index f8d732b2..6e4a1752 100644 --- a/runtime/go/prompty/model/compaction_failed_payload_test.go +++ b/runtime/go/prompty/model/compaction_failed_payload_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/compaction_start_payload.go b/runtime/go/prompty/model/compaction_start_payload.go index 9bb287ef..2eb39772 100644 --- a/runtime/go/prompty/model/compaction_start_payload.go +++ b/runtime/go/prompty/model/compaction_start_payload.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/compaction_start_payload_test.go b/runtime/go/prompty/model/compaction_start_payload_test.go index 5864f038..ebd6c3d7 100644 --- a/runtime/go/prompty/model/compaction_start_payload_test.go +++ b/runtime/go/prompty/model/compaction_start_payload_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/connection.go b/runtime/go/prompty/model/connection.go index 72a5867e..88b12b92 100644 --- a/runtime/go/prompty/model/connection.go +++ b/runtime/go/prompty/model/connection.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: connection package prompty diff --git a/runtime/go/prompty/model/connection_test.go b/runtime/go/prompty/model/connection_test.go index b3c7c131..07be686a 100644 --- a/runtime/go/prompty/model/connection_test.go +++ b/runtime/go/prompty/model/connection_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/content_part.go b/runtime/go/prompty/model/content_part.go index a5e4bc58..8b68a1ce 100644 --- a/runtime/go/prompty/model/content_part.go +++ b/runtime/go/prompty/model/content_part.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: conversation package prompty diff --git a/runtime/go/prompty/model/content_part_test.go b/runtime/go/prompty/model/content_part_test.go index 3df1459b..9cc5440c 100644 --- a/runtime/go/prompty/model/content_part_test.go +++ b/runtime/go/prompty/model/content_part_test.go @@ -1,3 +1,4 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/context.go b/runtime/go/prompty/model/context.go index 5c54e776..01a2c614 100644 --- a/runtime/go/prompty/model/context.go +++ b/runtime/go/prompty/model/context.go @@ -1,5 +1,6 @@ -// Code generated by Prompty emitter; DO NOT EDIT. -// Prompty Context +// +// Code generated by Typra emitter; DO NOT EDIT. +// Typra Context package prompty diff --git a/runtime/go/prompty/model/custom_tool_test.go b/runtime/go/prompty/model/custom_tool_test.go index b8dff888..3fa2dc7d 100644 --- a/runtime/go/prompty/model/custom_tool_test.go +++ b/runtime/go/prompty/model/custom_tool_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/done_event_payload.go b/runtime/go/prompty/model/done_event_payload.go index ec35cdb0..aa004931 100644 --- a/runtime/go/prompty/model/done_event_payload.go +++ b/runtime/go/prompty/model/done_event_payload.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/done_event_payload_test.go b/runtime/go/prompty/model/done_event_payload_test.go index 3df1459b..9cc5440c 100644 --- a/runtime/go/prompty/model/done_event_payload_test.go +++ b/runtime/go/prompty/model/done_event_payload_test.go @@ -1,3 +1,4 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/error_chunk_test.go b/runtime/go/prompty/model/error_chunk_test.go index fea253a4..27eec536 100644 --- a/runtime/go/prompty/model/error_chunk_test.go +++ b/runtime/go/prompty/model/error_chunk_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/error_event_payload.go b/runtime/go/prompty/model/error_event_payload.go index 225b7eca..a6010eeb 100644 --- a/runtime/go/prompty/model/error_event_payload.go +++ b/runtime/go/prompty/model/error_event_payload.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/error_event_payload_test.go b/runtime/go/prompty/model/error_event_payload_test.go index fa37d308..ea1023f0 100644 --- a/runtime/go/prompty/model/error_event_payload_test.go +++ b/runtime/go/prompty/model/error_event_payload_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/event_journal_writer.go b/runtime/go/prompty/model/event_journal_writer.go index 8a2c9acc..bfd2885c 100644 --- a/runtime/go/prompty/model/event_journal_writer.go +++ b/runtime/go/prompty/model/event_journal_writer.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: pipeline package prompty diff --git a/runtime/go/prompty/model/event_sink.go b/runtime/go/prompty/model/event_sink.go index e38e8260..2d68bb04 100644 --- a/runtime/go/prompty/model/event_sink.go +++ b/runtime/go/prompty/model/event_sink.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: pipeline package prompty diff --git a/runtime/go/prompty/model/executor.go b/runtime/go/prompty/model/executor.go index 45f46545..8571abf7 100644 --- a/runtime/go/prompty/model/executor.go +++ b/runtime/go/prompty/model/executor.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: pipeline package prompty diff --git a/runtime/go/prompty/model/file_not_found_error.go b/runtime/go/prompty/model/file_not_found_error.go index b20cae9f..4d84b270 100644 --- a/runtime/go/prompty/model/file_not_found_error.go +++ b/runtime/go/prompty/model/file_not_found_error.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: core package prompty diff --git a/runtime/go/prompty/model/file_not_found_error_test.go b/runtime/go/prompty/model/file_not_found_error_test.go index ac823786..fd5990c6 100644 --- a/runtime/go/prompty/model/file_not_found_error_test.go +++ b/runtime/go/prompty/model/file_not_found_error_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/file_part_test.go b/runtime/go/prompty/model/file_part_test.go index 7cdb9712..e96edd93 100644 --- a/runtime/go/prompty/model/file_part_test.go +++ b/runtime/go/prompty/model/file_part_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/format_config.go b/runtime/go/prompty/model/format_config.go index 93b285bf..009007d0 100644 --- a/runtime/go/prompty/model/format_config.go +++ b/runtime/go/prompty/model/format_config.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: template package prompty diff --git a/runtime/go/prompty/model/format_config_test.go b/runtime/go/prompty/model/format_config_test.go index 9e3eebcb..49fe81ce 100644 --- a/runtime/go/prompty/model/format_config_test.go +++ b/runtime/go/prompty/model/format_config_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/foundry_connection_test.go b/runtime/go/prompty/model/foundry_connection_test.go index 53238e31..4956eaee 100644 --- a/runtime/go/prompty/model/foundry_connection_test.go +++ b/runtime/go/prompty/model/foundry_connection_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/function_tool_test.go b/runtime/go/prompty/model/function_tool_test.go index e961bd94..111930dc 100644 --- a/runtime/go/prompty/model/function_tool_test.go +++ b/runtime/go/prompty/model/function_tool_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/guardrail_result.go b/runtime/go/prompty/model/guardrail_result.go index c072506a..53a4e83f 100644 --- a/runtime/go/prompty/model/guardrail_result.go +++ b/runtime/go/prompty/model/guardrail_result.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: agent package prompty diff --git a/runtime/go/prompty/model/guardrail_result_test.go b/runtime/go/prompty/model/guardrail_result_test.go index 7b064d8e..0a895378 100644 --- a/runtime/go/prompty/model/guardrail_result_test.go +++ b/runtime/go/prompty/model/guardrail_result_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/harness_context.go b/runtime/go/prompty/model/harness_context.go index d9e3e484..648a78bb 100644 --- a/runtime/go/prompty/model/harness_context.go +++ b/runtime/go/prompty/model/harness_context.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/harness_context_test.go b/runtime/go/prompty/model/harness_context_test.go index f8c12155..329da9b7 100644 --- a/runtime/go/prompty/model/harness_context_test.go +++ b/runtime/go/prompty/model/harness_context_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/hook_end_payload.go b/runtime/go/prompty/model/hook_end_payload.go index 8b6ca7fb..cd42a504 100644 --- a/runtime/go/prompty/model/hook_end_payload.go +++ b/runtime/go/prompty/model/hook_end_payload.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/hook_end_payload_test.go b/runtime/go/prompty/model/hook_end_payload_test.go index cec7647e..f112a207 100644 --- a/runtime/go/prompty/model/hook_end_payload_test.go +++ b/runtime/go/prompty/model/hook_end_payload_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/hook_start_payload.go b/runtime/go/prompty/model/hook_start_payload.go index 529803f4..868db2cd 100644 --- a/runtime/go/prompty/model/hook_start_payload.go +++ b/runtime/go/prompty/model/hook_start_payload.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/hook_start_payload_test.go b/runtime/go/prompty/model/hook_start_payload_test.go index b6d65429..ace58f8c 100644 --- a/runtime/go/prompty/model/hook_start_payload_test.go +++ b/runtime/go/prompty/model/hook_start_payload_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/host_tool_executor.go b/runtime/go/prompty/model/host_tool_executor.go index 97650f48..5a19f6ac 100644 --- a/runtime/go/prompty/model/host_tool_executor.go +++ b/runtime/go/prompty/model/host_tool_executor.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: pipeline package prompty diff --git a/runtime/go/prompty/model/host_tool_request.go b/runtime/go/prompty/model/host_tool_request.go index d2abd541..1e69e5a6 100644 --- a/runtime/go/prompty/model/host_tool_request.go +++ b/runtime/go/prompty/model/host_tool_request.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/host_tool_request_test.go b/runtime/go/prompty/model/host_tool_request_test.go index 48023ef3..456a422e 100644 --- a/runtime/go/prompty/model/host_tool_request_test.go +++ b/runtime/go/prompty/model/host_tool_request_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/host_tool_result.go b/runtime/go/prompty/model/host_tool_result.go index eed30373..d0200c8b 100644 --- a/runtime/go/prompty/model/host_tool_result.go +++ b/runtime/go/prompty/model/host_tool_result.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/host_tool_result_test.go b/runtime/go/prompty/model/host_tool_result_test.go index 94e03d41..260ab230 100644 --- a/runtime/go/prompty/model/host_tool_result_test.go +++ b/runtime/go/prompty/model/host_tool_result_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/image_part_test.go b/runtime/go/prompty/model/image_part_test.go index fa60b8eb..1d5e2beb 100644 --- a/runtime/go/prompty/model/image_part_test.go +++ b/runtime/go/prompty/model/image_part_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/invoker_error.go b/runtime/go/prompty/model/invoker_error.go index 48067ce7..002016bf 100644 --- a/runtime/go/prompty/model/invoker_error.go +++ b/runtime/go/prompty/model/invoker_error.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: core package prompty diff --git a/runtime/go/prompty/model/invoker_error_test.go b/runtime/go/prompty/model/invoker_error_test.go index 8a46c697..98208aa8 100644 --- a/runtime/go/prompty/model/invoker_error_test.go +++ b/runtime/go/prompty/model/invoker_error_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/llm_complete_payload.go b/runtime/go/prompty/model/llm_complete_payload.go index ec4bc18c..a9102200 100644 --- a/runtime/go/prompty/model/llm_complete_payload.go +++ b/runtime/go/prompty/model/llm_complete_payload.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/llm_complete_payload_test.go b/runtime/go/prompty/model/llm_complete_payload_test.go index be9d3029..6c861e04 100644 --- a/runtime/go/prompty/model/llm_complete_payload_test.go +++ b/runtime/go/prompty/model/llm_complete_payload_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/llm_start_payload.go b/runtime/go/prompty/model/llm_start_payload.go index b0935e75..3422ecfe 100644 --- a/runtime/go/prompty/model/llm_start_payload.go +++ b/runtime/go/prompty/model/llm_start_payload.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/llm_start_payload_test.go b/runtime/go/prompty/model/llm_start_payload_test.go index 7371ba01..ab1f61b1 100644 --- a/runtime/go/prompty/model/llm_start_payload_test.go +++ b/runtime/go/prompty/model/llm_start_payload_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/mcp_approval_mode.go b/runtime/go/prompty/model/mcp_approval_mode.go index bc93f3a5..f08724cc 100644 --- a/runtime/go/prompty/model/mcp_approval_mode.go +++ b/runtime/go/prompty/model/mcp_approval_mode.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: tools package prompty diff --git a/runtime/go/prompty/model/mcp_approval_mode_test.go b/runtime/go/prompty/model/mcp_approval_mode_test.go index 5d85c3ff..c3318e97 100644 --- a/runtime/go/prompty/model/mcp_approval_mode_test.go +++ b/runtime/go/prompty/model/mcp_approval_mode_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/mcp_tool_test.go b/runtime/go/prompty/model/mcp_tool_test.go index 4f1f83d1..082ea06b 100644 --- a/runtime/go/prompty/model/mcp_tool_test.go +++ b/runtime/go/prompty/model/mcp_tool_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/message.go b/runtime/go/prompty/model/message.go index 3cdb2f4f..7fe6c04d 100644 --- a/runtime/go/prompty/model/message.go +++ b/runtime/go/prompty/model/message.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: conversation package prompty diff --git a/runtime/go/prompty/model/message_test.go b/runtime/go/prompty/model/message_test.go index 1168d19d..d5609a79 100644 --- a/runtime/go/prompty/model/message_test.go +++ b/runtime/go/prompty/model/message_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/messages_updated_payload.go b/runtime/go/prompty/model/messages_updated_payload.go index 772b8e04..17937fae 100644 --- a/runtime/go/prompty/model/messages_updated_payload.go +++ b/runtime/go/prompty/model/messages_updated_payload.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/messages_updated_payload_test.go b/runtime/go/prompty/model/messages_updated_payload_test.go index ef142962..9550f593 100644 --- a/runtime/go/prompty/model/messages_updated_payload_test.go +++ b/runtime/go/prompty/model/messages_updated_payload_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/model.go b/runtime/go/prompty/model/model.go index 3cfd9e30..2b823850 100644 --- a/runtime/go/prompty/model/model.go +++ b/runtime/go/prompty/model/model.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: model package prompty diff --git a/runtime/go/prompty/model/model_info.go b/runtime/go/prompty/model/model_info.go index a362e02b..20e4c99b 100644 --- a/runtime/go/prompty/model/model_info.go +++ b/runtime/go/prompty/model/model_info.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: model package prompty diff --git a/runtime/go/prompty/model/model_info_test.go b/runtime/go/prompty/model/model_info_test.go index dec61dea..63b81afe 100644 --- a/runtime/go/prompty/model/model_info_test.go +++ b/runtime/go/prompty/model/model_info_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/model_options.go b/runtime/go/prompty/model/model_options.go index 5ef6f708..aed0a2fa 100644 --- a/runtime/go/prompty/model/model_options.go +++ b/runtime/go/prompty/model/model_options.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: model package prompty diff --git a/runtime/go/prompty/model/model_options_test.go b/runtime/go/prompty/model/model_options_test.go index 36b7613a..9cc41ce5 100644 --- a/runtime/go/prompty/model/model_options_test.go +++ b/runtime/go/prompty/model/model_options_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/model_test.go b/runtime/go/prompty/model/model_test.go index debf8efd..b2833d4d 100644 --- a/runtime/go/prompty/model/model_test.go +++ b/runtime/go/prompty/model/model_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/o_auth_connection_test.go b/runtime/go/prompty/model/o_auth_connection_test.go index 4107d7d0..2319b8c2 100644 --- a/runtime/go/prompty/model/o_auth_connection_test.go +++ b/runtime/go/prompty/model/o_auth_connection_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/object_property_test.go b/runtime/go/prompty/model/object_property_test.go index 473a9518..6f61ef6f 100644 --- a/runtime/go/prompty/model/object_property_test.go +++ b/runtime/go/prompty/model/object_property_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/open_api_tool_test.go b/runtime/go/prompty/model/open_api_tool_test.go index 75f6cd2e..d1fdf749 100644 --- a/runtime/go/prompty/model/open_api_tool_test.go +++ b/runtime/go/prompty/model/open_api_tool_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/parser.go b/runtime/go/prompty/model/parser.go index 07089fcd..894c2578 100644 --- a/runtime/go/prompty/model/parser.go +++ b/runtime/go/prompty/model/parser.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: pipeline package prompty diff --git a/runtime/go/prompty/model/parser_config.go b/runtime/go/prompty/model/parser_config.go index b95334ec..b6f30c57 100644 --- a/runtime/go/prompty/model/parser_config.go +++ b/runtime/go/prompty/model/parser_config.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: template package prompty diff --git a/runtime/go/prompty/model/parser_config_test.go b/runtime/go/prompty/model/parser_config_test.go index 65160d3c..9cb689b2 100644 --- a/runtime/go/prompty/model/parser_config_test.go +++ b/runtime/go/prompty/model/parser_config_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/permission_completed_payload.go b/runtime/go/prompty/model/permission_completed_payload.go index 0673e31d..feb1fb9f 100644 --- a/runtime/go/prompty/model/permission_completed_payload.go +++ b/runtime/go/prompty/model/permission_completed_payload.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/permission_completed_payload_test.go b/runtime/go/prompty/model/permission_completed_payload_test.go index 51a43cb4..182067e3 100644 --- a/runtime/go/prompty/model/permission_completed_payload_test.go +++ b/runtime/go/prompty/model/permission_completed_payload_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/permission_decision.go b/runtime/go/prompty/model/permission_decision.go index bf481cfb..e7776100 100644 --- a/runtime/go/prompty/model/permission_decision.go +++ b/runtime/go/prompty/model/permission_decision.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/permission_decision_test.go b/runtime/go/prompty/model/permission_decision_test.go index dbb58f0e..ed5ccea9 100644 --- a/runtime/go/prompty/model/permission_decision_test.go +++ b/runtime/go/prompty/model/permission_decision_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/permission_request.go b/runtime/go/prompty/model/permission_request.go index 4c723889..2e6e90de 100644 --- a/runtime/go/prompty/model/permission_request.go +++ b/runtime/go/prompty/model/permission_request.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/permission_request_test.go b/runtime/go/prompty/model/permission_request_test.go index 16dc42ef..5f3574ea 100644 --- a/runtime/go/prompty/model/permission_request_test.go +++ b/runtime/go/prompty/model/permission_request_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/permission_requested_payload.go b/runtime/go/prompty/model/permission_requested_payload.go index 61276ab5..2ecd64ea 100644 --- a/runtime/go/prompty/model/permission_requested_payload.go +++ b/runtime/go/prompty/model/permission_requested_payload.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/permission_requested_payload_test.go b/runtime/go/prompty/model/permission_requested_payload_test.go index 2e440c5e..0c0de7b6 100644 --- a/runtime/go/prompty/model/permission_requested_payload_test.go +++ b/runtime/go/prompty/model/permission_requested_payload_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/permission_resolver.go b/runtime/go/prompty/model/permission_resolver.go index 1ea77c71..8c5694ad 100644 --- a/runtime/go/prompty/model/permission_resolver.go +++ b/runtime/go/prompty/model/permission_resolver.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: pipeline package prompty diff --git a/runtime/go/prompty/model/processor.go b/runtime/go/prompty/model/processor.go index 484c49df..23a83d37 100644 --- a/runtime/go/prompty/model/processor.go +++ b/runtime/go/prompty/model/processor.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: pipeline package prompty diff --git a/runtime/go/prompty/model/prompty.go b/runtime/go/prompty/model/prompty.go index 767e7666..1b499432 100644 --- a/runtime/go/prompty/model/prompty.go +++ b/runtime/go/prompty/model/prompty.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: agent package prompty diff --git a/runtime/go/prompty/model/prompty_test.go b/runtime/go/prompty/model/prompty_test.go index 24da9bda..6378da70 100644 --- a/runtime/go/prompty/model/prompty_test.go +++ b/runtime/go/prompty/model/prompty_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/prompty_tool_test.go b/runtime/go/prompty/model/prompty_tool_test.go index 74751407..b36ba59d 100644 --- a/runtime/go/prompty/model/prompty_tool_test.go +++ b/runtime/go/prompty/model/prompty_tool_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/property.go b/runtime/go/prompty/model/property.go index 570ae1ac..14b7ce31 100644 --- a/runtime/go/prompty/model/property.go +++ b/runtime/go/prompty/model/property.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: core package prompty diff --git a/runtime/go/prompty/model/property_test.go b/runtime/go/prompty/model/property_test.go index 33f3cfe1..945e4396 100644 --- a/runtime/go/prompty/model/property_test.go +++ b/runtime/go/prompty/model/property_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/redacted_field.go b/runtime/go/prompty/model/redacted_field.go index 41534104..70d63939 100644 --- a/runtime/go/prompty/model/redacted_field.go +++ b/runtime/go/prompty/model/redacted_field.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/redacted_field_test.go b/runtime/go/prompty/model/redacted_field_test.go index 399a44ee..bacb98cd 100644 --- a/runtime/go/prompty/model/redacted_field_test.go +++ b/runtime/go/prompty/model/redacted_field_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/redaction_metadata.go b/runtime/go/prompty/model/redaction_metadata.go index dad963c2..36218637 100644 --- a/runtime/go/prompty/model/redaction_metadata.go +++ b/runtime/go/prompty/model/redaction_metadata.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/redaction_metadata_test.go b/runtime/go/prompty/model/redaction_metadata_test.go index 35bc3e6f..e12ea0d4 100644 --- a/runtime/go/prompty/model/redaction_metadata_test.go +++ b/runtime/go/prompty/model/redaction_metadata_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/reference_connection_test.go b/runtime/go/prompty/model/reference_connection_test.go index eb94de54..f4ab381d 100644 --- a/runtime/go/prompty/model/reference_connection_test.go +++ b/runtime/go/prompty/model/reference_connection_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/remote_connection_test.go b/runtime/go/prompty/model/remote_connection_test.go index 91155772..6ce6b6ec 100644 --- a/runtime/go/prompty/model/remote_connection_test.go +++ b/runtime/go/prompty/model/remote_connection_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/renderer.go b/runtime/go/prompty/model/renderer.go index a500ca5d..76510e88 100644 --- a/runtime/go/prompty/model/renderer.go +++ b/runtime/go/prompty/model/renderer.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: pipeline package prompty diff --git a/runtime/go/prompty/model/retry_payload.go b/runtime/go/prompty/model/retry_payload.go index c0a8bb96..f1057fb5 100644 --- a/runtime/go/prompty/model/retry_payload.go +++ b/runtime/go/prompty/model/retry_payload.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/retry_payload_test.go b/runtime/go/prompty/model/retry_payload_test.go index 1f106558..19113bc6 100644 --- a/runtime/go/prompty/model/retry_payload_test.go +++ b/runtime/go/prompty/model/retry_payload_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/session_end_payload.go b/runtime/go/prompty/model/session_end_payload.go index 0eb61674..be968217 100644 --- a/runtime/go/prompty/model/session_end_payload.go +++ b/runtime/go/prompty/model/session_end_payload.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/session_end_payload_test.go b/runtime/go/prompty/model/session_end_payload_test.go index a31a3629..263986c2 100644 --- a/runtime/go/prompty/model/session_end_payload_test.go +++ b/runtime/go/prompty/model/session_end_payload_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/session_event.go b/runtime/go/prompty/model/session_event.go index 63fb67f5..2b2081c2 100644 --- a/runtime/go/prompty/model/session_event.go +++ b/runtime/go/prompty/model/session_event.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/session_event_test.go b/runtime/go/prompty/model/session_event_test.go index af9f2d90..2fbf5270 100644 --- a/runtime/go/prompty/model/session_event_test.go +++ b/runtime/go/prompty/model/session_event_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/session_file_ref.go b/runtime/go/prompty/model/session_file_ref.go index bee2bde6..e6e4df6a 100644 --- a/runtime/go/prompty/model/session_file_ref.go +++ b/runtime/go/prompty/model/session_file_ref.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/session_file_ref_test.go b/runtime/go/prompty/model/session_file_ref_test.go index 82b0f3b0..187663a9 100644 --- a/runtime/go/prompty/model/session_file_ref_test.go +++ b/runtime/go/prompty/model/session_file_ref_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/session_ref.go b/runtime/go/prompty/model/session_ref.go index 3d116c82..cbd19ece 100644 --- a/runtime/go/prompty/model/session_ref.go +++ b/runtime/go/prompty/model/session_ref.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/session_ref_test.go b/runtime/go/prompty/model/session_ref_test.go index b9aed1fc..7bbe90c9 100644 --- a/runtime/go/prompty/model/session_ref_test.go +++ b/runtime/go/prompty/model/session_ref_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/session_start_payload.go b/runtime/go/prompty/model/session_start_payload.go index 9c11166f..b642e5c9 100644 --- a/runtime/go/prompty/model/session_start_payload.go +++ b/runtime/go/prompty/model/session_start_payload.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/session_start_payload_test.go b/runtime/go/prompty/model/session_start_payload_test.go index ad3fd52d..8aba7f73 100644 --- a/runtime/go/prompty/model/session_start_payload_test.go +++ b/runtime/go/prompty/model/session_start_payload_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/session_summary.go b/runtime/go/prompty/model/session_summary.go index 9f0f9b50..c83f4ab6 100644 --- a/runtime/go/prompty/model/session_summary.go +++ b/runtime/go/prompty/model/session_summary.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/session_summary_test.go b/runtime/go/prompty/model/session_summary_test.go index 3e9e9ca7..55ac95d0 100644 --- a/runtime/go/prompty/model/session_summary_test.go +++ b/runtime/go/prompty/model/session_summary_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/session_trace.go b/runtime/go/prompty/model/session_trace.go index 48f2e6ee..f8fe8bfd 100644 --- a/runtime/go/prompty/model/session_trace.go +++ b/runtime/go/prompty/model/session_trace.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/session_trace_test.go b/runtime/go/prompty/model/session_trace_test.go index 9996b709..a5b2cb02 100644 --- a/runtime/go/prompty/model/session_trace_test.go +++ b/runtime/go/prompty/model/session_trace_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/session_warning_payload.go b/runtime/go/prompty/model/session_warning_payload.go index b11ff11d..af0e39b8 100644 --- a/runtime/go/prompty/model/session_warning_payload.go +++ b/runtime/go/prompty/model/session_warning_payload.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/session_warning_payload_test.go b/runtime/go/prompty/model/session_warning_payload_test.go index ad8bae01..273124d7 100644 --- a/runtime/go/prompty/model/session_warning_payload_test.go +++ b/runtime/go/prompty/model/session_warning_payload_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/status_event_payload.go b/runtime/go/prompty/model/status_event_payload.go index 6b0d6e20..d7d3db3c 100644 --- a/runtime/go/prompty/model/status_event_payload.go +++ b/runtime/go/prompty/model/status_event_payload.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/status_event_payload_test.go b/runtime/go/prompty/model/status_event_payload_test.go index f5a6cdd0..b76f9a19 100644 --- a/runtime/go/prompty/model/status_event_payload_test.go +++ b/runtime/go/prompty/model/status_event_payload_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/stream_chunk.go b/runtime/go/prompty/model/stream_chunk.go index c0a17e33..714705f6 100644 --- a/runtime/go/prompty/model/stream_chunk.go +++ b/runtime/go/prompty/model/stream_chunk.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/stream_chunk_test.go b/runtime/go/prompty/model/stream_chunk_test.go index 3df1459b..9cc5440c 100644 --- a/runtime/go/prompty/model/stream_chunk_test.go +++ b/runtime/go/prompty/model/stream_chunk_test.go @@ -1,3 +1,4 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/stream_options.go b/runtime/go/prompty/model/stream_options.go index 951ad9f8..6527f6d8 100644 --- a/runtime/go/prompty/model/stream_options.go +++ b/runtime/go/prompty/model/stream_options.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: streaming package prompty diff --git a/runtime/go/prompty/model/stream_options_test.go b/runtime/go/prompty/model/stream_options_test.go index ac3fd0ab..6f4a274a 100644 --- a/runtime/go/prompty/model/stream_options_test.go +++ b/runtime/go/prompty/model/stream_options_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/template.go b/runtime/go/prompty/model/template.go index 00de91da..2e2c5b53 100644 --- a/runtime/go/prompty/model/template.go +++ b/runtime/go/prompty/model/template.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: template package prompty diff --git a/runtime/go/prompty/model/template_test.go b/runtime/go/prompty/model/template_test.go index 2e38d149..fba6744f 100644 --- a/runtime/go/prompty/model/template_test.go +++ b/runtime/go/prompty/model/template_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/text_chunk_test.go b/runtime/go/prompty/model/text_chunk_test.go index a02caf8a..aff59956 100644 --- a/runtime/go/prompty/model/text_chunk_test.go +++ b/runtime/go/prompty/model/text_chunk_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/text_part_test.go b/runtime/go/prompty/model/text_part_test.go index f1eb5b6f..742286a9 100644 --- a/runtime/go/prompty/model/text_part_test.go +++ b/runtime/go/prompty/model/text_part_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/thinking_chunk_test.go b/runtime/go/prompty/model/thinking_chunk_test.go index 3c2ea35d..14c1dc60 100644 --- a/runtime/go/prompty/model/thinking_chunk_test.go +++ b/runtime/go/prompty/model/thinking_chunk_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/thinking_event_payload.go b/runtime/go/prompty/model/thinking_event_payload.go index 123e7306..0cb6db91 100644 --- a/runtime/go/prompty/model/thinking_event_payload.go +++ b/runtime/go/prompty/model/thinking_event_payload.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/thinking_event_payload_test.go b/runtime/go/prompty/model/thinking_event_payload_test.go index 9902cea5..36260c01 100644 --- a/runtime/go/prompty/model/thinking_event_payload_test.go +++ b/runtime/go/prompty/model/thinking_event_payload_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/thread_marker.go b/runtime/go/prompty/model/thread_marker.go index 6c0cc46c..c86ad2d4 100644 --- a/runtime/go/prompty/model/thread_marker.go +++ b/runtime/go/prompty/model/thread_marker.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: conversation package prompty diff --git a/runtime/go/prompty/model/thread_marker_test.go b/runtime/go/prompty/model/thread_marker_test.go index cfa2c6ed..781fc8bd 100644 --- a/runtime/go/prompty/model/thread_marker_test.go +++ b/runtime/go/prompty/model/thread_marker_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/token_event_payload.go b/runtime/go/prompty/model/token_event_payload.go index c7fa00f0..c3151a2e 100644 --- a/runtime/go/prompty/model/token_event_payload.go +++ b/runtime/go/prompty/model/token_event_payload.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/token_event_payload_test.go b/runtime/go/prompty/model/token_event_payload_test.go index c6221d92..91769945 100644 --- a/runtime/go/prompty/model/token_event_payload_test.go +++ b/runtime/go/prompty/model/token_event_payload_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/token_usage.go b/runtime/go/prompty/model/token_usage.go index e19bee07..d85f351c 100644 --- a/runtime/go/prompty/model/token_usage.go +++ b/runtime/go/prompty/model/token_usage.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: model package prompty diff --git a/runtime/go/prompty/model/token_usage_test.go b/runtime/go/prompty/model/token_usage_test.go index 1e662647..dd649ad5 100644 --- a/runtime/go/prompty/model/token_usage_test.go +++ b/runtime/go/prompty/model/token_usage_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/tool.go b/runtime/go/prompty/model/tool.go index 9124b57c..48d46486 100644 --- a/runtime/go/prompty/model/tool.go +++ b/runtime/go/prompty/model/tool.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: tools package prompty diff --git a/runtime/go/prompty/model/tool_call.go b/runtime/go/prompty/model/tool_call.go index 7584ed99..8796e6ee 100644 --- a/runtime/go/prompty/model/tool_call.go +++ b/runtime/go/prompty/model/tool_call.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: conversation package prompty diff --git a/runtime/go/prompty/model/tool_call_complete_payload.go b/runtime/go/prompty/model/tool_call_complete_payload.go index b02d3672..427b3b14 100644 --- a/runtime/go/prompty/model/tool_call_complete_payload.go +++ b/runtime/go/prompty/model/tool_call_complete_payload.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/tool_call_complete_payload_test.go b/runtime/go/prompty/model/tool_call_complete_payload_test.go index 5f3f5ffe..ba7b11f5 100644 --- a/runtime/go/prompty/model/tool_call_complete_payload_test.go +++ b/runtime/go/prompty/model/tool_call_complete_payload_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/tool_call_start_payload.go b/runtime/go/prompty/model/tool_call_start_payload.go index 94db6dfd..6817a60a 100644 --- a/runtime/go/prompty/model/tool_call_start_payload.go +++ b/runtime/go/prompty/model/tool_call_start_payload.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/tool_call_start_payload_test.go b/runtime/go/prompty/model/tool_call_start_payload_test.go index 1cc86cd8..e3a534b0 100644 --- a/runtime/go/prompty/model/tool_call_start_payload_test.go +++ b/runtime/go/prompty/model/tool_call_start_payload_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/tool_call_test.go b/runtime/go/prompty/model/tool_call_test.go index d52a1740..7585868e 100644 --- a/runtime/go/prompty/model/tool_call_test.go +++ b/runtime/go/prompty/model/tool_call_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/tool_chunk_test.go b/runtime/go/prompty/model/tool_chunk_test.go index b8a70749..0bc09c61 100644 --- a/runtime/go/prompty/model/tool_chunk_test.go +++ b/runtime/go/prompty/model/tool_chunk_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/tool_context.go b/runtime/go/prompty/model/tool_context.go index 5c15a4ea..777f98ff 100644 --- a/runtime/go/prompty/model/tool_context.go +++ b/runtime/go/prompty/model/tool_context.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: tools package prompty diff --git a/runtime/go/prompty/model/tool_context_test.go b/runtime/go/prompty/model/tool_context_test.go index 4dddc6bf..5a45f2f1 100644 --- a/runtime/go/prompty/model/tool_context_test.go +++ b/runtime/go/prompty/model/tool_context_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/tool_dispatch_result.go b/runtime/go/prompty/model/tool_dispatch_result.go index 6492d5c5..95985a8f 100644 --- a/runtime/go/prompty/model/tool_dispatch_result.go +++ b/runtime/go/prompty/model/tool_dispatch_result.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: tools package prompty diff --git a/runtime/go/prompty/model/tool_dispatch_result_test.go b/runtime/go/prompty/model/tool_dispatch_result_test.go index 354ecf68..939045dc 100644 --- a/runtime/go/prompty/model/tool_dispatch_result_test.go +++ b/runtime/go/prompty/model/tool_dispatch_result_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/tool_execution_complete_payload.go b/runtime/go/prompty/model/tool_execution_complete_payload.go index b0a05e4f..9bd9d1b7 100644 --- a/runtime/go/prompty/model/tool_execution_complete_payload.go +++ b/runtime/go/prompty/model/tool_execution_complete_payload.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/tool_execution_complete_payload_test.go b/runtime/go/prompty/model/tool_execution_complete_payload_test.go index f15d0a22..67c89554 100644 --- a/runtime/go/prompty/model/tool_execution_complete_payload_test.go +++ b/runtime/go/prompty/model/tool_execution_complete_payload_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/tool_execution_start_payload.go b/runtime/go/prompty/model/tool_execution_start_payload.go index 7ac5c4d1..5ae0ebe9 100644 --- a/runtime/go/prompty/model/tool_execution_start_payload.go +++ b/runtime/go/prompty/model/tool_execution_start_payload.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/tool_execution_start_payload_test.go b/runtime/go/prompty/model/tool_execution_start_payload_test.go index 1e1392e6..d9c425fc 100644 --- a/runtime/go/prompty/model/tool_execution_start_payload_test.go +++ b/runtime/go/prompty/model/tool_execution_start_payload_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/tool_result.go b/runtime/go/prompty/model/tool_result.go index 9bfb5bc6..f5328808 100644 --- a/runtime/go/prompty/model/tool_result.go +++ b/runtime/go/prompty/model/tool_result.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: conversation package prompty diff --git a/runtime/go/prompty/model/tool_result_payload.go b/runtime/go/prompty/model/tool_result_payload.go index 514dce79..82b22b7e 100644 --- a/runtime/go/prompty/model/tool_result_payload.go +++ b/runtime/go/prompty/model/tool_result_payload.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/tool_result_payload_test.go b/runtime/go/prompty/model/tool_result_payload_test.go index 218ad74f..3052d58b 100644 --- a/runtime/go/prompty/model/tool_result_payload_test.go +++ b/runtime/go/prompty/model/tool_result_payload_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/tool_result_test.go b/runtime/go/prompty/model/tool_result_test.go index c409d41a..dca5a445 100644 --- a/runtime/go/prompty/model/tool_result_test.go +++ b/runtime/go/prompty/model/tool_result_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/tool_test.go b/runtime/go/prompty/model/tool_test.go index 8e5519f4..8fd8866a 100644 --- a/runtime/go/prompty/model/tool_test.go +++ b/runtime/go/prompty/model/tool_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/trace_file.go b/runtime/go/prompty/model/trace_file.go index bb696675..829e85c6 100644 --- a/runtime/go/prompty/model/trace_file.go +++ b/runtime/go/prompty/model/trace_file.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: tracing package prompty diff --git a/runtime/go/prompty/model/trace_file_test.go b/runtime/go/prompty/model/trace_file_test.go index 69658e4a..ca60fa81 100644 --- a/runtime/go/prompty/model/trace_file_test.go +++ b/runtime/go/prompty/model/trace_file_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/trace_span.go b/runtime/go/prompty/model/trace_span.go index 1deba3ad..31ca0ca6 100644 --- a/runtime/go/prompty/model/trace_span.go +++ b/runtime/go/prompty/model/trace_span.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: tracing package prompty diff --git a/runtime/go/prompty/model/trace_span_test.go b/runtime/go/prompty/model/trace_span_test.go index 5e6eae92..a1586656 100644 --- a/runtime/go/prompty/model/trace_span_test.go +++ b/runtime/go/prompty/model/trace_span_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/trace_time.go b/runtime/go/prompty/model/trace_time.go index 0fe1db62..e423b32a 100644 --- a/runtime/go/prompty/model/trace_time.go +++ b/runtime/go/prompty/model/trace_time.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: tracing package prompty diff --git a/runtime/go/prompty/model/trace_time_test.go b/runtime/go/prompty/model/trace_time_test.go index 56092ce1..dd9a91ac 100644 --- a/runtime/go/prompty/model/trace_time_test.go +++ b/runtime/go/prompty/model/trace_time_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/trajectory_event.go b/runtime/go/prompty/model/trajectory_event.go index b49a8c07..cb94c651 100644 --- a/runtime/go/prompty/model/trajectory_event.go +++ b/runtime/go/prompty/model/trajectory_event.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/trajectory_event_test.go b/runtime/go/prompty/model/trajectory_event_test.go index cdf24bdf..ed874d5d 100644 --- a/runtime/go/prompty/model/trajectory_event_test.go +++ b/runtime/go/prompty/model/trajectory_event_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/turn_end_payload.go b/runtime/go/prompty/model/turn_end_payload.go index 52e5ee14..6ce17dcd 100644 --- a/runtime/go/prompty/model/turn_end_payload.go +++ b/runtime/go/prompty/model/turn_end_payload.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/turn_end_payload_test.go b/runtime/go/prompty/model/turn_end_payload_test.go index c28ae0fe..e33a8cd0 100644 --- a/runtime/go/prompty/model/turn_end_payload_test.go +++ b/runtime/go/prompty/model/turn_end_payload_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/turn_event.go b/runtime/go/prompty/model/turn_event.go index c9f4b5d0..56a00b79 100644 --- a/runtime/go/prompty/model/turn_event.go +++ b/runtime/go/prompty/model/turn_event.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/turn_event_test.go b/runtime/go/prompty/model/turn_event_test.go index b1fc2dcb..5212da43 100644 --- a/runtime/go/prompty/model/turn_event_test.go +++ b/runtime/go/prompty/model/turn_event_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/turn_options.go b/runtime/go/prompty/model/turn_options.go index 08f60735..47876a43 100644 --- a/runtime/go/prompty/model/turn_options.go +++ b/runtime/go/prompty/model/turn_options.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: pipeline package prompty diff --git a/runtime/go/prompty/model/turn_options_test.go b/runtime/go/prompty/model/turn_options_test.go index c448023d..c25ed2fe 100644 --- a/runtime/go/prompty/model/turn_options_test.go +++ b/runtime/go/prompty/model/turn_options_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/turn_start_payload.go b/runtime/go/prompty/model/turn_start_payload.go index c127fa7a..b913b5bf 100644 --- a/runtime/go/prompty/model/turn_start_payload.go +++ b/runtime/go/prompty/model/turn_start_payload.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/turn_start_payload_test.go b/runtime/go/prompty/model/turn_start_payload_test.go index d9af183b..deb0fef2 100644 --- a/runtime/go/prompty/model/turn_start_payload_test.go +++ b/runtime/go/prompty/model/turn_start_payload_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/turn_summary.go b/runtime/go/prompty/model/turn_summary.go index 56be90fe..f59e8818 100644 --- a/runtime/go/prompty/model/turn_summary.go +++ b/runtime/go/prompty/model/turn_summary.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/turn_summary_test.go b/runtime/go/prompty/model/turn_summary_test.go index feb7c04c..5a58f518 100644 --- a/runtime/go/prompty/model/turn_summary_test.go +++ b/runtime/go/prompty/model/turn_summary_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/turn_trace.go b/runtime/go/prompty/model/turn_trace.go index 92693f33..56f573c8 100644 --- a/runtime/go/prompty/model/turn_trace.go +++ b/runtime/go/prompty/model/turn_trace.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: events package prompty diff --git a/runtime/go/prompty/model/turn_trace_test.go b/runtime/go/prompty/model/turn_trace_test.go index 2de9b5ac..1bf580f2 100644 --- a/runtime/go/prompty/model/turn_trace_test.go +++ b/runtime/go/prompty/model/turn_trace_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/validation_error.go b/runtime/go/prompty/model/validation_error.go index d20b1e12..f5556045 100644 --- a/runtime/go/prompty/model/validation_error.go +++ b/runtime/go/prompty/model/validation_error.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: core package prompty diff --git a/runtime/go/prompty/model/validation_error_test.go b/runtime/go/prompty/model/validation_error_test.go index 530c25a0..61bf8ad2 100644 --- a/runtime/go/prompty/model/validation_error_test.go +++ b/runtime/go/prompty/model/validation_error_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/go/prompty/model/validation_result.go b/runtime/go/prompty/model/validation_result.go index ab7a5701..23ab233e 100644 --- a/runtime/go/prompty/model/validation_result.go +++ b/runtime/go/prompty/model/validation_result.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Group: core package prompty diff --git a/runtime/go/prompty/model/validation_result_test.go b/runtime/go/prompty/model/validation_result_test.go index 9467217a..b259ea22 100644 --- a/runtime/go/prompty/model/validation_result_test.go +++ b/runtime/go/prompty/model/validation_result_test.go @@ -1,4 +1,5 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. package prompty_test diff --git a/runtime/python/prompty/prompty/model/__init__.py b/runtime/python/prompty/prompty/model/__init__.py index 3c00cd3e..68d0b307 100644 --- a/runtime/python/prompty/prompty/model/__init__.py +++ b/runtime/python/prompty/prompty/model/__init__.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/_context.py b/runtime/python/prompty/prompty/model/_context.py index 961fd708..c29e102c 100644 --- a/runtime/python/prompty/prompty/model/_context.py +++ b/runtime/python/prompty/prompty/model/_context.py @@ -1,4 +1,5 @@ -# Prompty LoadContext +# +# Typra LoadContext import json from collections.abc import Callable from dataclasses import dataclass diff --git a/runtime/python/prompty/prompty/model/agent/_GuardrailResult.py b/runtime/python/prompty/prompty/model/agent/_GuardrailResult.py index 6fe41041..ed297f00 100644 --- a/runtime/python/prompty/prompty/model/agent/_GuardrailResult.py +++ b/runtime/python/prompty/prompty/model/agent/_GuardrailResult.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/agent/_Prompty.py b/runtime/python/prompty/prompty/model/agent/_Prompty.py index 9bdfbeee..bdd60c33 100644 --- a/runtime/python/prompty/prompty/model/agent/_Prompty.py +++ b/runtime/python/prompty/prompty/model/agent/_Prompty.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/agent/__init__.py b/runtime/python/prompty/prompty/model/agent/__init__.py index ca1d0971..c475977a 100644 --- a/runtime/python/prompty/prompty/model/agent/__init__.py +++ b/runtime/python/prompty/prompty/model/agent/__init__.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/connection/_Connection.py b/runtime/python/prompty/prompty/model/connection/_Connection.py index 64f91a85..9df3d76f 100644 --- a/runtime/python/prompty/prompty/model/connection/_Connection.py +++ b/runtime/python/prompty/prompty/model/connection/_Connection.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/connection/__init__.py b/runtime/python/prompty/prompty/model/connection/__init__.py index 21677c89..344b6de4 100644 --- a/runtime/python/prompty/prompty/model/connection/__init__.py +++ b/runtime/python/prompty/prompty/model/connection/__init__.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/conversation/_ContentPart.py b/runtime/python/prompty/prompty/model/conversation/_ContentPart.py index b4c12736..af4e9004 100644 --- a/runtime/python/prompty/prompty/model/conversation/_ContentPart.py +++ b/runtime/python/prompty/prompty/model/conversation/_ContentPart.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/conversation/_Message.py b/runtime/python/prompty/prompty/model/conversation/_Message.py index 4f4a4342..8ee2fee0 100644 --- a/runtime/python/prompty/prompty/model/conversation/_Message.py +++ b/runtime/python/prompty/prompty/model/conversation/_Message.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/conversation/_ThreadMarker.py b/runtime/python/prompty/prompty/model/conversation/_ThreadMarker.py index 02f8728c..fc0d905b 100644 --- a/runtime/python/prompty/prompty/model/conversation/_ThreadMarker.py +++ b/runtime/python/prompty/prompty/model/conversation/_ThreadMarker.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/conversation/_ToolCall.py b/runtime/python/prompty/prompty/model/conversation/_ToolCall.py index 5c4526c8..08e44bad 100644 --- a/runtime/python/prompty/prompty/model/conversation/_ToolCall.py +++ b/runtime/python/prompty/prompty/model/conversation/_ToolCall.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/conversation/_ToolResult.py b/runtime/python/prompty/prompty/model/conversation/_ToolResult.py index c5192e01..3586a1ee 100644 --- a/runtime/python/prompty/prompty/model/conversation/_ToolResult.py +++ b/runtime/python/prompty/prompty/model/conversation/_ToolResult.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/conversation/__init__.py b/runtime/python/prompty/prompty/model/conversation/__init__.py index f9113dfb..33695a04 100644 --- a/runtime/python/prompty/prompty/model/conversation/__init__.py +++ b/runtime/python/prompty/prompty/model/conversation/__init__.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/core/_FileNotFoundError.py b/runtime/python/prompty/prompty/model/core/_FileNotFoundError.py index c663be66..47e95a79 100644 --- a/runtime/python/prompty/prompty/model/core/_FileNotFoundError.py +++ b/runtime/python/prompty/prompty/model/core/_FileNotFoundError.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/core/_InvokerError.py b/runtime/python/prompty/prompty/model/core/_InvokerError.py index 4b3d89f6..74bdd871 100644 --- a/runtime/python/prompty/prompty/model/core/_InvokerError.py +++ b/runtime/python/prompty/prompty/model/core/_InvokerError.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/core/_Property.py b/runtime/python/prompty/prompty/model/core/_Property.py index efa07454..13087bea 100644 --- a/runtime/python/prompty/prompty/model/core/_Property.py +++ b/runtime/python/prompty/prompty/model/core/_Property.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/core/_ValidationError.py b/runtime/python/prompty/prompty/model/core/_ValidationError.py index 2d1ee4cc..9efc6540 100644 --- a/runtime/python/prompty/prompty/model/core/_ValidationError.py +++ b/runtime/python/prompty/prompty/model/core/_ValidationError.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/core/_ValidationResult.py b/runtime/python/prompty/prompty/model/core/_ValidationResult.py index c603770b..d28edd55 100644 --- a/runtime/python/prompty/prompty/model/core/_ValidationResult.py +++ b/runtime/python/prompty/prompty/model/core/_ValidationResult.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/core/__init__.py b/runtime/python/prompty/prompty/model/core/__init__.py index 66a70e34..9f77200d 100644 --- a/runtime/python/prompty/prompty/model/core/__init__.py +++ b/runtime/python/prompty/prompty/model/core/__init__.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_Checkpoint.py b/runtime/python/prompty/prompty/model/events/_Checkpoint.py index b9dca919..7977d5ec 100644 --- a/runtime/python/prompty/prompty/model/events/_Checkpoint.py +++ b/runtime/python/prompty/prompty/model/events/_Checkpoint.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_CompactionCompletePayload.py b/runtime/python/prompty/prompty/model/events/_CompactionCompletePayload.py index 45c8486e..ae387785 100644 --- a/runtime/python/prompty/prompty/model/events/_CompactionCompletePayload.py +++ b/runtime/python/prompty/prompty/model/events/_CompactionCompletePayload.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_CompactionFailedPayload.py b/runtime/python/prompty/prompty/model/events/_CompactionFailedPayload.py index a8332923..e7d6f200 100644 --- a/runtime/python/prompty/prompty/model/events/_CompactionFailedPayload.py +++ b/runtime/python/prompty/prompty/model/events/_CompactionFailedPayload.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_CompactionStartPayload.py b/runtime/python/prompty/prompty/model/events/_CompactionStartPayload.py index 6a1e90a2..574b01b8 100644 --- a/runtime/python/prompty/prompty/model/events/_CompactionStartPayload.py +++ b/runtime/python/prompty/prompty/model/events/_CompactionStartPayload.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_DoneEventPayload.py b/runtime/python/prompty/prompty/model/events/_DoneEventPayload.py index 9478b5eb..cb577223 100644 --- a/runtime/python/prompty/prompty/model/events/_DoneEventPayload.py +++ b/runtime/python/prompty/prompty/model/events/_DoneEventPayload.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_ErrorEventPayload.py b/runtime/python/prompty/prompty/model/events/_ErrorEventPayload.py index b27d74f7..8524888c 100644 --- a/runtime/python/prompty/prompty/model/events/_ErrorEventPayload.py +++ b/runtime/python/prompty/prompty/model/events/_ErrorEventPayload.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_HarnessContext.py b/runtime/python/prompty/prompty/model/events/_HarnessContext.py index da7c5be9..5480523f 100644 --- a/runtime/python/prompty/prompty/model/events/_HarnessContext.py +++ b/runtime/python/prompty/prompty/model/events/_HarnessContext.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_HookEndPayload.py b/runtime/python/prompty/prompty/model/events/_HookEndPayload.py index 02819f5e..f913b870 100644 --- a/runtime/python/prompty/prompty/model/events/_HookEndPayload.py +++ b/runtime/python/prompty/prompty/model/events/_HookEndPayload.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_HookStartPayload.py b/runtime/python/prompty/prompty/model/events/_HookStartPayload.py index edaa4496..b1e6171b 100644 --- a/runtime/python/prompty/prompty/model/events/_HookStartPayload.py +++ b/runtime/python/prompty/prompty/model/events/_HookStartPayload.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_HostToolRequest.py b/runtime/python/prompty/prompty/model/events/_HostToolRequest.py index e6c9e6db..24f9c717 100644 --- a/runtime/python/prompty/prompty/model/events/_HostToolRequest.py +++ b/runtime/python/prompty/prompty/model/events/_HostToolRequest.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_HostToolResult.py b/runtime/python/prompty/prompty/model/events/_HostToolResult.py index 82e8c064..c54872f5 100644 --- a/runtime/python/prompty/prompty/model/events/_HostToolResult.py +++ b/runtime/python/prompty/prompty/model/events/_HostToolResult.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_LlmCompletePayload.py b/runtime/python/prompty/prompty/model/events/_LlmCompletePayload.py index 274da046..d59608f4 100644 --- a/runtime/python/prompty/prompty/model/events/_LlmCompletePayload.py +++ b/runtime/python/prompty/prompty/model/events/_LlmCompletePayload.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_LlmStartPayload.py b/runtime/python/prompty/prompty/model/events/_LlmStartPayload.py index 8e5edd3c..719dd935 100644 --- a/runtime/python/prompty/prompty/model/events/_LlmStartPayload.py +++ b/runtime/python/prompty/prompty/model/events/_LlmStartPayload.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_MessagesUpdatedPayload.py b/runtime/python/prompty/prompty/model/events/_MessagesUpdatedPayload.py index 1e71aa26..42f8d612 100644 --- a/runtime/python/prompty/prompty/model/events/_MessagesUpdatedPayload.py +++ b/runtime/python/prompty/prompty/model/events/_MessagesUpdatedPayload.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_PermissionCompletedPayload.py b/runtime/python/prompty/prompty/model/events/_PermissionCompletedPayload.py index 100a2617..9215718a 100644 --- a/runtime/python/prompty/prompty/model/events/_PermissionCompletedPayload.py +++ b/runtime/python/prompty/prompty/model/events/_PermissionCompletedPayload.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_PermissionDecision.py b/runtime/python/prompty/prompty/model/events/_PermissionDecision.py index 61a50ba5..aaa61632 100644 --- a/runtime/python/prompty/prompty/model/events/_PermissionDecision.py +++ b/runtime/python/prompty/prompty/model/events/_PermissionDecision.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_PermissionRequest.py b/runtime/python/prompty/prompty/model/events/_PermissionRequest.py index b12bf6b7..85963dc0 100644 --- a/runtime/python/prompty/prompty/model/events/_PermissionRequest.py +++ b/runtime/python/prompty/prompty/model/events/_PermissionRequest.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_PermissionRequestedPayload.py b/runtime/python/prompty/prompty/model/events/_PermissionRequestedPayload.py index 2a4a2ebf..6125d53b 100644 --- a/runtime/python/prompty/prompty/model/events/_PermissionRequestedPayload.py +++ b/runtime/python/prompty/prompty/model/events/_PermissionRequestedPayload.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_RedactedField.py b/runtime/python/prompty/prompty/model/events/_RedactedField.py index 4ec2a2b2..59d929e6 100644 --- a/runtime/python/prompty/prompty/model/events/_RedactedField.py +++ b/runtime/python/prompty/prompty/model/events/_RedactedField.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_RedactionMetadata.py b/runtime/python/prompty/prompty/model/events/_RedactionMetadata.py index 1c16dbfc..0c325b01 100644 --- a/runtime/python/prompty/prompty/model/events/_RedactionMetadata.py +++ b/runtime/python/prompty/prompty/model/events/_RedactionMetadata.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_RetryPayload.py b/runtime/python/prompty/prompty/model/events/_RetryPayload.py index a9c58f34..215706aa 100644 --- a/runtime/python/prompty/prompty/model/events/_RetryPayload.py +++ b/runtime/python/prompty/prompty/model/events/_RetryPayload.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_SessionEndPayload.py b/runtime/python/prompty/prompty/model/events/_SessionEndPayload.py index 9a87cfbf..aec2e435 100644 --- a/runtime/python/prompty/prompty/model/events/_SessionEndPayload.py +++ b/runtime/python/prompty/prompty/model/events/_SessionEndPayload.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_SessionEvent.py b/runtime/python/prompty/prompty/model/events/_SessionEvent.py index 242fbd79..663e64b3 100644 --- a/runtime/python/prompty/prompty/model/events/_SessionEvent.py +++ b/runtime/python/prompty/prompty/model/events/_SessionEvent.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_SessionFileRef.py b/runtime/python/prompty/prompty/model/events/_SessionFileRef.py index 46013203..b932f69f 100644 --- a/runtime/python/prompty/prompty/model/events/_SessionFileRef.py +++ b/runtime/python/prompty/prompty/model/events/_SessionFileRef.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_SessionRef.py b/runtime/python/prompty/prompty/model/events/_SessionRef.py index 720a3167..9c7d22f1 100644 --- a/runtime/python/prompty/prompty/model/events/_SessionRef.py +++ b/runtime/python/prompty/prompty/model/events/_SessionRef.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_SessionStartPayload.py b/runtime/python/prompty/prompty/model/events/_SessionStartPayload.py index 81fbbf94..bc13ed0f 100644 --- a/runtime/python/prompty/prompty/model/events/_SessionStartPayload.py +++ b/runtime/python/prompty/prompty/model/events/_SessionStartPayload.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_SessionSummary.py b/runtime/python/prompty/prompty/model/events/_SessionSummary.py index c2e98c33..f3d7bb58 100644 --- a/runtime/python/prompty/prompty/model/events/_SessionSummary.py +++ b/runtime/python/prompty/prompty/model/events/_SessionSummary.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_SessionTrace.py b/runtime/python/prompty/prompty/model/events/_SessionTrace.py index 8457af1c..70bae77e 100644 --- a/runtime/python/prompty/prompty/model/events/_SessionTrace.py +++ b/runtime/python/prompty/prompty/model/events/_SessionTrace.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_SessionWarningPayload.py b/runtime/python/prompty/prompty/model/events/_SessionWarningPayload.py index e0a573e9..6b597c35 100644 --- a/runtime/python/prompty/prompty/model/events/_SessionWarningPayload.py +++ b/runtime/python/prompty/prompty/model/events/_SessionWarningPayload.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_StatusEventPayload.py b/runtime/python/prompty/prompty/model/events/_StatusEventPayload.py index 34a934ad..ad7bf9b8 100644 --- a/runtime/python/prompty/prompty/model/events/_StatusEventPayload.py +++ b/runtime/python/prompty/prompty/model/events/_StatusEventPayload.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_StreamChunk.py b/runtime/python/prompty/prompty/model/events/_StreamChunk.py index 5a668fc1..08078506 100644 --- a/runtime/python/prompty/prompty/model/events/_StreamChunk.py +++ b/runtime/python/prompty/prompty/model/events/_StreamChunk.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_ThinkingEventPayload.py b/runtime/python/prompty/prompty/model/events/_ThinkingEventPayload.py index f8732ca3..0639fcaf 100644 --- a/runtime/python/prompty/prompty/model/events/_ThinkingEventPayload.py +++ b/runtime/python/prompty/prompty/model/events/_ThinkingEventPayload.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_TokenEventPayload.py b/runtime/python/prompty/prompty/model/events/_TokenEventPayload.py index 59e3ea4d..e1ab3921 100644 --- a/runtime/python/prompty/prompty/model/events/_TokenEventPayload.py +++ b/runtime/python/prompty/prompty/model/events/_TokenEventPayload.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_ToolCallCompletePayload.py b/runtime/python/prompty/prompty/model/events/_ToolCallCompletePayload.py index 2f85b721..736fd44f 100644 --- a/runtime/python/prompty/prompty/model/events/_ToolCallCompletePayload.py +++ b/runtime/python/prompty/prompty/model/events/_ToolCallCompletePayload.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_ToolCallStartPayload.py b/runtime/python/prompty/prompty/model/events/_ToolCallStartPayload.py index b836732f..8870c6e6 100644 --- a/runtime/python/prompty/prompty/model/events/_ToolCallStartPayload.py +++ b/runtime/python/prompty/prompty/model/events/_ToolCallStartPayload.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_ToolExecutionCompletePayload.py b/runtime/python/prompty/prompty/model/events/_ToolExecutionCompletePayload.py index bcb9211f..dbb9de24 100644 --- a/runtime/python/prompty/prompty/model/events/_ToolExecutionCompletePayload.py +++ b/runtime/python/prompty/prompty/model/events/_ToolExecutionCompletePayload.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_ToolExecutionStartPayload.py b/runtime/python/prompty/prompty/model/events/_ToolExecutionStartPayload.py index f6517386..5421c4ac 100644 --- a/runtime/python/prompty/prompty/model/events/_ToolExecutionStartPayload.py +++ b/runtime/python/prompty/prompty/model/events/_ToolExecutionStartPayload.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_ToolResultPayload.py b/runtime/python/prompty/prompty/model/events/_ToolResultPayload.py index f621a884..d184dd71 100644 --- a/runtime/python/prompty/prompty/model/events/_ToolResultPayload.py +++ b/runtime/python/prompty/prompty/model/events/_ToolResultPayload.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_TrajectoryEvent.py b/runtime/python/prompty/prompty/model/events/_TrajectoryEvent.py index 71a2ddc6..aca0073f 100644 --- a/runtime/python/prompty/prompty/model/events/_TrajectoryEvent.py +++ b/runtime/python/prompty/prompty/model/events/_TrajectoryEvent.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_TurnEndPayload.py b/runtime/python/prompty/prompty/model/events/_TurnEndPayload.py index d4d532a0..9c8b1dfd 100644 --- a/runtime/python/prompty/prompty/model/events/_TurnEndPayload.py +++ b/runtime/python/prompty/prompty/model/events/_TurnEndPayload.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_TurnEvent.py b/runtime/python/prompty/prompty/model/events/_TurnEvent.py index 280d5ebc..4e447d8d 100644 --- a/runtime/python/prompty/prompty/model/events/_TurnEvent.py +++ b/runtime/python/prompty/prompty/model/events/_TurnEvent.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_TurnStartPayload.py b/runtime/python/prompty/prompty/model/events/_TurnStartPayload.py index 3584eddd..bb45b0e1 100644 --- a/runtime/python/prompty/prompty/model/events/_TurnStartPayload.py +++ b/runtime/python/prompty/prompty/model/events/_TurnStartPayload.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_TurnSummary.py b/runtime/python/prompty/prompty/model/events/_TurnSummary.py index 79d1c254..03bc0c37 100644 --- a/runtime/python/prompty/prompty/model/events/_TurnSummary.py +++ b/runtime/python/prompty/prompty/model/events/_TurnSummary.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/_TurnTrace.py b/runtime/python/prompty/prompty/model/events/_TurnTrace.py index 7dbcd956..99798bab 100644 --- a/runtime/python/prompty/prompty/model/events/_TurnTrace.py +++ b/runtime/python/prompty/prompty/model/events/_TurnTrace.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/events/__init__.py b/runtime/python/prompty/prompty/model/events/__init__.py index 0c80cdb2..f3cba7f8 100644 --- a/runtime/python/prompty/prompty/model/events/__init__.py +++ b/runtime/python/prompty/prompty/model/events/__init__.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/model/_Model.py b/runtime/python/prompty/prompty/model/model/_Model.py index 42633ca3..aa0341c5 100644 --- a/runtime/python/prompty/prompty/model/model/_Model.py +++ b/runtime/python/prompty/prompty/model/model/_Model.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/model/_ModelInfo.py b/runtime/python/prompty/prompty/model/model/_ModelInfo.py index 75a0c9e1..d1c5a9f5 100644 --- a/runtime/python/prompty/prompty/model/model/_ModelInfo.py +++ b/runtime/python/prompty/prompty/model/model/_ModelInfo.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/model/_ModelOptions.py b/runtime/python/prompty/prompty/model/model/_ModelOptions.py index 9326c2e2..a73310d7 100644 --- a/runtime/python/prompty/prompty/model/model/_ModelOptions.py +++ b/runtime/python/prompty/prompty/model/model/_ModelOptions.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/model/_TokenUsage.py b/runtime/python/prompty/prompty/model/model/_TokenUsage.py index 22d02c9d..e4ecd1ae 100644 --- a/runtime/python/prompty/prompty/model/model/_TokenUsage.py +++ b/runtime/python/prompty/prompty/model/model/_TokenUsage.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/model/__init__.py b/runtime/python/prompty/prompty/model/model/__init__.py index 672e31b9..1e4ae9e4 100644 --- a/runtime/python/prompty/prompty/model/model/__init__.py +++ b/runtime/python/prompty/prompty/model/model/__init__.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/pipeline/_CheckpointStore.py b/runtime/python/prompty/prompty/model/pipeline/_CheckpointStore.py index b19cbbaa..89681cac 100644 --- a/runtime/python/prompty/prompty/model/pipeline/_CheckpointStore.py +++ b/runtime/python/prompty/prompty/model/pipeline/_CheckpointStore.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/pipeline/_CompactionConfig.py b/runtime/python/prompty/prompty/model/pipeline/_CompactionConfig.py index 087b08b0..112bf9d0 100644 --- a/runtime/python/prompty/prompty/model/pipeline/_CompactionConfig.py +++ b/runtime/python/prompty/prompty/model/pipeline/_CompactionConfig.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/pipeline/_EventJournalWriter.py b/runtime/python/prompty/prompty/model/pipeline/_EventJournalWriter.py index dfe4340a..21960aeb 100644 --- a/runtime/python/prompty/prompty/model/pipeline/_EventJournalWriter.py +++ b/runtime/python/prompty/prompty/model/pipeline/_EventJournalWriter.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/pipeline/_EventSink.py b/runtime/python/prompty/prompty/model/pipeline/_EventSink.py index 5446f786..a78bbe1d 100644 --- a/runtime/python/prompty/prompty/model/pipeline/_EventSink.py +++ b/runtime/python/prompty/prompty/model/pipeline/_EventSink.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/pipeline/_Executor.py b/runtime/python/prompty/prompty/model/pipeline/_Executor.py index 4b18564f..2ec3313a 100644 --- a/runtime/python/prompty/prompty/model/pipeline/_Executor.py +++ b/runtime/python/prompty/prompty/model/pipeline/_Executor.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/pipeline/_HostToolExecutor.py b/runtime/python/prompty/prompty/model/pipeline/_HostToolExecutor.py index 5edb3425..46f451e3 100644 --- a/runtime/python/prompty/prompty/model/pipeline/_HostToolExecutor.py +++ b/runtime/python/prompty/prompty/model/pipeline/_HostToolExecutor.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/pipeline/_Parser.py b/runtime/python/prompty/prompty/model/pipeline/_Parser.py index 4ee14088..b9aebf0e 100644 --- a/runtime/python/prompty/prompty/model/pipeline/_Parser.py +++ b/runtime/python/prompty/prompty/model/pipeline/_Parser.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/pipeline/_PermissionResolver.py b/runtime/python/prompty/prompty/model/pipeline/_PermissionResolver.py index 2c6d90ef..306b6907 100644 --- a/runtime/python/prompty/prompty/model/pipeline/_PermissionResolver.py +++ b/runtime/python/prompty/prompty/model/pipeline/_PermissionResolver.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/pipeline/_Processor.py b/runtime/python/prompty/prompty/model/pipeline/_Processor.py index 78dea4d5..110e71c6 100644 --- a/runtime/python/prompty/prompty/model/pipeline/_Processor.py +++ b/runtime/python/prompty/prompty/model/pipeline/_Processor.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/pipeline/_Renderer.py b/runtime/python/prompty/prompty/model/pipeline/_Renderer.py index 02e0cf5e..c0794c6d 100644 --- a/runtime/python/prompty/prompty/model/pipeline/_Renderer.py +++ b/runtime/python/prompty/prompty/model/pipeline/_Renderer.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/pipeline/_TurnOptions.py b/runtime/python/prompty/prompty/model/pipeline/_TurnOptions.py index 1e64dccc..be8fdf9d 100644 --- a/runtime/python/prompty/prompty/model/pipeline/_TurnOptions.py +++ b/runtime/python/prompty/prompty/model/pipeline/_TurnOptions.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/pipeline/__init__.py b/runtime/python/prompty/prompty/model/pipeline/__init__.py index d17de053..7bfb7c77 100644 --- a/runtime/python/prompty/prompty/model/pipeline/__init__.py +++ b/runtime/python/prompty/prompty/model/pipeline/__init__.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/py.typed b/runtime/python/prompty/prompty/model/py.typed index e69de29b..66ab2838 100644 --- a/runtime/python/prompty/prompty/model/py.typed +++ b/runtime/python/prompty/prompty/model/py.typed @@ -0,0 +1 @@ +// diff --git a/runtime/python/prompty/prompty/model/streaming/_StreamOptions.py b/runtime/python/prompty/prompty/model/streaming/_StreamOptions.py index 36881dc9..6400bbd2 100644 --- a/runtime/python/prompty/prompty/model/streaming/_StreamOptions.py +++ b/runtime/python/prompty/prompty/model/streaming/_StreamOptions.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/streaming/__init__.py b/runtime/python/prompty/prompty/model/streaming/__init__.py index 099ef532..14675110 100644 --- a/runtime/python/prompty/prompty/model/streaming/__init__.py +++ b/runtime/python/prompty/prompty/model/streaming/__init__.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/template/_FormatConfig.py b/runtime/python/prompty/prompty/model/template/_FormatConfig.py index baf603d1..4f80e68a 100644 --- a/runtime/python/prompty/prompty/model/template/_FormatConfig.py +++ b/runtime/python/prompty/prompty/model/template/_FormatConfig.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/template/_ParserConfig.py b/runtime/python/prompty/prompty/model/template/_ParserConfig.py index be926a3e..1bb897c3 100644 --- a/runtime/python/prompty/prompty/model/template/_ParserConfig.py +++ b/runtime/python/prompty/prompty/model/template/_ParserConfig.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/template/_Template.py b/runtime/python/prompty/prompty/model/template/_Template.py index 9b85c8ff..577260a8 100644 --- a/runtime/python/prompty/prompty/model/template/_Template.py +++ b/runtime/python/prompty/prompty/model/template/_Template.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/template/__init__.py b/runtime/python/prompty/prompty/model/template/__init__.py index 4e65c6c3..b4a49acc 100644 --- a/runtime/python/prompty/prompty/model/template/__init__.py +++ b/runtime/python/prompty/prompty/model/template/__init__.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/tools/_Binding.py b/runtime/python/prompty/prompty/model/tools/_Binding.py index f39325da..8b834581 100644 --- a/runtime/python/prompty/prompty/model/tools/_Binding.py +++ b/runtime/python/prompty/prompty/model/tools/_Binding.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/tools/_McpApprovalMode.py b/runtime/python/prompty/prompty/model/tools/_McpApprovalMode.py index a48c7ef7..a4f9ba9b 100644 --- a/runtime/python/prompty/prompty/model/tools/_McpApprovalMode.py +++ b/runtime/python/prompty/prompty/model/tools/_McpApprovalMode.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/tools/_Tool.py b/runtime/python/prompty/prompty/model/tools/_Tool.py index 6a0a263c..96f666ef 100644 --- a/runtime/python/prompty/prompty/model/tools/_Tool.py +++ b/runtime/python/prompty/prompty/model/tools/_Tool.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/tools/_ToolContext.py b/runtime/python/prompty/prompty/model/tools/_ToolContext.py index 2aab5a54..e79292c9 100644 --- a/runtime/python/prompty/prompty/model/tools/_ToolContext.py +++ b/runtime/python/prompty/prompty/model/tools/_ToolContext.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/tools/_ToolDispatchResult.py b/runtime/python/prompty/prompty/model/tools/_ToolDispatchResult.py index 23b1a986..cbc16f9d 100644 --- a/runtime/python/prompty/prompty/model/tools/_ToolDispatchResult.py +++ b/runtime/python/prompty/prompty/model/tools/_ToolDispatchResult.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/tools/__init__.py b/runtime/python/prompty/prompty/model/tools/__init__.py index 97fb4c71..81352179 100644 --- a/runtime/python/prompty/prompty/model/tools/__init__.py +++ b/runtime/python/prompty/prompty/model/tools/__init__.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/tracing/_TraceFile.py b/runtime/python/prompty/prompty/model/tracing/_TraceFile.py index 9967bb0a..ba4a79e7 100644 --- a/runtime/python/prompty/prompty/model/tracing/_TraceFile.py +++ b/runtime/python/prompty/prompty/model/tracing/_TraceFile.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/tracing/_TraceSpan.py b/runtime/python/prompty/prompty/model/tracing/_TraceSpan.py index 386fb5aa..5bb42ad5 100644 --- a/runtime/python/prompty/prompty/model/tracing/_TraceSpan.py +++ b/runtime/python/prompty/prompty/model/tracing/_TraceSpan.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/tracing/_TraceTime.py b/runtime/python/prompty/prompty/model/tracing/_TraceTime.py index ff208518..85c5fbd3 100644 --- a/runtime/python/prompty/prompty/model/tracing/_TraceTime.py +++ b/runtime/python/prompty/prompty/model/tracing/_TraceTime.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/tracing/__init__.py b/runtime/python/prompty/prompty/model/tracing/__init__.py index 7eb0a530..548c34c3 100644 --- a/runtime/python/prompty/prompty/model/tracing/__init__.py +++ b/runtime/python/prompty/prompty/model/tracing/__init__.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/wire/_AnthropicImageBlock.py b/runtime/python/prompty/prompty/model/wire/_AnthropicImageBlock.py index 63d6a74c..f2a2a3d1 100644 --- a/runtime/python/prompty/prompty/model/wire/_AnthropicImageBlock.py +++ b/runtime/python/prompty/prompty/model/wire/_AnthropicImageBlock.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/wire/_AnthropicImageSource.py b/runtime/python/prompty/prompty/model/wire/_AnthropicImageSource.py index 9b6ba862..4305990a 100644 --- a/runtime/python/prompty/prompty/model/wire/_AnthropicImageSource.py +++ b/runtime/python/prompty/prompty/model/wire/_AnthropicImageSource.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/wire/_AnthropicMessagesRequest.py b/runtime/python/prompty/prompty/model/wire/_AnthropicMessagesRequest.py index 6f430618..760dc4be 100644 --- a/runtime/python/prompty/prompty/model/wire/_AnthropicMessagesRequest.py +++ b/runtime/python/prompty/prompty/model/wire/_AnthropicMessagesRequest.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/wire/_AnthropicMessagesResponse.py b/runtime/python/prompty/prompty/model/wire/_AnthropicMessagesResponse.py index 8c02b899..5c621a83 100644 --- a/runtime/python/prompty/prompty/model/wire/_AnthropicMessagesResponse.py +++ b/runtime/python/prompty/prompty/model/wire/_AnthropicMessagesResponse.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/wire/_AnthropicTextBlock.py b/runtime/python/prompty/prompty/model/wire/_AnthropicTextBlock.py index ecf1c6d6..6b7667ee 100644 --- a/runtime/python/prompty/prompty/model/wire/_AnthropicTextBlock.py +++ b/runtime/python/prompty/prompty/model/wire/_AnthropicTextBlock.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/wire/_AnthropicToolDefinition.py b/runtime/python/prompty/prompty/model/wire/_AnthropicToolDefinition.py index 531b9ec3..c726e5b6 100644 --- a/runtime/python/prompty/prompty/model/wire/_AnthropicToolDefinition.py +++ b/runtime/python/prompty/prompty/model/wire/_AnthropicToolDefinition.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/wire/_AnthropicToolResultBlock.py b/runtime/python/prompty/prompty/model/wire/_AnthropicToolResultBlock.py index bfed762a..9144beb1 100644 --- a/runtime/python/prompty/prompty/model/wire/_AnthropicToolResultBlock.py +++ b/runtime/python/prompty/prompty/model/wire/_AnthropicToolResultBlock.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/wire/_AnthropicToolUseBlock.py b/runtime/python/prompty/prompty/model/wire/_AnthropicToolUseBlock.py index e6447659..f4bec46e 100644 --- a/runtime/python/prompty/prompty/model/wire/_AnthropicToolUseBlock.py +++ b/runtime/python/prompty/prompty/model/wire/_AnthropicToolUseBlock.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/wire/_AnthropicUsage.py b/runtime/python/prompty/prompty/model/wire/_AnthropicUsage.py index 68c45ff0..e85927b6 100644 --- a/runtime/python/prompty/prompty/model/wire/_AnthropicUsage.py +++ b/runtime/python/prompty/prompty/model/wire/_AnthropicUsage.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/wire/_AnthropicWireMessage.py b/runtime/python/prompty/prompty/model/wire/_AnthropicWireMessage.py index 45911ef5..cd52a857 100644 --- a/runtime/python/prompty/prompty/model/wire/_AnthropicWireMessage.py +++ b/runtime/python/prompty/prompty/model/wire/_AnthropicWireMessage.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/prompty/model/wire/__init__.py b/runtime/python/prompty/prompty/model/wire/__init__.py index ec174f95..e3abec73 100644 --- a/runtime/python/prompty/prompty/model/wire/__init__.py +++ b/runtime/python/prompty/prompty/model/wire/__init__.py @@ -1,3 +1,4 @@ +# ########################################## # WARNING: This is an auto-generated file. # DO NOT EDIT THIS FILE DIRECTLY diff --git a/runtime/python/prompty/tests/model/agent/test_guardrail_result.py b/runtime/python/prompty/tests/model/agent/test_guardrail_result.py index 598110a6..b5c9a22a 100644 --- a/runtime/python/prompty/tests/model/agent/test_guardrail_result.py +++ b/runtime/python/prompty/tests/model/agent/test_guardrail_result.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/agent/test_prompty.py b/runtime/python/prompty/tests/model/agent/test_prompty.py index 5717ed59..8a455edb 100644 --- a/runtime/python/prompty/tests/model/agent/test_prompty.py +++ b/runtime/python/prompty/tests/model/agent/test_prompty.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/connection/test_anonymous_connection.py b/runtime/python/prompty/tests/model/connection/test_anonymous_connection.py index 95ff3290..0c3aedc4 100644 --- a/runtime/python/prompty/tests/model/connection/test_anonymous_connection.py +++ b/runtime/python/prompty/tests/model/connection/test_anonymous_connection.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/connection/test_api_key_connection.py b/runtime/python/prompty/tests/model/connection/test_api_key_connection.py index c063a7d4..9497397a 100644 --- a/runtime/python/prompty/tests/model/connection/test_api_key_connection.py +++ b/runtime/python/prompty/tests/model/connection/test_api_key_connection.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/connection/test_connection.py b/runtime/python/prompty/tests/model/connection/test_connection.py index 4019463d..2277658c 100644 --- a/runtime/python/prompty/tests/model/connection/test_connection.py +++ b/runtime/python/prompty/tests/model/connection/test_connection.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/connection/test_foundry_connection.py b/runtime/python/prompty/tests/model/connection/test_foundry_connection.py index c7cecba9..52677bc5 100644 --- a/runtime/python/prompty/tests/model/connection/test_foundry_connection.py +++ b/runtime/python/prompty/tests/model/connection/test_foundry_connection.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/connection/test_o_auth_connection.py b/runtime/python/prompty/tests/model/connection/test_o_auth_connection.py index 79e5f353..c38381cd 100644 --- a/runtime/python/prompty/tests/model/connection/test_o_auth_connection.py +++ b/runtime/python/prompty/tests/model/connection/test_o_auth_connection.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/connection/test_reference_connection.py b/runtime/python/prompty/tests/model/connection/test_reference_connection.py index e3aa655b..12abdb16 100644 --- a/runtime/python/prompty/tests/model/connection/test_reference_connection.py +++ b/runtime/python/prompty/tests/model/connection/test_reference_connection.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/connection/test_remote_connection.py b/runtime/python/prompty/tests/model/connection/test_remote_connection.py index 345edaaa..bc1ea153 100644 --- a/runtime/python/prompty/tests/model/connection/test_remote_connection.py +++ b/runtime/python/prompty/tests/model/connection/test_remote_connection.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/conversation/test_audio_part.py b/runtime/python/prompty/tests/model/conversation/test_audio_part.py index 7d65c3c2..1bf28610 100644 --- a/runtime/python/prompty/tests/model/conversation/test_audio_part.py +++ b/runtime/python/prompty/tests/model/conversation/test_audio_part.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/conversation/test_content_part.py b/runtime/python/prompty/tests/model/conversation/test_content_part.py index 8b137891..752835a0 100644 --- a/runtime/python/prompty/tests/model/conversation/test_content_part.py +++ b/runtime/python/prompty/tests/model/conversation/test_content_part.py @@ -1 +1,2 @@ +# diff --git a/runtime/python/prompty/tests/model/conversation/test_file_part.py b/runtime/python/prompty/tests/model/conversation/test_file_part.py index 22967d53..c2ef2bea 100644 --- a/runtime/python/prompty/tests/model/conversation/test_file_part.py +++ b/runtime/python/prompty/tests/model/conversation/test_file_part.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/conversation/test_image_part.py b/runtime/python/prompty/tests/model/conversation/test_image_part.py index f7fa3f59..0c326bf7 100644 --- a/runtime/python/prompty/tests/model/conversation/test_image_part.py +++ b/runtime/python/prompty/tests/model/conversation/test_image_part.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/conversation/test_message.py b/runtime/python/prompty/tests/model/conversation/test_message.py index 8bb1119a..e1fc9276 100644 --- a/runtime/python/prompty/tests/model/conversation/test_message.py +++ b/runtime/python/prompty/tests/model/conversation/test_message.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/conversation/test_text_part.py b/runtime/python/prompty/tests/model/conversation/test_text_part.py index 66f759f5..01cf1469 100644 --- a/runtime/python/prompty/tests/model/conversation/test_text_part.py +++ b/runtime/python/prompty/tests/model/conversation/test_text_part.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/conversation/test_thread_marker.py b/runtime/python/prompty/tests/model/conversation/test_thread_marker.py index 58f7ee53..92b566d0 100644 --- a/runtime/python/prompty/tests/model/conversation/test_thread_marker.py +++ b/runtime/python/prompty/tests/model/conversation/test_thread_marker.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/conversation/test_tool_call.py b/runtime/python/prompty/tests/model/conversation/test_tool_call.py index 7d3ab534..9f0c636b 100644 --- a/runtime/python/prompty/tests/model/conversation/test_tool_call.py +++ b/runtime/python/prompty/tests/model/conversation/test_tool_call.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/conversation/test_tool_result.py b/runtime/python/prompty/tests/model/conversation/test_tool_result.py index f8bb462b..6e26fbbc 100644 --- a/runtime/python/prompty/tests/model/conversation/test_tool_result.py +++ b/runtime/python/prompty/tests/model/conversation/test_tool_result.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/core/test_array_property.py b/runtime/python/prompty/tests/model/core/test_array_property.py index 71c4ce25..70f29e0b 100644 --- a/runtime/python/prompty/tests/model/core/test_array_property.py +++ b/runtime/python/prompty/tests/model/core/test_array_property.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/core/test_file_not_found_error.py b/runtime/python/prompty/tests/model/core/test_file_not_found_error.py index ae4a39ac..e0ab2125 100644 --- a/runtime/python/prompty/tests/model/core/test_file_not_found_error.py +++ b/runtime/python/prompty/tests/model/core/test_file_not_found_error.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/core/test_invoker_error.py b/runtime/python/prompty/tests/model/core/test_invoker_error.py index 640a3b0b..7647a976 100644 --- a/runtime/python/prompty/tests/model/core/test_invoker_error.py +++ b/runtime/python/prompty/tests/model/core/test_invoker_error.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/core/test_object_property.py b/runtime/python/prompty/tests/model/core/test_object_property.py index 13209441..d1e518d9 100644 --- a/runtime/python/prompty/tests/model/core/test_object_property.py +++ b/runtime/python/prompty/tests/model/core/test_object_property.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/core/test_property.py b/runtime/python/prompty/tests/model/core/test_property.py index 2552c8be..c7dc731e 100644 --- a/runtime/python/prompty/tests/model/core/test_property.py +++ b/runtime/python/prompty/tests/model/core/test_property.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/core/test_validation_error.py b/runtime/python/prompty/tests/model/core/test_validation_error.py index 31627a60..dd94ab06 100644 --- a/runtime/python/prompty/tests/model/core/test_validation_error.py +++ b/runtime/python/prompty/tests/model/core/test_validation_error.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/core/test_validation_result.py b/runtime/python/prompty/tests/model/core/test_validation_result.py index 2c64ec8d..1f33af40 100644 --- a/runtime/python/prompty/tests/model/core/test_validation_result.py +++ b/runtime/python/prompty/tests/model/core/test_validation_result.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_checkpoint.py b/runtime/python/prompty/tests/model/events/test_checkpoint.py index b0a946b6..4c8621b1 100644 --- a/runtime/python/prompty/tests/model/events/test_checkpoint.py +++ b/runtime/python/prompty/tests/model/events/test_checkpoint.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_compaction_complete_payload.py b/runtime/python/prompty/tests/model/events/test_compaction_complete_payload.py index 85a5a934..50ef24d7 100644 --- a/runtime/python/prompty/tests/model/events/test_compaction_complete_payload.py +++ b/runtime/python/prompty/tests/model/events/test_compaction_complete_payload.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_compaction_failed_payload.py b/runtime/python/prompty/tests/model/events/test_compaction_failed_payload.py index 6b2f2314..43c0e248 100644 --- a/runtime/python/prompty/tests/model/events/test_compaction_failed_payload.py +++ b/runtime/python/prompty/tests/model/events/test_compaction_failed_payload.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_compaction_start_payload.py b/runtime/python/prompty/tests/model/events/test_compaction_start_payload.py index 803790ae..07a9c224 100644 --- a/runtime/python/prompty/tests/model/events/test_compaction_start_payload.py +++ b/runtime/python/prompty/tests/model/events/test_compaction_start_payload.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_done_event_payload.py b/runtime/python/prompty/tests/model/events/test_done_event_payload.py index 8b137891..752835a0 100644 --- a/runtime/python/prompty/tests/model/events/test_done_event_payload.py +++ b/runtime/python/prompty/tests/model/events/test_done_event_payload.py @@ -1 +1,2 @@ +# diff --git a/runtime/python/prompty/tests/model/events/test_error_chunk.py b/runtime/python/prompty/tests/model/events/test_error_chunk.py index 9d72fa79..b4c1eb28 100644 --- a/runtime/python/prompty/tests/model/events/test_error_chunk.py +++ b/runtime/python/prompty/tests/model/events/test_error_chunk.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_error_event_payload.py b/runtime/python/prompty/tests/model/events/test_error_event_payload.py index ab051896..8056a237 100644 --- a/runtime/python/prompty/tests/model/events/test_error_event_payload.py +++ b/runtime/python/prompty/tests/model/events/test_error_event_payload.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_harness_context.py b/runtime/python/prompty/tests/model/events/test_harness_context.py index 2aa085c7..1c6b51ba 100644 --- a/runtime/python/prompty/tests/model/events/test_harness_context.py +++ b/runtime/python/prompty/tests/model/events/test_harness_context.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_hook_end_payload.py b/runtime/python/prompty/tests/model/events/test_hook_end_payload.py index c7c44fb1..8c94ae9c 100644 --- a/runtime/python/prompty/tests/model/events/test_hook_end_payload.py +++ b/runtime/python/prompty/tests/model/events/test_hook_end_payload.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_hook_start_payload.py b/runtime/python/prompty/tests/model/events/test_hook_start_payload.py index 71042da9..f67c22fd 100644 --- a/runtime/python/prompty/tests/model/events/test_hook_start_payload.py +++ b/runtime/python/prompty/tests/model/events/test_hook_start_payload.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_host_tool_request.py b/runtime/python/prompty/tests/model/events/test_host_tool_request.py index 26dcadf3..670be8af 100644 --- a/runtime/python/prompty/tests/model/events/test_host_tool_request.py +++ b/runtime/python/prompty/tests/model/events/test_host_tool_request.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_host_tool_result.py b/runtime/python/prompty/tests/model/events/test_host_tool_result.py index 800efc17..77a04cd4 100644 --- a/runtime/python/prompty/tests/model/events/test_host_tool_result.py +++ b/runtime/python/prompty/tests/model/events/test_host_tool_result.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_llm_complete_payload.py b/runtime/python/prompty/tests/model/events/test_llm_complete_payload.py index 037cb038..be3065bf 100644 --- a/runtime/python/prompty/tests/model/events/test_llm_complete_payload.py +++ b/runtime/python/prompty/tests/model/events/test_llm_complete_payload.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_llm_start_payload.py b/runtime/python/prompty/tests/model/events/test_llm_start_payload.py index c0a8f15d..7c233949 100644 --- a/runtime/python/prompty/tests/model/events/test_llm_start_payload.py +++ b/runtime/python/prompty/tests/model/events/test_llm_start_payload.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_messages_updated_payload.py b/runtime/python/prompty/tests/model/events/test_messages_updated_payload.py index 374aa720..d304426a 100644 --- a/runtime/python/prompty/tests/model/events/test_messages_updated_payload.py +++ b/runtime/python/prompty/tests/model/events/test_messages_updated_payload.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_permission_completed_payload.py b/runtime/python/prompty/tests/model/events/test_permission_completed_payload.py index 620570e8..d9f07ca7 100644 --- a/runtime/python/prompty/tests/model/events/test_permission_completed_payload.py +++ b/runtime/python/prompty/tests/model/events/test_permission_completed_payload.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_permission_decision.py b/runtime/python/prompty/tests/model/events/test_permission_decision.py index e53a98e3..bf50b5fe 100644 --- a/runtime/python/prompty/tests/model/events/test_permission_decision.py +++ b/runtime/python/prompty/tests/model/events/test_permission_decision.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_permission_request.py b/runtime/python/prompty/tests/model/events/test_permission_request.py index a0d58ec6..11344158 100644 --- a/runtime/python/prompty/tests/model/events/test_permission_request.py +++ b/runtime/python/prompty/tests/model/events/test_permission_request.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_permission_requested_payload.py b/runtime/python/prompty/tests/model/events/test_permission_requested_payload.py index 14fcc80b..20cbbe12 100644 --- a/runtime/python/prompty/tests/model/events/test_permission_requested_payload.py +++ b/runtime/python/prompty/tests/model/events/test_permission_requested_payload.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_redacted_field.py b/runtime/python/prompty/tests/model/events/test_redacted_field.py index cf006de8..100ea0f1 100644 --- a/runtime/python/prompty/tests/model/events/test_redacted_field.py +++ b/runtime/python/prompty/tests/model/events/test_redacted_field.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_redaction_metadata.py b/runtime/python/prompty/tests/model/events/test_redaction_metadata.py index ed11ded6..644776f5 100644 --- a/runtime/python/prompty/tests/model/events/test_redaction_metadata.py +++ b/runtime/python/prompty/tests/model/events/test_redaction_metadata.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_retry_payload.py b/runtime/python/prompty/tests/model/events/test_retry_payload.py index 1aa7e60b..02095b1f 100644 --- a/runtime/python/prompty/tests/model/events/test_retry_payload.py +++ b/runtime/python/prompty/tests/model/events/test_retry_payload.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_session_end_payload.py b/runtime/python/prompty/tests/model/events/test_session_end_payload.py index 63d34e7c..ac65359d 100644 --- a/runtime/python/prompty/tests/model/events/test_session_end_payload.py +++ b/runtime/python/prompty/tests/model/events/test_session_end_payload.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_session_event.py b/runtime/python/prompty/tests/model/events/test_session_event.py index 19160b13..7888076f 100644 --- a/runtime/python/prompty/tests/model/events/test_session_event.py +++ b/runtime/python/prompty/tests/model/events/test_session_event.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_session_file_ref.py b/runtime/python/prompty/tests/model/events/test_session_file_ref.py index 91d92aa5..de77d1e5 100644 --- a/runtime/python/prompty/tests/model/events/test_session_file_ref.py +++ b/runtime/python/prompty/tests/model/events/test_session_file_ref.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_session_ref.py b/runtime/python/prompty/tests/model/events/test_session_ref.py index 167ac961..fb88257a 100644 --- a/runtime/python/prompty/tests/model/events/test_session_ref.py +++ b/runtime/python/prompty/tests/model/events/test_session_ref.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_session_start_payload.py b/runtime/python/prompty/tests/model/events/test_session_start_payload.py index bc5e1fc8..31b60cb1 100644 --- a/runtime/python/prompty/tests/model/events/test_session_start_payload.py +++ b/runtime/python/prompty/tests/model/events/test_session_start_payload.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_session_summary.py b/runtime/python/prompty/tests/model/events/test_session_summary.py index f1cbf05a..b629ee74 100644 --- a/runtime/python/prompty/tests/model/events/test_session_summary.py +++ b/runtime/python/prompty/tests/model/events/test_session_summary.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_session_trace.py b/runtime/python/prompty/tests/model/events/test_session_trace.py index 095784dc..97747afa 100644 --- a/runtime/python/prompty/tests/model/events/test_session_trace.py +++ b/runtime/python/prompty/tests/model/events/test_session_trace.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_session_warning_payload.py b/runtime/python/prompty/tests/model/events/test_session_warning_payload.py index 75a58b67..d8be4cab 100644 --- a/runtime/python/prompty/tests/model/events/test_session_warning_payload.py +++ b/runtime/python/prompty/tests/model/events/test_session_warning_payload.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_status_event_payload.py b/runtime/python/prompty/tests/model/events/test_status_event_payload.py index 0f73b67e..8dcfb2cd 100644 --- a/runtime/python/prompty/tests/model/events/test_status_event_payload.py +++ b/runtime/python/prompty/tests/model/events/test_status_event_payload.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_stream_chunk.py b/runtime/python/prompty/tests/model/events/test_stream_chunk.py index 8b137891..752835a0 100644 --- a/runtime/python/prompty/tests/model/events/test_stream_chunk.py +++ b/runtime/python/prompty/tests/model/events/test_stream_chunk.py @@ -1 +1,2 @@ +# diff --git a/runtime/python/prompty/tests/model/events/test_text_chunk.py b/runtime/python/prompty/tests/model/events/test_text_chunk.py index 0b9eac8f..46e425e4 100644 --- a/runtime/python/prompty/tests/model/events/test_text_chunk.py +++ b/runtime/python/prompty/tests/model/events/test_text_chunk.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_thinking_chunk.py b/runtime/python/prompty/tests/model/events/test_thinking_chunk.py index 9efc4643..cccdb224 100644 --- a/runtime/python/prompty/tests/model/events/test_thinking_chunk.py +++ b/runtime/python/prompty/tests/model/events/test_thinking_chunk.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_thinking_event_payload.py b/runtime/python/prompty/tests/model/events/test_thinking_event_payload.py index 671fd5cf..56bc343b 100644 --- a/runtime/python/prompty/tests/model/events/test_thinking_event_payload.py +++ b/runtime/python/prompty/tests/model/events/test_thinking_event_payload.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_token_event_payload.py b/runtime/python/prompty/tests/model/events/test_token_event_payload.py index 829a4ceb..4e92f290 100644 --- a/runtime/python/prompty/tests/model/events/test_token_event_payload.py +++ b/runtime/python/prompty/tests/model/events/test_token_event_payload.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_tool_call_complete_payload.py b/runtime/python/prompty/tests/model/events/test_tool_call_complete_payload.py index 532d23d0..c916ce49 100644 --- a/runtime/python/prompty/tests/model/events/test_tool_call_complete_payload.py +++ b/runtime/python/prompty/tests/model/events/test_tool_call_complete_payload.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_tool_call_start_payload.py b/runtime/python/prompty/tests/model/events/test_tool_call_start_payload.py index 1468afe9..9683e763 100644 --- a/runtime/python/prompty/tests/model/events/test_tool_call_start_payload.py +++ b/runtime/python/prompty/tests/model/events/test_tool_call_start_payload.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_tool_chunk.py b/runtime/python/prompty/tests/model/events/test_tool_chunk.py index d64011c4..be59a227 100644 --- a/runtime/python/prompty/tests/model/events/test_tool_chunk.py +++ b/runtime/python/prompty/tests/model/events/test_tool_chunk.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_tool_execution_complete_payload.py b/runtime/python/prompty/tests/model/events/test_tool_execution_complete_payload.py index 3a83bba7..be4c543a 100644 --- a/runtime/python/prompty/tests/model/events/test_tool_execution_complete_payload.py +++ b/runtime/python/prompty/tests/model/events/test_tool_execution_complete_payload.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_tool_execution_start_payload.py b/runtime/python/prompty/tests/model/events/test_tool_execution_start_payload.py index be931ff4..1be78c0c 100644 --- a/runtime/python/prompty/tests/model/events/test_tool_execution_start_payload.py +++ b/runtime/python/prompty/tests/model/events/test_tool_execution_start_payload.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_tool_result_payload.py b/runtime/python/prompty/tests/model/events/test_tool_result_payload.py index c5f95332..394ef0e6 100644 --- a/runtime/python/prompty/tests/model/events/test_tool_result_payload.py +++ b/runtime/python/prompty/tests/model/events/test_tool_result_payload.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_trajectory_event.py b/runtime/python/prompty/tests/model/events/test_trajectory_event.py index 8cce6486..8545928f 100644 --- a/runtime/python/prompty/tests/model/events/test_trajectory_event.py +++ b/runtime/python/prompty/tests/model/events/test_trajectory_event.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_turn_end_payload.py b/runtime/python/prompty/tests/model/events/test_turn_end_payload.py index de85f141..01539ad4 100644 --- a/runtime/python/prompty/tests/model/events/test_turn_end_payload.py +++ b/runtime/python/prompty/tests/model/events/test_turn_end_payload.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_turn_event.py b/runtime/python/prompty/tests/model/events/test_turn_event.py index 13f86793..3e6cb774 100644 --- a/runtime/python/prompty/tests/model/events/test_turn_event.py +++ b/runtime/python/prompty/tests/model/events/test_turn_event.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_turn_start_payload.py b/runtime/python/prompty/tests/model/events/test_turn_start_payload.py index b3334c30..8f210c8a 100644 --- a/runtime/python/prompty/tests/model/events/test_turn_start_payload.py +++ b/runtime/python/prompty/tests/model/events/test_turn_start_payload.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_turn_summary.py b/runtime/python/prompty/tests/model/events/test_turn_summary.py index 712be713..2cb5af2e 100644 --- a/runtime/python/prompty/tests/model/events/test_turn_summary.py +++ b/runtime/python/prompty/tests/model/events/test_turn_summary.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/events/test_turn_trace.py b/runtime/python/prompty/tests/model/events/test_turn_trace.py index 3d8852df..6328d732 100644 --- a/runtime/python/prompty/tests/model/events/test_turn_trace.py +++ b/runtime/python/prompty/tests/model/events/test_turn_trace.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/model/test_model.py b/runtime/python/prompty/tests/model/model/test_model.py index e5b775be..f1da05fa 100644 --- a/runtime/python/prompty/tests/model/model/test_model.py +++ b/runtime/python/prompty/tests/model/model/test_model.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/model/test_model_info.py b/runtime/python/prompty/tests/model/model/test_model_info.py index 3a65b1a9..cb68dc3f 100644 --- a/runtime/python/prompty/tests/model/model/test_model_info.py +++ b/runtime/python/prompty/tests/model/model/test_model_info.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/model/test_model_options.py b/runtime/python/prompty/tests/model/model/test_model_options.py index fa7e8e7d..a11fa313 100644 --- a/runtime/python/prompty/tests/model/model/test_model_options.py +++ b/runtime/python/prompty/tests/model/model/test_model_options.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/model/test_token_usage.py b/runtime/python/prompty/tests/model/model/test_token_usage.py index 6fde31a7..512b4b1a 100644 --- a/runtime/python/prompty/tests/model/model/test_token_usage.py +++ b/runtime/python/prompty/tests/model/model/test_token_usage.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/pipeline/test_compaction_config.py b/runtime/python/prompty/tests/model/pipeline/test_compaction_config.py index d3329fe4..311547b9 100644 --- a/runtime/python/prompty/tests/model/pipeline/test_compaction_config.py +++ b/runtime/python/prompty/tests/model/pipeline/test_compaction_config.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/pipeline/test_turn_options.py b/runtime/python/prompty/tests/model/pipeline/test_turn_options.py index 5320b2a4..8c41cb07 100644 --- a/runtime/python/prompty/tests/model/pipeline/test_turn_options.py +++ b/runtime/python/prompty/tests/model/pipeline/test_turn_options.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/streaming/test_stream_options.py b/runtime/python/prompty/tests/model/streaming/test_stream_options.py index 1512544a..2e3a0925 100644 --- a/runtime/python/prompty/tests/model/streaming/test_stream_options.py +++ b/runtime/python/prompty/tests/model/streaming/test_stream_options.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/template/test_format_config.py b/runtime/python/prompty/tests/model/template/test_format_config.py index 1d232e3e..6cccae4f 100644 --- a/runtime/python/prompty/tests/model/template/test_format_config.py +++ b/runtime/python/prompty/tests/model/template/test_format_config.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/template/test_parser_config.py b/runtime/python/prompty/tests/model/template/test_parser_config.py index 81f353ad..57b1b4a6 100644 --- a/runtime/python/prompty/tests/model/template/test_parser_config.py +++ b/runtime/python/prompty/tests/model/template/test_parser_config.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/template/test_template.py b/runtime/python/prompty/tests/model/template/test_template.py index aa5bc3a0..e2fb2f21 100644 --- a/runtime/python/prompty/tests/model/template/test_template.py +++ b/runtime/python/prompty/tests/model/template/test_template.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/test_context.py b/runtime/python/prompty/tests/model/test_context.py index 9cac75b7..b9b1cee1 100644 --- a/runtime/python/prompty/tests/model/test_context.py +++ b/runtime/python/prompty/tests/model/test_context.py @@ -1,4 +1,5 @@ -# Prompty LoadContext +# +# Typra LoadContext from prompty.model._context import LoadContext, SaveContext diff --git a/runtime/python/prompty/tests/model/tools/test_binding.py b/runtime/python/prompty/tests/model/tools/test_binding.py index 2f27b071..7ea45d5b 100644 --- a/runtime/python/prompty/tests/model/tools/test_binding.py +++ b/runtime/python/prompty/tests/model/tools/test_binding.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/tools/test_custom_tool.py b/runtime/python/prompty/tests/model/tools/test_custom_tool.py index 53b8bdf9..293a742a 100644 --- a/runtime/python/prompty/tests/model/tools/test_custom_tool.py +++ b/runtime/python/prompty/tests/model/tools/test_custom_tool.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/tools/test_function_tool.py b/runtime/python/prompty/tests/model/tools/test_function_tool.py index 950f9a26..d0c83506 100644 --- a/runtime/python/prompty/tests/model/tools/test_function_tool.py +++ b/runtime/python/prompty/tests/model/tools/test_function_tool.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/tools/test_mcp_approval_mode.py b/runtime/python/prompty/tests/model/tools/test_mcp_approval_mode.py index c81edc9d..f94be0ec 100644 --- a/runtime/python/prompty/tests/model/tools/test_mcp_approval_mode.py +++ b/runtime/python/prompty/tests/model/tools/test_mcp_approval_mode.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/tools/test_mcp_tool.py b/runtime/python/prompty/tests/model/tools/test_mcp_tool.py index c15dce00..48c7c35c 100644 --- a/runtime/python/prompty/tests/model/tools/test_mcp_tool.py +++ b/runtime/python/prompty/tests/model/tools/test_mcp_tool.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/tools/test_open_api_tool.py b/runtime/python/prompty/tests/model/tools/test_open_api_tool.py index 09f93de8..9bd22a71 100644 --- a/runtime/python/prompty/tests/model/tools/test_open_api_tool.py +++ b/runtime/python/prompty/tests/model/tools/test_open_api_tool.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/tools/test_prompty_tool.py b/runtime/python/prompty/tests/model/tools/test_prompty_tool.py index a5200e03..8187f263 100644 --- a/runtime/python/prompty/tests/model/tools/test_prompty_tool.py +++ b/runtime/python/prompty/tests/model/tools/test_prompty_tool.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/tools/test_tool.py b/runtime/python/prompty/tests/model/tools/test_tool.py index 9df46730..c85f2cff 100644 --- a/runtime/python/prompty/tests/model/tools/test_tool.py +++ b/runtime/python/prompty/tests/model/tools/test_tool.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/tools/test_tool_context.py b/runtime/python/prompty/tests/model/tools/test_tool_context.py index 1ade3a0f..20818f4b 100644 --- a/runtime/python/prompty/tests/model/tools/test_tool_context.py +++ b/runtime/python/prompty/tests/model/tools/test_tool_context.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/tools/test_tool_dispatch_result.py b/runtime/python/prompty/tests/model/tools/test_tool_dispatch_result.py index 0c38d711..1163f203 100644 --- a/runtime/python/prompty/tests/model/tools/test_tool_dispatch_result.py +++ b/runtime/python/prompty/tests/model/tools/test_tool_dispatch_result.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/tracing/test_trace_file.py b/runtime/python/prompty/tests/model/tracing/test_trace_file.py index d6fbd6ff..694a524b 100644 --- a/runtime/python/prompty/tests/model/tracing/test_trace_file.py +++ b/runtime/python/prompty/tests/model/tracing/test_trace_file.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/tracing/test_trace_span.py b/runtime/python/prompty/tests/model/tracing/test_trace_span.py index 5cb0cd96..0a683580 100644 --- a/runtime/python/prompty/tests/model/tracing/test_trace_span.py +++ b/runtime/python/prompty/tests/model/tracing/test_trace_span.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/tracing/test_trace_time.py b/runtime/python/prompty/tests/model/tracing/test_trace_time.py index 15eeb845..220a2d56 100644 --- a/runtime/python/prompty/tests/model/tracing/test_trace_time.py +++ b/runtime/python/prompty/tests/model/tracing/test_trace_time.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/wire/test_anthropic_image_block.py b/runtime/python/prompty/tests/model/wire/test_anthropic_image_block.py index 8b137891..752835a0 100644 --- a/runtime/python/prompty/tests/model/wire/test_anthropic_image_block.py +++ b/runtime/python/prompty/tests/model/wire/test_anthropic_image_block.py @@ -1 +1,2 @@ +# diff --git a/runtime/python/prompty/tests/model/wire/test_anthropic_image_source.py b/runtime/python/prompty/tests/model/wire/test_anthropic_image_source.py index b5e6d5aa..6aba195c 100644 --- a/runtime/python/prompty/tests/model/wire/test_anthropic_image_source.py +++ b/runtime/python/prompty/tests/model/wire/test_anthropic_image_source.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/wire/test_anthropic_messages_request.py b/runtime/python/prompty/tests/model/wire/test_anthropic_messages_request.py index 9f2c0a65..b97daf3e 100644 --- a/runtime/python/prompty/tests/model/wire/test_anthropic_messages_request.py +++ b/runtime/python/prompty/tests/model/wire/test_anthropic_messages_request.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/wire/test_anthropic_messages_response.py b/runtime/python/prompty/tests/model/wire/test_anthropic_messages_response.py index eb4e2ecf..4ace73d0 100644 --- a/runtime/python/prompty/tests/model/wire/test_anthropic_messages_response.py +++ b/runtime/python/prompty/tests/model/wire/test_anthropic_messages_response.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/wire/test_anthropic_text_block.py b/runtime/python/prompty/tests/model/wire/test_anthropic_text_block.py index bc5e06f4..f8a1c63e 100644 --- a/runtime/python/prompty/tests/model/wire/test_anthropic_text_block.py +++ b/runtime/python/prompty/tests/model/wire/test_anthropic_text_block.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/wire/test_anthropic_tool_definition.py b/runtime/python/prompty/tests/model/wire/test_anthropic_tool_definition.py index 3a75f0eb..909c83df 100644 --- a/runtime/python/prompty/tests/model/wire/test_anthropic_tool_definition.py +++ b/runtime/python/prompty/tests/model/wire/test_anthropic_tool_definition.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/wire/test_anthropic_tool_result_block.py b/runtime/python/prompty/tests/model/wire/test_anthropic_tool_result_block.py index 3ae0b0ec..f25ed786 100644 --- a/runtime/python/prompty/tests/model/wire/test_anthropic_tool_result_block.py +++ b/runtime/python/prompty/tests/model/wire/test_anthropic_tool_result_block.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/wire/test_anthropic_tool_use_block.py b/runtime/python/prompty/tests/model/wire/test_anthropic_tool_use_block.py index 96cbd5e7..f2d76e27 100644 --- a/runtime/python/prompty/tests/model/wire/test_anthropic_tool_use_block.py +++ b/runtime/python/prompty/tests/model/wire/test_anthropic_tool_use_block.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/wire/test_anthropic_usage.py b/runtime/python/prompty/tests/model/wire/test_anthropic_usage.py index 5e8ad5d6..6180fd3a 100644 --- a/runtime/python/prompty/tests/model/wire/test_anthropic_usage.py +++ b/runtime/python/prompty/tests/model/wire/test_anthropic_usage.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/python/prompty/tests/model/wire/test_anthropic_wire_message.py b/runtime/python/prompty/tests/model/wire/test_anthropic_wire_message.py index d89a84f9..8a55fac8 100644 --- a/runtime/python/prompty/tests/model/wire/test_anthropic_wire_message.py +++ b/runtime/python/prompty/tests/model/wire/test_anthropic_wire_message.py @@ -1,3 +1,4 @@ +# import json import yaml diff --git a/runtime/rust/prompty/src/harness.rs b/runtime/rust/prompty/src/harness.rs index 6da1ad63..05ff0fef 100644 --- a/runtime/rust/prompty/src/harness.rs +++ b/runtime/rust/prompty/src/harness.rs @@ -17,8 +17,9 @@ use crate::model::events::{ session_event::SessionEvent, session_summary::SessionSummary, turn_event::TurnEvent, }; use crate::model::pipeline::{ - checkpoint_store::CheckpointStore, event_journal_writer::EventJournalWriter, event_sink::EventSink, - host_tool_executor::HostToolExecutor, permission_resolver::PermissionResolver, + checkpoint_store::CheckpointStore, event_journal_writer::EventJournalWriter, + event_sink::EventSink, host_tool_executor::HostToolExecutor, + permission_resolver::PermissionResolver, }; type AdapterError = Box; @@ -117,11 +118,7 @@ impl JsonlEventJournalWriter { } fn append_record(path: &PathBuf, record: Value) -> bool { - let mut file = match OpenOptions::new() - .create(true) - .append(true) - .open(path) - { + let mut file = match OpenOptions::new().create(true).append(true).open(path) { Ok(file) => file, Err(_) => return false, }; diff --git a/runtime/rust/prompty/src/model/agent/guardrail_result.rs b/runtime/rust/prompty/src/model/agent/guardrail_result.rs index 7806d46c..08ab63cd 100644 --- a/runtime/rust/prompty/src/model/agent/guardrail_result.rs +++ b/runtime/rust/prompty/src/model/agent/guardrail_result.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -39,8 +46,14 @@ impl GuardrailResult { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - allowed: value.get("allowed").and_then(|v| v.as_bool()).unwrap_or(false), - reason: value.get("reason").and_then(|v| v.as_str()).map(|s| s.to_string()), + allowed: value + .get("allowed") + .and_then(|v| v.as_bool()) + .unwrap_or(false), + reason: value + .get("reason") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), rewrite: value.get("rewrite").cloned(), } } @@ -72,14 +85,25 @@ impl GuardrailResult { } /// Create a GuardrailResult with preset field values. pub fn rewrite(rewrite: impl Into) -> Self { - GuardrailResult { allowed: true, rewrite: Some(rewrite.into()), ..Default::default() } + GuardrailResult { + allowed: true, + rewrite: Some(rewrite.into()), + ..Default::default() + } } /// Create a GuardrailResult with preset field values. pub fn deny(reason: impl Into) -> Self { - GuardrailResult { allowed: false, reason: Some(reason.into()), ..Default::default() } + GuardrailResult { + allowed: false, + reason: Some(reason.into()), + ..Default::default() + } } /// Create a GuardrailResult with preset field values. pub fn allow() -> Self { - GuardrailResult { allowed: true, ..Default::default() } + GuardrailResult { + allowed: true, + ..Default::default() + } } } diff --git a/runtime/rust/prompty/src/model/agent/mod.rs b/runtime/rust/prompty/src/model/agent/mod.rs index 0a791d90..c8214401 100644 --- a/runtime/rust/prompty/src/model/agent/mod.rs +++ b/runtime/rust/prompty/src/model/agent/mod.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] pub mod prompty; pub use prompty::*; diff --git a/runtime/rust/prompty/src/model/agent/prompty.rs b/runtime/rust/prompty/src/model/agent/prompty.rs index d1ae92ff..4dbca6d1 100644 --- a/runtime/rust/prompty/src/model/agent/prompty.rs +++ b/runtime/rust/prompty/src/model/agent/prompty.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -61,16 +68,48 @@ impl Prompty { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - name: value.get("name").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - display_name: value.get("displayName").and_then(|v| v.as_str()).map(|s| s.to_string()), - description: value.get("description").and_then(|v| v.as_str()).map(|s| s.to_string()), - metadata: value.get("metadata").cloned().unwrap_or(serde_json::Value::Null), - inputs: value.get("inputs").map(|v| Self::load_inputs(v, ctx)).unwrap_or_default(), - outputs: value.get("outputs").map(|v| Self::load_outputs(v, ctx)).unwrap_or_default(), - model: value.get("model").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| Model::load_from_value(v, ctx)).unwrap_or_default(), - tools: value.get("tools").map(|v| Self::load_tools(v, ctx)).unwrap_or_default(), - template: value.get("template").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| Template::load_from_value(v, ctx)), - instructions: value.get("instructions").and_then(|v| v.as_str()).map(|s| s.to_string()), + name: value + .get("name") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + display_name: value + .get("displayName") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + description: value + .get("description") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + metadata: value + .get("metadata") + .cloned() + .unwrap_or(serde_json::Value::Null), + inputs: value + .get("inputs") + .map(|v| Self::load_inputs(v, ctx)) + .unwrap_or_default(), + outputs: value + .get("outputs") + .map(|v| Self::load_outputs(v, ctx)) + .unwrap_or_default(), + model: value + .get("model") + .filter(|v| v.is_object() || v.is_array() || v.is_string()) + .map(|v| Model::load_from_value(v, ctx)) + .unwrap_or_default(), + tools: value + .get("tools") + .map(|v| Self::load_tools(v, ctx)) + .unwrap_or_default(), + template: value + .get("template") + .filter(|v| v.is_object() || v.is_array() || v.is_string()) + .map(|v| Template::load_from_value(v, ctx)), + instructions: value + .get("instructions") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), } } @@ -81,13 +120,22 @@ impl Prompty { let mut result = serde_json::Map::new(); // Write base fields if !self.name.is_empty() { - result.insert("name".to_string(), serde_json::Value::String(self.name.clone())); + result.insert( + "name".to_string(), + serde_json::Value::String(self.name.clone()), + ); } if let Some(ref val) = self.display_name { - result.insert("displayName".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "displayName".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(ref val) = self.description { - result.insert("description".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "description".to_string(), + serde_json::Value::String(val.clone()), + ); } if !self.metadata.is_null() { result.insert("metadata".to_string(), self.metadata.clone()); @@ -96,7 +144,10 @@ impl Prompty { result.insert("inputs".to_string(), Self::save_inputs(&self.inputs, ctx)); } if !self.outputs.is_empty() { - result.insert("outputs".to_string(), Self::save_outputs(&self.outputs, ctx)); + result.insert( + "outputs".to_string(), + Self::save_outputs(&self.outputs, ctx), + ); } { let nested = self.model.to_value(ctx); @@ -114,7 +165,10 @@ impl Prompty { } } if let Some(ref val) = self.instructions { - result.insert("instructions".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "instructions".to_string(), + serde_json::Value::String(val.clone()), + ); } ctx.process_dict(serde_json::Value::Object(result)) } @@ -134,77 +188,86 @@ impl Prompty { self.metadata.as_object() } - /// Load a collection of Property from a JSON value. /// Handles both array format `[{...}]` and dict format `{"name": {...}}`. fn load_inputs(data: &serde_json::Value, ctx: &LoadContext) -> Vec { match data { - serde_json::Value::Array(arr) => { - arr.iter().map(|v| Property::load_from_value(v, ctx)).collect() - } - - serde_json::Value::Object(obj) => { - obj.iter() - .filter_map(|(name, value)| { - if value.is_array() { - return None; - } - let mut v = if value.is_object() { - value.clone() - } else { - serde_json::json!({ "kind": value }) - }; - if let serde_json::Value::Object(ref mut m) = v { - m.entry("name".to_string()).or_insert_with(|| serde_json::Value::String(name.clone())); - } - Some(Property::load_from_value(&v, ctx)) - }) - .collect() - } + serde_json::Value::Array(arr) => arr + .iter() + .map(|v| Property::load_from_value(v, ctx)) + .collect(), + + serde_json::Value::Object(obj) => obj + .iter() + .filter_map(|(name, value)| { + if value.is_array() { + return None; + } + let mut v = if value.is_object() { + value.clone() + } else { + serde_json::json!({ "kind": value }) + }; + if let serde_json::Value::Object(ref mut m) = v { + m.entry("name".to_string()) + .or_insert_with(|| serde_json::Value::String(name.clone())); + } + Some(Property::load_from_value(&v, ctx)) + }) + .collect(), _ => Vec::new(), - } } /// Save a collection of Property to a JSON value. fn save_inputs(items: &[Property], ctx: &SaveContext) -> serde_json::Value { - if ctx.collection_format == "array" { - return serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()); + return serde_json::Value::Array( + items + .iter() + .map(|item| item.to_value(ctx)) + .collect::>(), + ); } // Object format: use name as key let mut result = serde_json::Map::new(); for item in items { let mut item_data = match item.to_value(ctx) { serde_json::Value::Object(m) => m, - other => { let mut m = serde_json::Map::new(); m.insert("value".to_string(), other); m }, + other => { + let mut m = serde_json::Map::new(); + m.insert("value".to_string(), other); + m + } }; if let Some(serde_json::Value::String(name)) = item_data.remove("name") { result.insert(name, serde_json::Value::Object(item_data)); } } serde_json::Value::Object(result) - } /// Load a collection of Property from a JSON value. /// Handles both array format `[{...}]`. fn load_outputs(data: &serde_json::Value, ctx: &LoadContext) -> Vec { match data { - serde_json::Value::Array(arr) => { - arr.iter().map(|v| Property::load_from_value(v, ctx)).collect() - } + serde_json::Value::Array(arr) => arr + .iter() + .map(|v| Property::load_from_value(v, ctx)) + .collect(), _ => Vec::new(), - } } /// Save a collection of Property to a JSON value. fn save_outputs(items: &[Property], ctx: &SaveContext) -> serde_json::Value { - - serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()) - + serde_json::Value::Array( + items + .iter() + .map(|item| item.to_value(ctx)) + .collect::>(), + ) } /// Load a collection of Tool from a JSON value. @@ -215,47 +278,53 @@ impl Prompty { arr.iter().map(|v| Tool::load_from_value(v, ctx)).collect() } - serde_json::Value::Object(obj) => { - obj.iter() - .filter_map(|(name, value)| { - if value.is_array() { - return None; - } - let mut v = if value.is_object() { - value.clone() - } else { - serde_json::json!({ "kind": value }) - }; - if let serde_json::Value::Object(ref mut m) = v { - m.entry("name".to_string()).or_insert_with(|| serde_json::Value::String(name.clone())); - } - Some(Tool::load_from_value(&v, ctx)) - }) - .collect() - } + serde_json::Value::Object(obj) => obj + .iter() + .filter_map(|(name, value)| { + if value.is_array() { + return None; + } + let mut v = if value.is_object() { + value.clone() + } else { + serde_json::json!({ "kind": value }) + }; + if let serde_json::Value::Object(ref mut m) = v { + m.entry("name".to_string()) + .or_insert_with(|| serde_json::Value::String(name.clone())); + } + Some(Tool::load_from_value(&v, ctx)) + }) + .collect(), _ => Vec::new(), - } } /// Save a collection of Tool to a JSON value. fn save_tools(items: &[Tool], ctx: &SaveContext) -> serde_json::Value { - if ctx.collection_format == "array" { - return serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()); + return serde_json::Value::Array( + items + .iter() + .map(|item| item.to_value(ctx)) + .collect::>(), + ); } // Object format: use name as key let mut result = serde_json::Map::new(); for item in items { let mut item_data = match item.to_value(ctx) { serde_json::Value::Object(m) => m, - other => { let mut m = serde_json::Map::new(); m.insert("value".to_string(), other); m }, + other => { + let mut m = serde_json::Map::new(); + m.insert("value".to_string(), other); + m + } }; if let Some(serde_json::Value::String(name)) = item_data.remove("name") { result.insert(name, serde_json::Value::Object(item_data)); } } serde_json::Value::Object(result) - } } diff --git a/runtime/rust/prompty/src/model/connection/connection.rs b/runtime/rust/prompty/src/model/connection/connection.rs index c34ea881..e01781a9 100644 --- a/runtime/rust/prompty/src/model/connection/connection.rs +++ b/runtime/rust/prompty/src/model/connection/connection.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -42,7 +49,6 @@ impl AuthenticationMode { } } - /// Variant-specific data for [`Connection`], discriminated by `kind`. #[derive(Debug, Clone)] pub enum ConnectionKind { @@ -141,37 +147,100 @@ impl Connection { let kind_str = value.get("kind").and_then(|v| v.as_str()).unwrap_or(""); let kind = match kind_str { "reference" => ConnectionKind::Reference { - name: value.get("name").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - target: value.get("target").and_then(|v| v.as_str()).map(|s| s.to_string()), + name: value + .get("name") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + target: value + .get("target") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), }, "remote" => ConnectionKind::Remote { - name: value.get("name").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - endpoint: value.get("endpoint").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + name: value + .get("name") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + endpoint: value + .get("endpoint") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), }, "key" => ConnectionKind::ApiKey { - endpoint: value.get("endpoint").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - api_key: value.get("apiKey").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + endpoint: value + .get("endpoint") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + api_key: value + .get("apiKey") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), }, "anonymous" => ConnectionKind::Anonymous { - endpoint: value.get("endpoint").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + endpoint: value + .get("endpoint") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), }, "oauth" => ConnectionKind::OAuth { - endpoint: value.get("endpoint").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - client_id: value.get("clientId").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - client_secret: value.get("clientSecret").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - token_url: value.get("tokenUrl").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - scopes: value.get("scopes").and_then(|v| v.as_array()).map(|arr| arr.iter().filter_map(|v| v.as_str().map(|s| s.to_string())).collect()), + endpoint: value + .get("endpoint") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + client_id: value + .get("clientId") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + client_secret: value + .get("clientSecret") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + token_url: value + .get("tokenUrl") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + scopes: value.get("scopes").and_then(|v| v.as_array()).map(|arr| { + arr.iter() + .filter_map(|v| v.as_str().map(|s| s.to_string())) + .collect() + }), }, "foundry" => ConnectionKind::Foundry { - endpoint: value.get("endpoint").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - name: value.get("name").and_then(|v| v.as_str()).map(|s| s.to_string()), - connection_type: value.get("connectionType").and_then(|v| v.as_str()).map(|s| s.to_string()), + endpoint: value + .get("endpoint") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + name: value + .get("name") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + connection_type: value + .get("connectionType") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), }, _ => ConnectionKind::default(), }; Self { - authentication_mode: value.get("authenticationMode").and_then(|v| v.as_str()).and_then(|s| AuthenticationMode::from_str_opt(s)), - usage_description: value.get("usageDescription").and_then(|v| v.as_str()).map(|s| s.to_string()), + authentication_mode: value + .get("authenticationMode") + .and_then(|v| v.as_str()) + .and_then(|s| AuthenticationMode::from_str_opt(s)), + usage_description: value + .get("usageDescription") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), kind: kind, } } @@ -194,17 +263,26 @@ impl Connection { pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { let mut result = serde_json::Map::new(); // Write the discriminator - result.insert("kind".to_string(), serde_json::Value::String(self.kind_str().to_string())); + result.insert( + "kind".to_string(), + serde_json::Value::String(self.kind_str().to_string()), + ); // Write base fields if let Some(ref val) = self.authentication_mode { - result.insert("authenticationMode".to_string(), serde_json::Value::String(val.to_string())); + result.insert( + "authenticationMode".to_string(), + serde_json::Value::String(val.to_string()), + ); } if let Some(ref val) = self.usage_description { - result.insert("usageDescription".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "usageDescription".to_string(), + serde_json::Value::String(val.clone()), + ); } // Write variant-specific fields match &self.kind { - ConnectionKind::Reference { name, target, .. } => { + ConnectionKind::Reference { name, target, .. } => { if !name.is_empty() { result.insert("name".to_string(), serde_json::Value::String(name.clone())); } @@ -212,53 +290,100 @@ impl Connection { result.insert("target".to_string(), serde_json::Value::String(val.clone())); } } - ConnectionKind::Remote { name, endpoint, .. } => { + ConnectionKind::Remote { name, endpoint, .. } => { if !name.is_empty() { result.insert("name".to_string(), serde_json::Value::String(name.clone())); } if !endpoint.is_empty() { - result.insert("endpoint".to_string(), serde_json::Value::String(endpoint.clone())); + result.insert( + "endpoint".to_string(), + serde_json::Value::String(endpoint.clone()), + ); } } - ConnectionKind::ApiKey { endpoint, api_key, .. } => { + ConnectionKind::ApiKey { + endpoint, api_key, .. + } => { if !endpoint.is_empty() { - result.insert("endpoint".to_string(), serde_json::Value::String(endpoint.clone())); + result.insert( + "endpoint".to_string(), + serde_json::Value::String(endpoint.clone()), + ); } if !api_key.is_empty() { - result.insert("apiKey".to_string(), serde_json::Value::String(api_key.clone())); + result.insert( + "apiKey".to_string(), + serde_json::Value::String(api_key.clone()), + ); } } - ConnectionKind::Anonymous { endpoint, .. } => { + ConnectionKind::Anonymous { endpoint, .. } => { if !endpoint.is_empty() { - result.insert("endpoint".to_string(), serde_json::Value::String(endpoint.clone())); + result.insert( + "endpoint".to_string(), + serde_json::Value::String(endpoint.clone()), + ); } } - ConnectionKind::OAuth { endpoint, client_id, client_secret, token_url, scopes, .. } => { + ConnectionKind::OAuth { + endpoint, + client_id, + client_secret, + token_url, + scopes, + .. + } => { if !endpoint.is_empty() { - result.insert("endpoint".to_string(), serde_json::Value::String(endpoint.clone())); + result.insert( + "endpoint".to_string(), + serde_json::Value::String(endpoint.clone()), + ); } if !client_id.is_empty() { - result.insert("clientId".to_string(), serde_json::Value::String(client_id.clone())); + result.insert( + "clientId".to_string(), + serde_json::Value::String(client_id.clone()), + ); } if !client_secret.is_empty() { - result.insert("clientSecret".to_string(), serde_json::Value::String(client_secret.clone())); + result.insert( + "clientSecret".to_string(), + serde_json::Value::String(client_secret.clone()), + ); } if !token_url.is_empty() { - result.insert("tokenUrl".to_string(), serde_json::Value::String(token_url.clone())); + result.insert( + "tokenUrl".to_string(), + serde_json::Value::String(token_url.clone()), + ); } if let Some(items) = scopes { - result.insert("scopes".to_string(), serde_json::to_value(items).unwrap_or(serde_json::Value::Null)); + result.insert( + "scopes".to_string(), + serde_json::to_value(items).unwrap_or(serde_json::Value::Null), + ); } } - ConnectionKind::Foundry { endpoint, name, connection_type, .. } => { + ConnectionKind::Foundry { + endpoint, + name, + connection_type, + .. + } => { if !endpoint.is_empty() { - result.insert("endpoint".to_string(), serde_json::Value::String(endpoint.clone())); + result.insert( + "endpoint".to_string(), + serde_json::Value::String(endpoint.clone()), + ); } if let Some(val) = name { result.insert("name".to_string(), serde_json::Value::String(val.clone())); } if let Some(val) = connection_type { - result.insert("connectionType".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "connectionType".to_string(), + serde_json::Value::String(val.clone()), + ); } } } diff --git a/runtime/rust/prompty/src/model/connection/mod.rs b/runtime/rust/prompty/src/model/connection/mod.rs index c0f3a1e2..1d114672 100644 --- a/runtime/rust/prompty/src/model/connection/mod.rs +++ b/runtime/rust/prompty/src/model/connection/mod.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] pub mod connection; pub use connection::*; diff --git a/runtime/rust/prompty/src/model/context.rs b/runtime/rust/prompty/src/model/context.rs index a660f24c..cacfe41f 100644 --- a/runtime/rust/prompty/src/model/context.rs +++ b/runtime/rust/prompty/src/model/context.rs @@ -1,7 +1,14 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. // Prompty Context -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] /// Callback type for pre-processing input data before parsing. pub type PreProcessFn = Box serde_json::Value + Send + Sync>; @@ -162,7 +169,11 @@ impl SaveContext { } /// Convert a value to a JSON string. - pub fn to_json(&self, data: &serde_json::Value, indent: bool) -> Result { + pub fn to_json( + &self, + data: &serde_json::Value, + indent: bool, + ) -> Result { if indent { serde_json::to_string_pretty(data) } else { diff --git a/runtime/rust/prompty/src/model/conversation/content_part.rs b/runtime/rust/prompty/src/model/conversation/content_part.rs index f2a1ae2e..010a56fb 100644 --- a/runtime/rust/prompty/src/model/conversation/content_part.rs +++ b/runtime/rust/prompty/src/model/conversation/content_part.rs @@ -1,10 +1,16 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; - /// Variant-specific data for [`ContentPart`], discriminated by `kind`. #[derive(Debug, Clone)] pub enum ContentPartKind { @@ -78,26 +84,52 @@ impl ContentPart { let kind_str = value.get("kind").and_then(|v| v.as_str()).unwrap_or(""); let kind = match kind_str { "text" => ContentPartKind::TextPart { - value: value.get("value").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + value: value + .get("value") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), }, "image" => ContentPartKind::ImagePart { - source: value.get("source").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - detail: value.get("detail").and_then(|v| v.as_str()).map(|s| s.to_string()), - media_type: value.get("mediaType").and_then(|v| v.as_str()).map(|s| s.to_string()), + source: value + .get("source") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + detail: value + .get("detail") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + media_type: value + .get("mediaType") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), }, "file" => ContentPartKind::FilePart { - source: value.get("source").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - media_type: value.get("mediaType").and_then(|v| v.as_str()).map(|s| s.to_string()), + source: value + .get("source") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + media_type: value + .get("mediaType") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), }, "audio" => ContentPartKind::AudioPart { - source: value.get("source").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - media_type: value.get("mediaType").and_then(|v| v.as_str()).map(|s| s.to_string()), + source: value + .get("source") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + media_type: value + .get("mediaType") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), }, _ => ContentPartKind::default(), }; - Self { - kind: kind, - } + Self { kind: kind } } /// Returns the `kind` discriminator string for this instance. @@ -116,40 +148,73 @@ impl ContentPart { pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { let mut result = serde_json::Map::new(); // Write the discriminator - result.insert("kind".to_string(), serde_json::Value::String(self.kind_str().to_string())); + result.insert( + "kind".to_string(), + serde_json::Value::String(self.kind_str().to_string()), + ); // Write base fields // Write variant-specific fields match &self.kind { - ContentPartKind::TextPart { value, .. } => { + ContentPartKind::TextPart { value, .. } => { if !value.is_empty() { - result.insert("value".to_string(), serde_json::Value::String(value.clone())); + result.insert( + "value".to_string(), + serde_json::Value::String(value.clone()), + ); } } - ContentPartKind::ImagePart { source, detail, media_type, .. } => { + ContentPartKind::ImagePart { + source, + detail, + media_type, + .. + } => { if !source.is_empty() { - result.insert("source".to_string(), serde_json::Value::String(source.clone())); + result.insert( + "source".to_string(), + serde_json::Value::String(source.clone()), + ); } if let Some(val) = detail { result.insert("detail".to_string(), serde_json::Value::String(val.clone())); } if let Some(val) = media_type { - result.insert("mediaType".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "mediaType".to_string(), + serde_json::Value::String(val.clone()), + ); } } - ContentPartKind::FilePart { source, media_type, .. } => { + ContentPartKind::FilePart { + source, media_type, .. + } => { if !source.is_empty() { - result.insert("source".to_string(), serde_json::Value::String(source.clone())); + result.insert( + "source".to_string(), + serde_json::Value::String(source.clone()), + ); } if let Some(val) = media_type { - result.insert("mediaType".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "mediaType".to_string(), + serde_json::Value::String(val.clone()), + ); } } - ContentPartKind::AudioPart { source, media_type, .. } => { + ContentPartKind::AudioPart { + source, media_type, .. + } => { if !source.is_empty() { - result.insert("source".to_string(), serde_json::Value::String(source.clone())); + result.insert( + "source".to_string(), + serde_json::Value::String(source.clone()), + ); } if let Some(val) = media_type { - result.insert("mediaType".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "mediaType".to_string(), + serde_json::Value::String(val.clone()), + ); } } } diff --git a/runtime/rust/prompty/src/model/conversation/message.rs b/runtime/rust/prompty/src/model/conversation/message.rs index a6ccc9ae..1b285aed 100644 --- a/runtime/rust/prompty/src/model/conversation/message.rs +++ b/runtime/rust/prompty/src/model/conversation/message.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -91,9 +98,19 @@ impl Message { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - role: value.get("role").and_then(|v| v.as_str()).and_then(|s| Role::from_str_opt(s)).unwrap_or(Role::User), - parts: value.get("parts").map(|v| Self::load_parts(v, ctx)).unwrap_or_default(), - metadata: value.get("metadata").cloned().unwrap_or(serde_json::Value::Null), + role: value + .get("role") + .and_then(|v| v.as_str()) + .and_then(|s| Role::from_str_opt(s)) + .unwrap_or(Role::User), + parts: value + .get("parts") + .map(|v| Self::load_parts(v, ctx)) + .unwrap_or_default(), + metadata: value + .get("metadata") + .cloned() + .unwrap_or(serde_json::Value::Null), } } @@ -103,7 +120,10 @@ impl Message { pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { let mut result = serde_json::Map::new(); // Write base fields - result.insert("role".to_string(), serde_json::Value::String(self.role.to_string())); + result.insert( + "role".to_string(), + serde_json::Value::String(self.role.to_string()), + ); if !self.parts.is_empty() { result.insert("parts".to_string(), Self::save_parts(&self.parts, ctx)); } @@ -128,37 +148,60 @@ impl Message { self.metadata.as_object() } - /// Load a collection of ContentPart from a JSON value. /// Handles both array format `[{...}]`. fn load_parts(data: &serde_json::Value, ctx: &LoadContext) -> Vec { match data { - serde_json::Value::Array(arr) => { - arr.iter().map(|v| ContentPart::load_from_value(v, ctx)).collect() - } + serde_json::Value::Array(arr) => arr + .iter() + .map(|v| ContentPart::load_from_value(v, ctx)) + .collect(), _ => Vec::new(), - } } /// Save a collection of ContentPart to a JSON value. fn save_parts(items: &[ContentPart], ctx: &SaveContext) -> serde_json::Value { - - serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()) - + serde_json::Value::Array( + items + .iter() + .map(|item| item.to_value(ctx)) + .collect::>(), + ) } /// Create a Message with preset field values. pub fn assistant(text: impl Into) -> Self { - Message { role: Role::Assistant, parts: vec![ContentPart { kind: ContentPartKind::TextPart { value: text.into() }, ..Default::default() }], ..Default::default() } + Message { + role: Role::Assistant, + parts: vec![ContentPart { + kind: ContentPartKind::TextPart { value: text.into() }, + ..Default::default() + }], + ..Default::default() + } } /// Create a Message with preset field values. pub fn system(text: impl Into) -> Self { - Message { role: Role::System, parts: vec![ContentPart { kind: ContentPartKind::TextPart { value: text.into() }, ..Default::default() }], ..Default::default() } + Message { + role: Role::System, + parts: vec![ContentPart { + kind: ContentPartKind::TextPart { value: text.into() }, + ..Default::default() + }], + ..Default::default() + } } /// Create a Message with preset field values. pub fn user(text: impl Into) -> Self { - Message { role: Role::User, parts: vec![ContentPart { kind: ContentPartKind::TextPart { value: text.into() }, ..Default::default() }], ..Default::default() } + Message { + role: Role::User, + parts: vec![ContentPart { + kind: ContentPartKind::TextPart { value: text.into() }, + ..Default::default() + }], + ..Default::default() + } } } /// Helpers for [`Message`]. Implement in a separate file. diff --git a/runtime/rust/prompty/src/model/conversation/mod.rs b/runtime/rust/prompty/src/model/conversation/mod.rs index ba57a8b5..649d0a30 100644 --- a/runtime/rust/prompty/src/model/conversation/mod.rs +++ b/runtime/rust/prompty/src/model/conversation/mod.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] pub mod content_part; pub use content_part::*; diff --git a/runtime/rust/prompty/src/model/conversation/thread_marker.rs b/runtime/rust/prompty/src/model/conversation/thread_marker.rs index 1e61e4d2..da1b4cbe 100644 --- a/runtime/rust/prompty/src/model/conversation/thread_marker.rs +++ b/runtime/rust/prompty/src/model/conversation/thread_marker.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -37,8 +44,16 @@ impl ThreadMarker { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - name: value.get("name").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - kind: value.get("kind").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + name: value + .get("name") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + kind: value + .get("kind") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), } } @@ -49,10 +64,16 @@ impl ThreadMarker { let mut result = serde_json::Map::new(); // Write base fields if !self.name.is_empty() { - result.insert("name".to_string(), serde_json::Value::String(self.name.clone())); + result.insert( + "name".to_string(), + serde_json::Value::String(self.name.clone()), + ); } if !self.kind.is_empty() { - result.insert("kind".to_string(), serde_json::Value::String(self.kind.clone())); + result.insert( + "kind".to_string(), + serde_json::Value::String(self.kind.clone()), + ); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/conversation/tool_call.rs b/runtime/rust/prompty/src/model/conversation/tool_call.rs index d4d8f871..9c14a366 100644 --- a/runtime/rust/prompty/src/model/conversation/tool_call.rs +++ b/runtime/rust/prompty/src/model/conversation/tool_call.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -39,9 +46,21 @@ impl ToolCall { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - id: value.get("id").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - name: value.get("name").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - arguments: value.get("arguments").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + id: value + .get("id") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + name: value + .get("name") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + arguments: value + .get("arguments") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), } } @@ -55,10 +74,16 @@ impl ToolCall { result.insert("id".to_string(), serde_json::Value::String(self.id.clone())); } if !self.name.is_empty() { - result.insert("name".to_string(), serde_json::Value::String(self.name.clone())); + result.insert( + "name".to_string(), + serde_json::Value::String(self.name.clone()), + ); } if !self.arguments.is_empty() { - result.insert("arguments".to_string(), serde_json::Value::String(self.arguments.clone())); + result.insert( + "arguments".to_string(), + serde_json::Value::String(self.arguments.clone()), + ); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/conversation/tool_result.rs b/runtime/rust/prompty/src/model/conversation/tool_result.rs index 351b0418..5fbee4ce 100644 --- a/runtime/rust/prompty/src/model/conversation/tool_result.rs +++ b/runtime/rust/prompty/src/model/conversation/tool_result.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -91,10 +98,22 @@ impl ToolResult { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - parts: value.get("parts").map(|v| Self::load_parts(v, ctx)).unwrap_or_default(), - status: value.get("status").and_then(|v| v.as_str()).and_then(|s| ToolResultStatus::from_str_opt(s)), - error_kind: value.get("errorKind").and_then(|v| v.as_str()).map(|s| s.to_string()), - error_message: value.get("errorMessage").and_then(|v| v.as_str()).map(|s| s.to_string()), + parts: value + .get("parts") + .map(|v| Self::load_parts(v, ctx)) + .unwrap_or_default(), + status: value + .get("status") + .and_then(|v| v.as_str()) + .and_then(|s| ToolResultStatus::from_str_opt(s)), + error_kind: value + .get("errorKind") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + error_message: value + .get("errorMessage") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), duration_ms: value.get("durationMs").and_then(|v| v.as_f64()), } } @@ -109,16 +128,30 @@ impl ToolResult { result.insert("parts".to_string(), Self::save_parts(&self.parts, ctx)); } if let Some(ref val) = self.status { - result.insert("status".to_string(), serde_json::Value::String(val.to_string())); + result.insert( + "status".to_string(), + serde_json::Value::String(val.to_string()), + ); } if let Some(ref val) = self.error_kind { - result.insert("errorKind".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "errorKind".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(ref val) = self.error_message { - result.insert("errorMessage".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "errorMessage".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(val) = self.duration_ms { - result.insert("durationMs".to_string(), serde_json::Number::from_f64(val as f64).map(serde_json::Value::Number).unwrap_or(serde_json::Value::Null)); + result.insert( + "durationMs".to_string(), + serde_json::Number::from_f64(val as f64) + .map(serde_json::Value::Number) + .unwrap_or(serde_json::Value::Null), + ); } ctx.process_dict(serde_json::Value::Object(result)) } @@ -137,24 +170,35 @@ impl ToolResult { /// Handles both array format `[{...}]`. fn load_parts(data: &serde_json::Value, ctx: &LoadContext) -> Vec { match data { - serde_json::Value::Array(arr) => { - arr.iter().map(|v| ContentPart::load_from_value(v, ctx)).collect() - } + serde_json::Value::Array(arr) => arr + .iter() + .map(|v| ContentPart::load_from_value(v, ctx)) + .collect(), _ => Vec::new(), - } } /// Save a collection of ContentPart to a JSON value. fn save_parts(items: &[ContentPart], ctx: &SaveContext) -> serde_json::Value { - - serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()) - + serde_json::Value::Array( + items + .iter() + .map(|item| item.to_value(ctx)) + .collect::>(), + ) } /// Create a ToolResult with preset field values. pub fn text(value: impl Into) -> Self { - ToolResult { parts: vec![ContentPart { kind: ContentPartKind::TextPart { value: value.into() }, ..Default::default() }], ..Default::default() } + ToolResult { + parts: vec![ContentPart { + kind: ContentPartKind::TextPart { + value: value.into(), + }, + ..Default::default() + }], + ..Default::default() + } } } /// Helpers for [`ToolResult`]. Implement in a separate file. diff --git a/runtime/rust/prompty/src/model/core/file_not_found_error.rs b/runtime/rust/prompty/src/model/core/file_not_found_error.rs index f5b24962..369ce03e 100644 --- a/runtime/rust/prompty/src/model/core/file_not_found_error.rs +++ b/runtime/rust/prompty/src/model/core/file_not_found_error.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -37,8 +44,16 @@ impl FileNotFoundError { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - message: value.get("message").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - path: value.get("path").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + message: value + .get("message") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + path: value + .get("path") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), } } @@ -49,10 +64,16 @@ impl FileNotFoundError { let mut result = serde_json::Map::new(); // Write base fields if !self.message.is_empty() { - result.insert("message".to_string(), serde_json::Value::String(self.message.clone())); + result.insert( + "message".to_string(), + serde_json::Value::String(self.message.clone()), + ); } if !self.path.is_empty() { - result.insert("path".to_string(), serde_json::Value::String(self.path.clone())); + result.insert( + "path".to_string(), + serde_json::Value::String(self.path.clone()), + ); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/core/invoker_error.rs b/runtime/rust/prompty/src/model/core/invoker_error.rs index 6140e913..36cdefce 100644 --- a/runtime/rust/prompty/src/model/core/invoker_error.rs +++ b/runtime/rust/prompty/src/model/core/invoker_error.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -39,9 +46,21 @@ impl InvokerError { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - message: value.get("message").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - component: value.get("component").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - key: value.get("key").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + message: value + .get("message") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + component: value + .get("component") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + key: value + .get("key") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), } } @@ -52,13 +71,22 @@ impl InvokerError { let mut result = serde_json::Map::new(); // Write base fields if !self.message.is_empty() { - result.insert("message".to_string(), serde_json::Value::String(self.message.clone())); + result.insert( + "message".to_string(), + serde_json::Value::String(self.message.clone()), + ); } if !self.component.is_empty() { - result.insert("component".to_string(), serde_json::Value::String(self.component.clone())); + result.insert( + "component".to_string(), + serde_json::Value::String(self.component.clone()), + ); } if !self.key.is_empty() { - result.insert("key".to_string(), serde_json::Value::String(self.key.clone())); + result.insert( + "key".to_string(), + serde_json::Value::String(self.key.clone()), + ); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/core/mod.rs b/runtime/rust/prompty/src/model/core/mod.rs index bf18c31f..8213f1b5 100644 --- a/runtime/rust/prompty/src/model/core/mod.rs +++ b/runtime/rust/prompty/src/model/core/mod.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] pub mod property; pub use property::*; diff --git a/runtime/rust/prompty/src/model/core/property.rs b/runtime/rust/prompty/src/model/core/property.rs index 69e9c63c..9e68ac62 100644 --- a/runtime/rust/prompty/src/model/core/property.rs +++ b/runtime/rust/prompty/src/model/core/property.rs @@ -1,10 +1,16 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; - /// Variant-specific data for [`Property`], discriminated by `kind`. #[derive(Debug, Clone)] pub enum PropertyKind { @@ -75,34 +81,68 @@ impl Property { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); if let Some(value) = value.as_bool() { - return Property { kind: PropertyKind::Custom { kind_name: "boolean".to_string() }, example: Some(value.into()), ..Default::default() }; + return Property { + kind: PropertyKind::Custom { + kind_name: "boolean".to_string(), + }, + example: Some(value.into()), + ..Default::default() + }; } if let Some(value) = value.as_i64() { - return Property { kind: PropertyKind::Custom { kind_name: "integer".to_string() }, example: Some(value.into()), ..Default::default() }; + return Property { + kind: PropertyKind::Custom { + kind_name: "integer".to_string(), + }, + example: Some(value.into()), + ..Default::default() + }; } if let Some(s) = value.as_str() { let value = s.to_string(); - return Property { kind: PropertyKind::Custom { kind_name: "string".to_string() }, example: Some(value.into()), ..Default::default() }; + return Property { + kind: PropertyKind::Custom { + kind_name: "string".to_string(), + }, + example: Some(value.into()), + ..Default::default() + }; } let kind_str = value.get("kind").and_then(|v| v.as_str()).unwrap_or(""); let kind = match kind_str { "array" => PropertyKind::Array { - items: value.get("items").cloned().unwrap_or(serde_json::Value::Null), + items: value + .get("items") + .cloned() + .unwrap_or(serde_json::Value::Null), }, "object" => PropertyKind::Object { - properties: value.get("properties").map(|v| Self::load_properties(v, ctx)).unwrap_or_default(), + properties: value + .get("properties") + .map(|v| Self::load_properties(v, ctx)) + .unwrap_or_default(), }, _ => PropertyKind::Custom { kind_name: kind_str.to_string(), }, }; Self { - name: value.get("name").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - description: value.get("description").and_then(|v| v.as_str()).map(|s| s.to_string()), + name: value + .get("name") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + description: value + .get("description") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), required: value.get("required").and_then(|v| v.as_bool()), default: value.get("default").cloned(), example: value.get("example").cloned(), - enum_values: value.get("enumValues").and_then(|v| v.as_array()).map(|arr| arr.to_vec()), + enum_values: value + .get("enumValues") + .and_then(|v| v.as_array()) + .map(|arr| arr.to_vec()), kind: kind, } } @@ -122,13 +162,22 @@ impl Property { pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { let mut result = serde_json::Map::new(); // Write the discriminator - result.insert("kind".to_string(), serde_json::Value::String(self.kind_str().to_string())); + result.insert( + "kind".to_string(), + serde_json::Value::String(self.kind_str().to_string()), + ); // Write base fields if !self.name.is_empty() { - result.insert("name".to_string(), serde_json::Value::String(self.name.clone())); + result.insert( + "name".to_string(), + serde_json::Value::String(self.name.clone()), + ); } if let Some(ref val) = self.description { - result.insert("description".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "description".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(val) = self.required { result.insert("required".to_string(), serde_json::Value::Bool(val)); @@ -140,22 +189,29 @@ impl Property { result.insert("example".to_string(), val.clone()); } if let Some(ref items) = self.enum_values { - result.insert("enumValues".to_string(), serde_json::to_value(items).unwrap_or(serde_json::Value::Null)); + result.insert( + "enumValues".to_string(), + serde_json::to_value(items).unwrap_or(serde_json::Value::Null), + ); } // Write variant-specific fields match &self.kind { - PropertyKind::Array { items, .. } => { + PropertyKind::Array { items, .. } => { if !items.is_null() { result.insert("items".to_string(), items.clone()); } } - PropertyKind::Object { properties, .. } => { + PropertyKind::Object { properties, .. } => { if !properties.is_empty() { - result.insert("properties".to_string(), serde_json::Value::Array(properties.iter().map(|item| item.to_value(ctx)).collect())); + result.insert( + "properties".to_string(), + serde_json::Value::Array( + properties.iter().map(|item| item.to_value(ctx)).collect(), + ), + ); } } - PropertyKind::Custom { kind_name: _, .. } => { - } + PropertyKind::Custom { kind_name: _, .. } => {} } ctx.process_dict(serde_json::Value::Object(result)) } @@ -174,19 +230,22 @@ impl Property { /// Handles both array format `[{...}]`. fn load_properties(data: &serde_json::Value, ctx: &LoadContext) -> Vec { match data { - serde_json::Value::Array(arr) => { - arr.iter().map(|v| Property::load_from_value(v, ctx)).collect() - } + serde_json::Value::Array(arr) => arr + .iter() + .map(|v| Property::load_from_value(v, ctx)) + .collect(), _ => Vec::new(), - } } /// Save a collection of Property to a JSON value. fn save_properties(items: &[Property], ctx: &SaveContext) -> serde_json::Value { - - serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()) - + serde_json::Value::Array( + items + .iter() + .map(|item| item.to_value(ctx)) + .collect::>(), + ) } } diff --git a/runtime/rust/prompty/src/model/core/validation_error.rs b/runtime/rust/prompty/src/model/core/validation_error.rs index ec2abb0d..25b7d06e 100644 --- a/runtime/rust/prompty/src/model/core/validation_error.rs +++ b/runtime/rust/prompty/src/model/core/validation_error.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -39,9 +46,21 @@ impl ValidationError { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - message: value.get("message").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - property: value.get("property").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - constraint: value.get("constraint").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + message: value + .get("message") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + property: value + .get("property") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + constraint: value + .get("constraint") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), } } @@ -52,13 +71,22 @@ impl ValidationError { let mut result = serde_json::Map::new(); // Write base fields if !self.message.is_empty() { - result.insert("message".to_string(), serde_json::Value::String(self.message.clone())); + result.insert( + "message".to_string(), + serde_json::Value::String(self.message.clone()), + ); } if !self.property.is_empty() { - result.insert("property".to_string(), serde_json::Value::String(self.property.clone())); + result.insert( + "property".to_string(), + serde_json::Value::String(self.property.clone()), + ); } if !self.constraint.is_empty() { - result.insert("constraint".to_string(), serde_json::Value::String(self.constraint.clone())); + result.insert( + "constraint".to_string(), + serde_json::Value::String(self.constraint.clone()), + ); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/core/validation_result.rs b/runtime/rust/prompty/src/model/core/validation_result.rs index ed40b9b4..3603317b 100644 --- a/runtime/rust/prompty/src/model/core/validation_result.rs +++ b/runtime/rust/prompty/src/model/core/validation_result.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -39,8 +46,14 @@ impl ValidationResult { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - valid: value.get("valid").and_then(|v| v.as_bool()).unwrap_or(false), - errors: value.get("errors").map(|v| Self::load_errors(v, ctx)).unwrap_or_default(), + valid: value + .get("valid") + .and_then(|v| v.as_bool()) + .unwrap_or(false), + errors: value + .get("errors") + .map(|v| Self::load_errors(v, ctx)) + .unwrap_or_default(), } } @@ -71,19 +84,22 @@ impl ValidationResult { /// Handles both array format `[{...}]`. fn load_errors(data: &serde_json::Value, ctx: &LoadContext) -> Vec { match data { - serde_json::Value::Array(arr) => { - arr.iter().map(|v| ValidationError::load_from_value(v, ctx)).collect() - } + serde_json::Value::Array(arr) => arr + .iter() + .map(|v| ValidationError::load_from_value(v, ctx)) + .collect(), _ => Vec::new(), - } } /// Save a collection of ValidationError to a JSON value. fn save_errors(items: &[ValidationError], ctx: &SaveContext) -> serde_json::Value { - - serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()) - + serde_json::Value::Array( + items + .iter() + .map(|item| item.to_value(ctx)) + .collect::>(), + ) } } diff --git a/runtime/rust/prompty/src/model/events/checkpoint.rs b/runtime/rust/prompty/src/model/events/checkpoint.rs index 0fda30d5..bc3bb170 100644 --- a/runtime/rust/prompty/src/model/events/checkpoint.rs +++ b/runtime/rust/prompty/src/model/events/checkpoint.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -57,17 +64,51 @@ impl Checkpoint { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - id: value.get("id").and_then(|v| v.as_str()).map(|s| s.to_string()), - session_id: value.get("sessionId").and_then(|v| v.as_str()).map(|s| s.to_string()), - turn_id: value.get("turnId").and_then(|v| v.as_str()).map(|s| s.to_string()), - checkpoint_number: value.get("checkpointNumber").and_then(|v| v.as_i64()).map(|v| v as i32), - title: value.get("title").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - overview: value.get("overview").and_then(|v| v.as_str()).map(|s| s.to_string()), - state: value.get("state").cloned().unwrap_or(serde_json::Value::Null), - summary: value.get("summary").and_then(|v| v.as_str()).map(|s| s.to_string()), - metadata: value.get("metadata").cloned().unwrap_or(serde_json::Value::Null), - created_at: value.get("createdAt").and_then(|v| v.as_str()).map(|s| s.to_string()), - redaction: value.get("redaction").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| RedactionMetadata::load_from_value(v, ctx)), + id: value + .get("id") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + session_id: value + .get("sessionId") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + turn_id: value + .get("turnId") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + checkpoint_number: value + .get("checkpointNumber") + .and_then(|v| v.as_i64()) + .map(|v| v as i32), + title: value + .get("title") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + overview: value + .get("overview") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + state: value + .get("state") + .cloned() + .unwrap_or(serde_json::Value::Null), + summary: value + .get("summary") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + metadata: value + .get("metadata") + .cloned() + .unwrap_or(serde_json::Value::Null), + created_at: value + .get("createdAt") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + redaction: value + .get("redaction") + .filter(|v| v.is_object() || v.is_array() || v.is_string()) + .map(|v| RedactionMetadata::load_from_value(v, ctx)), } } @@ -81,31 +122,49 @@ impl Checkpoint { result.insert("id".to_string(), serde_json::Value::String(val.clone())); } if let Some(ref val) = self.session_id { - result.insert("sessionId".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "sessionId".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(ref val) = self.turn_id { result.insert("turnId".to_string(), serde_json::Value::String(val.clone())); } if let Some(val) = self.checkpoint_number { - result.insert("checkpointNumber".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + result.insert( + "checkpointNumber".to_string(), + serde_json::Value::Number(serde_json::Number::from(val)), + ); } if !self.title.is_empty() { - result.insert("title".to_string(), serde_json::Value::String(self.title.clone())); + result.insert( + "title".to_string(), + serde_json::Value::String(self.title.clone()), + ); } if let Some(ref val) = self.overview { - result.insert("overview".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "overview".to_string(), + serde_json::Value::String(val.clone()), + ); } if !self.state.is_null() { result.insert("state".to_string(), self.state.clone()); } if let Some(ref val) = self.summary { - result.insert("summary".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "summary".to_string(), + serde_json::Value::String(val.clone()), + ); } if !self.metadata.is_null() { result.insert("metadata".to_string(), self.metadata.clone()); } if let Some(ref val) = self.created_at { - result.insert("createdAt".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "createdAt".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(ref val) = self.redaction { let nested = val.to_value(ctx); @@ -136,5 +195,4 @@ impl Checkpoint { pub fn as_metadata_dict(&self) -> Option<&serde_json::Map> { self.metadata.as_object() } - } diff --git a/runtime/rust/prompty/src/model/events/compaction_complete_payload.rs b/runtime/rust/prompty/src/model/events/compaction_complete_payload.rs index b17a52a0..54e72fa4 100644 --- a/runtime/rust/prompty/src/model/events/compaction_complete_payload.rs +++ b/runtime/rust/prompty/src/model/events/compaction_complete_payload.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -41,7 +48,10 @@ impl CompactionCompletePayload { Self { removed: value.get("removed").and_then(|v| v.as_i64()).unwrap_or(0) as i32, remaining: value.get("remaining").and_then(|v| v.as_i64()).unwrap_or(0) as i32, - summary_length: value.get("summaryLength").and_then(|v| v.as_i64()).map(|v| v as i32), + summary_length: value + .get("summaryLength") + .and_then(|v| v.as_i64()) + .map(|v| v as i32), } } @@ -52,13 +62,22 @@ impl CompactionCompletePayload { let mut result = serde_json::Map::new(); // Write base fields if self.removed != 0 { - result.insert("removed".to_string(), serde_json::Value::Number(serde_json::Number::from(self.removed))); + result.insert( + "removed".to_string(), + serde_json::Value::Number(serde_json::Number::from(self.removed)), + ); } if self.remaining != 0 { - result.insert("remaining".to_string(), serde_json::Value::Number(serde_json::Number::from(self.remaining))); + result.insert( + "remaining".to_string(), + serde_json::Value::Number(serde_json::Number::from(self.remaining)), + ); } if let Some(val) = self.summary_length { - result.insert("summaryLength".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + result.insert( + "summaryLength".to_string(), + serde_json::Value::Number(serde_json::Number::from(val)), + ); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/events/compaction_failed_payload.rs b/runtime/rust/prompty/src/model/events/compaction_failed_payload.rs index 8bc29779..73a4e147 100644 --- a/runtime/rust/prompty/src/model/events/compaction_failed_payload.rs +++ b/runtime/rust/prompty/src/model/events/compaction_failed_payload.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -35,7 +42,11 @@ impl CompactionFailedPayload { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - message: value.get("message").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + message: value + .get("message") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), } } @@ -46,7 +57,10 @@ impl CompactionFailedPayload { let mut result = serde_json::Map::new(); // Write base fields if !self.message.is_empty() { - result.insert("message".to_string(), serde_json::Value::String(self.message.clone())); + result.insert( + "message".to_string(), + serde_json::Value::String(self.message.clone()), + ); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/events/compaction_start_payload.rs b/runtime/rust/prompty/src/model/events/compaction_start_payload.rs index 376bfb7a..18ee7137 100644 --- a/runtime/rust/prompty/src/model/events/compaction_start_payload.rs +++ b/runtime/rust/prompty/src/model/events/compaction_start_payload.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -35,7 +42,10 @@ impl CompactionStartPayload { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - dropped_count: value.get("droppedCount").and_then(|v| v.as_i64()).unwrap_or(0) as i32, + dropped_count: value + .get("droppedCount") + .and_then(|v| v.as_i64()) + .unwrap_or(0) as i32, } } @@ -46,7 +56,10 @@ impl CompactionStartPayload { let mut result = serde_json::Map::new(); // Write base fields if self.dropped_count != 0 { - result.insert("droppedCount".to_string(), serde_json::Value::Number(serde_json::Number::from(self.dropped_count))); + result.insert( + "droppedCount".to_string(), + serde_json::Value::Number(serde_json::Number::from(self.dropped_count)), + ); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/events/done_event_payload.rs b/runtime/rust/prompty/src/model/events/done_event_payload.rs index cbaba5b7..566510dd 100644 --- a/runtime/rust/prompty/src/model/events/done_event_payload.rs +++ b/runtime/rust/prompty/src/model/events/done_event_payload.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -39,8 +46,14 @@ impl DoneEventPayload { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - response: value.get("response").cloned().unwrap_or(serde_json::Value::Null), - messages: value.get("messages").map(|v| Self::load_messages(v, ctx)).unwrap_or_default(), + response: value + .get("response") + .cloned() + .unwrap_or(serde_json::Value::Null), + messages: value + .get("messages") + .map(|v| Self::load_messages(v, ctx)) + .unwrap_or_default(), } } @@ -54,7 +67,10 @@ impl DoneEventPayload { result.insert("response".to_string(), self.response.clone()); } if !self.messages.is_empty() { - result.insert("messages".to_string(), Self::save_messages(&self.messages, ctx)); + result.insert( + "messages".to_string(), + Self::save_messages(&self.messages, ctx), + ); } ctx.process_dict(serde_json::Value::Object(result)) } @@ -73,19 +89,22 @@ impl DoneEventPayload { /// Handles both array format `[{...}]`. fn load_messages(data: &serde_json::Value, ctx: &LoadContext) -> Vec { match data { - serde_json::Value::Array(arr) => { - arr.iter().map(|v| Message::load_from_value(v, ctx)).collect() - } + serde_json::Value::Array(arr) => arr + .iter() + .map(|v| Message::load_from_value(v, ctx)) + .collect(), _ => Vec::new(), - } } /// Save a collection of Message to a JSON value. fn save_messages(items: &[Message], ctx: &SaveContext) -> serde_json::Value { - - serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()) - + serde_json::Value::Array( + items + .iter() + .map(|item| item.to_value(ctx)) + .collect::>(), + ) } } diff --git a/runtime/rust/prompty/src/model/events/error_event_payload.rs b/runtime/rust/prompty/src/model/events/error_event_payload.rs index d71bea3d..2cc751d9 100644 --- a/runtime/rust/prompty/src/model/events/error_event_payload.rs +++ b/runtime/rust/prompty/src/model/events/error_event_payload.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -39,9 +46,19 @@ impl ErrorEventPayload { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - message: value.get("message").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - error_kind: value.get("errorKind").and_then(|v| v.as_str()).map(|s| s.to_string()), - phase: value.get("phase").and_then(|v| v.as_str()).map(|s| s.to_string()), + message: value + .get("message") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + error_kind: value + .get("errorKind") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + phase: value + .get("phase") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), } } @@ -52,10 +69,16 @@ impl ErrorEventPayload { let mut result = serde_json::Map::new(); // Write base fields if !self.message.is_empty() { - result.insert("message".to_string(), serde_json::Value::String(self.message.clone())); + result.insert( + "message".to_string(), + serde_json::Value::String(self.message.clone()), + ); } if let Some(ref val) = self.error_kind { - result.insert("errorKind".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "errorKind".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(ref val) = self.phase { result.insert("phase".to_string(), serde_json::Value::String(val.clone())); diff --git a/runtime/rust/prompty/src/model/events/harness_context.rs b/runtime/rust/prompty/src/model/events/harness_context.rs index 1f53dc88..603fb466 100644 --- a/runtime/rust/prompty/src/model/events/harness_context.rs +++ b/runtime/rust/prompty/src/model/events/harness_context.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -39,9 +46,18 @@ impl HarnessContext { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - cwd: value.get("cwd").and_then(|v| v.as_str()).map(|s| s.to_string()), - git_root: value.get("gitRoot").and_then(|v| v.as_str()).map(|s| s.to_string()), - metadata: value.get("metadata").cloned().unwrap_or(serde_json::Value::Null), + cwd: value + .get("cwd") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + git_root: value + .get("gitRoot") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + metadata: value + .get("metadata") + .cloned() + .unwrap_or(serde_json::Value::Null), } } @@ -55,7 +71,10 @@ impl HarnessContext { result.insert("cwd".to_string(), serde_json::Value::String(val.clone())); } if let Some(ref val) = self.git_root { - result.insert("gitRoot".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "gitRoot".to_string(), + serde_json::Value::String(val.clone()), + ); } if !self.metadata.is_null() { result.insert("metadata".to_string(), self.metadata.clone()); @@ -77,5 +96,4 @@ impl HarnessContext { pub fn as_metadata_dict(&self) -> Option<&serde_json::Map> { self.metadata.as_object() } - } diff --git a/runtime/rust/prompty/src/model/events/hook_end_payload.rs b/runtime/rust/prompty/src/model/events/hook_end_payload.rs index 35da9b0d..ecf0e651 100644 --- a/runtime/rust/prompty/src/model/events/hook_end_payload.rs +++ b/runtime/rust/prompty/src/model/events/hook_end_payload.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -89,14 +96,37 @@ impl HookEndPayload { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - hook_invocation_id: value.get("hookInvocationId").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - hook_type: value.get("hookType").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - scope: value.get("scope").and_then(|v| v.as_str()).and_then(|s| HookEndScope::from_str_opt(s)), - success: value.get("success").and_then(|v| v.as_bool()).unwrap_or(false), - output: value.get("output").cloned().unwrap_or(serde_json::Value::Null), + hook_invocation_id: value + .get("hookInvocationId") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + hook_type: value + .get("hookType") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + scope: value + .get("scope") + .and_then(|v| v.as_str()) + .and_then(|s| HookEndScope::from_str_opt(s)), + success: value + .get("success") + .and_then(|v| v.as_bool()) + .unwrap_or(false), + output: value + .get("output") + .cloned() + .unwrap_or(serde_json::Value::Null), duration_ms: value.get("durationMs").and_then(|v| v.as_f64()), - error: value.get("error").and_then(|v| v.as_str()).map(|s| s.to_string()), - redaction: value.get("redaction").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| RedactionMetadata::load_from_value(v, ctx)), + error: value + .get("error") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + redaction: value + .get("redaction") + .filter(|v| v.is_object() || v.is_array() || v.is_string()) + .map(|v| RedactionMetadata::load_from_value(v, ctx)), } } @@ -107,20 +137,34 @@ impl HookEndPayload { let mut result = serde_json::Map::new(); // Write base fields if !self.hook_invocation_id.is_empty() { - result.insert("hookInvocationId".to_string(), serde_json::Value::String(self.hook_invocation_id.clone())); + result.insert( + "hookInvocationId".to_string(), + serde_json::Value::String(self.hook_invocation_id.clone()), + ); } if !self.hook_type.is_empty() { - result.insert("hookType".to_string(), serde_json::Value::String(self.hook_type.clone())); + result.insert( + "hookType".to_string(), + serde_json::Value::String(self.hook_type.clone()), + ); } if let Some(ref val) = self.scope { - result.insert("scope".to_string(), serde_json::Value::String(val.to_string())); + result.insert( + "scope".to_string(), + serde_json::Value::String(val.to_string()), + ); } result.insert("success".to_string(), serde_json::Value::Bool(self.success)); if !self.output.is_null() { result.insert("output".to_string(), self.output.clone()); } if let Some(val) = self.duration_ms { - result.insert("durationMs".to_string(), serde_json::Number::from_f64(val as f64).map(serde_json::Value::Number).unwrap_or(serde_json::Value::Null)); + result.insert( + "durationMs".to_string(), + serde_json::Number::from_f64(val as f64) + .map(serde_json::Value::Number) + .unwrap_or(serde_json::Value::Null), + ); } if let Some(ref val) = self.error { result.insert("error".to_string(), serde_json::Value::String(val.clone())); @@ -148,5 +192,4 @@ impl HookEndPayload { pub fn as_output_dict(&self) -> Option<&serde_json::Map> { self.output.as_object() } - } diff --git a/runtime/rust/prompty/src/model/events/hook_start_payload.rs b/runtime/rust/prompty/src/model/events/hook_start_payload.rs index 39ec15f3..219d4294 100644 --- a/runtime/rust/prompty/src/model/events/hook_start_payload.rs +++ b/runtime/rust/prompty/src/model/events/hook_start_payload.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -83,11 +90,28 @@ impl HookStartPayload { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - hook_invocation_id: value.get("hookInvocationId").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - hook_type: value.get("hookType").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - scope: value.get("scope").and_then(|v| v.as_str()).and_then(|s| HookStartScope::from_str_opt(s)), - input: value.get("input").cloned().unwrap_or(serde_json::Value::Null), - redaction: value.get("redaction").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| RedactionMetadata::load_from_value(v, ctx)), + hook_invocation_id: value + .get("hookInvocationId") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + hook_type: value + .get("hookType") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + scope: value + .get("scope") + .and_then(|v| v.as_str()) + .and_then(|s| HookStartScope::from_str_opt(s)), + input: value + .get("input") + .cloned() + .unwrap_or(serde_json::Value::Null), + redaction: value + .get("redaction") + .filter(|v| v.is_object() || v.is_array() || v.is_string()) + .map(|v| RedactionMetadata::load_from_value(v, ctx)), } } @@ -98,13 +122,22 @@ impl HookStartPayload { let mut result = serde_json::Map::new(); // Write base fields if !self.hook_invocation_id.is_empty() { - result.insert("hookInvocationId".to_string(), serde_json::Value::String(self.hook_invocation_id.clone())); + result.insert( + "hookInvocationId".to_string(), + serde_json::Value::String(self.hook_invocation_id.clone()), + ); } if !self.hook_type.is_empty() { - result.insert("hookType".to_string(), serde_json::Value::String(self.hook_type.clone())); + result.insert( + "hookType".to_string(), + serde_json::Value::String(self.hook_type.clone()), + ); } if let Some(ref val) = self.scope { - result.insert("scope".to_string(), serde_json::Value::String(val.to_string())); + result.insert( + "scope".to_string(), + serde_json::Value::String(val.to_string()), + ); } if !self.input.is_null() { result.insert("input".to_string(), self.input.clone()); @@ -132,5 +165,4 @@ impl HookStartPayload { pub fn as_input_dict(&self) -> Option<&serde_json::Map> { self.input.as_object() } - } diff --git a/runtime/rust/prompty/src/model/events/host_tool_request.rs b/runtime/rust/prompty/src/model/events/host_tool_request.rs index 851e1f13..60053f09 100644 --- a/runtime/rust/prompty/src/model/events/host_tool_request.rs +++ b/runtime/rust/prompty/src/model/events/host_tool_request.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -43,11 +50,27 @@ impl HostToolRequest { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - request_id: value.get("requestId").and_then(|v| v.as_str()).map(|s| s.to_string()), - tool_call_id: value.get("toolCallId").and_then(|v| v.as_str()).map(|s| s.to_string()), - tool_name: value.get("toolName").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - arguments: value.get("arguments").cloned().unwrap_or(serde_json::Value::Null), - working_directory: value.get("workingDirectory").and_then(|v| v.as_str()).map(|s| s.to_string()), + request_id: value + .get("requestId") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + tool_call_id: value + .get("toolCallId") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + tool_name: value + .get("toolName") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + arguments: value + .get("arguments") + .cloned() + .unwrap_or(serde_json::Value::Null), + working_directory: value + .get("workingDirectory") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), } } @@ -58,19 +81,31 @@ impl HostToolRequest { let mut result = serde_json::Map::new(); // Write base fields if let Some(ref val) = self.request_id { - result.insert("requestId".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "requestId".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(ref val) = self.tool_call_id { - result.insert("toolCallId".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "toolCallId".to_string(), + serde_json::Value::String(val.clone()), + ); } if !self.tool_name.is_empty() { - result.insert("toolName".to_string(), serde_json::Value::String(self.tool_name.clone())); + result.insert( + "toolName".to_string(), + serde_json::Value::String(self.tool_name.clone()), + ); } if !self.arguments.is_null() { result.insert("arguments".to_string(), self.arguments.clone()); } if let Some(ref val) = self.working_directory { - result.insert("workingDirectory".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "workingDirectory".to_string(), + serde_json::Value::String(val.clone()), + ); } ctx.process_dict(serde_json::Value::Object(result)) } @@ -89,5 +124,4 @@ impl HostToolRequest { pub fn as_arguments_dict(&self) -> Option<&serde_json::Map> { self.arguments.as_object() } - } diff --git a/runtime/rust/prompty/src/model/events/host_tool_result.rs b/runtime/rust/prompty/src/model/events/host_tool_result.rs index 3d7e7e1e..928ad094 100644 --- a/runtime/rust/prompty/src/model/events/host_tool_result.rs +++ b/runtime/rust/prompty/src/model/events/host_tool_result.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -51,15 +58,37 @@ impl HostToolResult { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - request_id: value.get("requestId").and_then(|v| v.as_str()).map(|s| s.to_string()), - tool_call_id: value.get("toolCallId").and_then(|v| v.as_str()).map(|s| s.to_string()), - tool_name: value.get("toolName").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - success: value.get("success").and_then(|v| v.as_bool()).unwrap_or(false), + request_id: value + .get("requestId") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + tool_call_id: value + .get("toolCallId") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + tool_name: value + .get("toolName") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + success: value + .get("success") + .and_then(|v| v.as_bool()) + .unwrap_or(false), result: value.get("result").cloned(), - exit_code: value.get("exitCode").and_then(|v| v.as_i64()).map(|v| v as i32), + exit_code: value + .get("exitCode") + .and_then(|v| v.as_i64()) + .map(|v| v as i32), duration_ms: value.get("durationMs").and_then(|v| v.as_f64()), - error_kind: value.get("errorKind").and_then(|v| v.as_str()).map(|s| s.to_string()), - telemetry: value.get("telemetry").cloned().unwrap_or(serde_json::Value::Null), + error_kind: value + .get("errorKind") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + telemetry: value + .get("telemetry") + .cloned() + .unwrap_or(serde_json::Value::Null), } } @@ -70,26 +99,46 @@ impl HostToolResult { let mut result = serde_json::Map::new(); // Write base fields if let Some(ref val) = self.request_id { - result.insert("requestId".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "requestId".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(ref val) = self.tool_call_id { - result.insert("toolCallId".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "toolCallId".to_string(), + serde_json::Value::String(val.clone()), + ); } if !self.tool_name.is_empty() { - result.insert("toolName".to_string(), serde_json::Value::String(self.tool_name.clone())); + result.insert( + "toolName".to_string(), + serde_json::Value::String(self.tool_name.clone()), + ); } result.insert("success".to_string(), serde_json::Value::Bool(self.success)); if let Some(ref val) = self.result { result.insert("result".to_string(), val.clone()); } if let Some(val) = self.exit_code { - result.insert("exitCode".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + result.insert( + "exitCode".to_string(), + serde_json::Value::Number(serde_json::Number::from(val)), + ); } if let Some(val) = self.duration_ms { - result.insert("durationMs".to_string(), serde_json::Number::from_f64(val as f64).map(serde_json::Value::Number).unwrap_or(serde_json::Value::Null)); + result.insert( + "durationMs".to_string(), + serde_json::Number::from_f64(val as f64) + .map(serde_json::Value::Number) + .unwrap_or(serde_json::Value::Null), + ); } if let Some(ref val) = self.error_kind { - result.insert("errorKind".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "errorKind".to_string(), + serde_json::Value::String(val.clone()), + ); } if !self.telemetry.is_null() { result.insert("telemetry".to_string(), self.telemetry.clone()); @@ -111,5 +160,4 @@ impl HostToolResult { pub fn as_telemetry_dict(&self) -> Option<&serde_json::Map> { self.telemetry.as_object() } - } diff --git a/runtime/rust/prompty/src/model/events/llm_complete_payload.rs b/runtime/rust/prompty/src/model/events/llm_complete_payload.rs index db82dd0c..b55c8fac 100644 --- a/runtime/rust/prompty/src/model/events/llm_complete_payload.rs +++ b/runtime/rust/prompty/src/model/events/llm_complete_payload.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -43,9 +50,18 @@ impl LlmCompletePayload { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - request_id: value.get("requestId").and_then(|v| v.as_str()).map(|s| s.to_string()), - service_request_id: value.get("serviceRequestId").and_then(|v| v.as_str()).map(|s| s.to_string()), - usage: value.get("usage").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| TokenUsage::load_from_value(v, ctx)), + request_id: value + .get("requestId") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + service_request_id: value + .get("serviceRequestId") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + usage: value + .get("usage") + .filter(|v| v.is_object() || v.is_array() || v.is_string()) + .map(|v| TokenUsage::load_from_value(v, ctx)), duration_ms: value.get("durationMs").and_then(|v| v.as_f64()), } } @@ -57,10 +73,16 @@ impl LlmCompletePayload { let mut result = serde_json::Map::new(); // Write base fields if let Some(ref val) = self.request_id { - result.insert("requestId".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "requestId".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(ref val) = self.service_request_id { - result.insert("serviceRequestId".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "serviceRequestId".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(ref val) = self.usage { let nested = val.to_value(ctx); @@ -69,7 +91,12 @@ impl LlmCompletePayload { } } if let Some(val) = self.duration_ms { - result.insert("durationMs".to_string(), serde_json::Number::from_f64(val as f64).map(serde_json::Value::Number).unwrap_or(serde_json::Value::Null)); + result.insert( + "durationMs".to_string(), + serde_json::Number::from_f64(val as f64) + .map(serde_json::Value::Number) + .unwrap_or(serde_json::Value::Null), + ); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/events/llm_start_payload.rs b/runtime/rust/prompty/src/model/events/llm_start_payload.rs index e3b41166..095bbebc 100644 --- a/runtime/rust/prompty/src/model/events/llm_start_payload.rs +++ b/runtime/rust/prompty/src/model/events/llm_start_payload.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -41,10 +48,22 @@ impl LlmStartPayload { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - provider: value.get("provider").and_then(|v| v.as_str()).map(|s| s.to_string()), - model_id: value.get("modelId").and_then(|v| v.as_str()).map(|s| s.to_string()), - message_count: value.get("messageCount").and_then(|v| v.as_i64()).map(|v| v as i32), - attempt: value.get("attempt").and_then(|v| v.as_i64()).map(|v| v as i32), + provider: value + .get("provider") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + model_id: value + .get("modelId") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + message_count: value + .get("messageCount") + .and_then(|v| v.as_i64()) + .map(|v| v as i32), + attempt: value + .get("attempt") + .and_then(|v| v.as_i64()) + .map(|v| v as i32), } } @@ -55,16 +74,28 @@ impl LlmStartPayload { let mut result = serde_json::Map::new(); // Write base fields if let Some(ref val) = self.provider { - result.insert("provider".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "provider".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(ref val) = self.model_id { - result.insert("modelId".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "modelId".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(val) = self.message_count { - result.insert("messageCount".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + result.insert( + "messageCount".to_string(), + serde_json::Value::Number(serde_json::Number::from(val)), + ); } if let Some(val) = self.attempt { - result.insert("attempt".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + result.insert( + "attempt".to_string(), + serde_json::Value::Number(serde_json::Number::from(val)), + ); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/events/messages_updated_payload.rs b/runtime/rust/prompty/src/model/events/messages_updated_payload.rs index bbf7ad8f..90adea51 100644 --- a/runtime/rust/prompty/src/model/events/messages_updated_payload.rs +++ b/runtime/rust/prompty/src/model/events/messages_updated_payload.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -43,10 +50,22 @@ impl MessagesUpdatedPayload { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - messages: value.get("messages").map(|v| Self::load_messages(v, ctx)).unwrap_or_default(), - reason: value.get("reason").and_then(|v| v.as_str()).map(|s| s.to_string()), - appended: value.get("appended").map(|v| Self::load_appended(v, ctx)).unwrap_or_default(), - removed: value.get("removed").and_then(|v| v.as_i64()).map(|v| v as i32), + messages: value + .get("messages") + .map(|v| Self::load_messages(v, ctx)) + .unwrap_or_default(), + reason: value + .get("reason") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + appended: value + .get("appended") + .map(|v| Self::load_appended(v, ctx)) + .unwrap_or_default(), + removed: value + .get("removed") + .and_then(|v| v.as_i64()) + .map(|v| v as i32), } } @@ -57,16 +76,25 @@ impl MessagesUpdatedPayload { let mut result = serde_json::Map::new(); // Write base fields if !self.messages.is_empty() { - result.insert("messages".to_string(), Self::save_messages(&self.messages, ctx)); + result.insert( + "messages".to_string(), + Self::save_messages(&self.messages, ctx), + ); } if let Some(ref val) = self.reason { result.insert("reason".to_string(), serde_json::Value::String(val.clone())); } if !self.appended.is_empty() { - result.insert("appended".to_string(), Self::save_appended(&self.appended, ctx)); + result.insert( + "appended".to_string(), + Self::save_appended(&self.appended, ctx), + ); } if let Some(val) = self.removed { - result.insert("removed".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + result.insert( + "removed".to_string(), + serde_json::Value::Number(serde_json::Number::from(val)), + ); } ctx.process_dict(serde_json::Value::Object(result)) } @@ -85,39 +113,45 @@ impl MessagesUpdatedPayload { /// Handles both array format `[{...}]`. fn load_messages(data: &serde_json::Value, ctx: &LoadContext) -> Vec { match data { - serde_json::Value::Array(arr) => { - arr.iter().map(|v| Message::load_from_value(v, ctx)).collect() - } + serde_json::Value::Array(arr) => arr + .iter() + .map(|v| Message::load_from_value(v, ctx)) + .collect(), _ => Vec::new(), - } } /// Save a collection of Message to a JSON value. fn save_messages(items: &[Message], ctx: &SaveContext) -> serde_json::Value { - - serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()) - + serde_json::Value::Array( + items + .iter() + .map(|item| item.to_value(ctx)) + .collect::>(), + ) } /// Load a collection of Message from a JSON value. /// Handles both array format `[{...}]`. fn load_appended(data: &serde_json::Value, ctx: &LoadContext) -> Vec { match data { - serde_json::Value::Array(arr) => { - arr.iter().map(|v| Message::load_from_value(v, ctx)).collect() - } + serde_json::Value::Array(arr) => arr + .iter() + .map(|v| Message::load_from_value(v, ctx)) + .collect(), _ => Vec::new(), - } } /// Save a collection of Message to a JSON value. fn save_appended(items: &[Message], ctx: &SaveContext) -> serde_json::Value { - - serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()) - + serde_json::Value::Array( + items + .iter() + .map(|item| item.to_value(ctx)) + .collect::>(), + ) } } diff --git a/runtime/rust/prompty/src/model/events/mod.rs b/runtime/rust/prompty/src/model/events/mod.rs index c6bb2c10..8203d559 100644 --- a/runtime/rust/prompty/src/model/events/mod.rs +++ b/runtime/rust/prompty/src/model/events/mod.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. - -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +// +// Code generated by Typra emitter; DO NOT EDIT. + +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] pub mod turn_event; pub use turn_event::*; diff --git a/runtime/rust/prompty/src/model/events/permission_completed_payload.rs b/runtime/rust/prompty/src/model/events/permission_completed_payload.rs index f2223efe..108c94fb 100644 --- a/runtime/rust/prompty/src/model/events/permission_completed_payload.rs +++ b/runtime/rust/prompty/src/model/events/permission_completed_payload.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -49,13 +56,35 @@ impl PermissionCompletedPayload { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - request_id: value.get("requestId").and_then(|v| v.as_str()).map(|s| s.to_string()), - tool_call_id: value.get("toolCallId").and_then(|v| v.as_str()).map(|s| s.to_string()), - permission: value.get("permission").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - approved: value.get("approved").and_then(|v| v.as_bool()).unwrap_or(false), - reason: value.get("reason").and_then(|v| v.as_str()).map(|s| s.to_string()), - result: value.get("result").cloned().unwrap_or(serde_json::Value::Null), - redaction: value.get("redaction").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| RedactionMetadata::load_from_value(v, ctx)), + request_id: value + .get("requestId") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + tool_call_id: value + .get("toolCallId") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + permission: value + .get("permission") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + approved: value + .get("approved") + .and_then(|v| v.as_bool()) + .unwrap_or(false), + reason: value + .get("reason") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + result: value + .get("result") + .cloned() + .unwrap_or(serde_json::Value::Null), + redaction: value + .get("redaction") + .filter(|v| v.is_object() || v.is_array() || v.is_string()) + .map(|v| RedactionMetadata::load_from_value(v, ctx)), } } @@ -66,15 +95,27 @@ impl PermissionCompletedPayload { let mut result = serde_json::Map::new(); // Write base fields if let Some(ref val) = self.request_id { - result.insert("requestId".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "requestId".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(ref val) = self.tool_call_id { - result.insert("toolCallId".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "toolCallId".to_string(), + serde_json::Value::String(val.clone()), + ); } if !self.permission.is_empty() { - result.insert("permission".to_string(), serde_json::Value::String(self.permission.clone())); + result.insert( + "permission".to_string(), + serde_json::Value::String(self.permission.clone()), + ); } - result.insert("approved".to_string(), serde_json::Value::Bool(self.approved)); + result.insert( + "approved".to_string(), + serde_json::Value::Bool(self.approved), + ); if let Some(ref val) = self.reason { result.insert("reason".to_string(), serde_json::Value::String(val.clone())); } @@ -104,5 +145,4 @@ impl PermissionCompletedPayload { pub fn as_result_dict(&self) -> Option<&serde_json::Map> { self.result.as_object() } - } diff --git a/runtime/rust/prompty/src/model/events/permission_decision.rs b/runtime/rust/prompty/src/model/events/permission_decision.rs index a9adfb52..7df0473a 100644 --- a/runtime/rust/prompty/src/model/events/permission_decision.rs +++ b/runtime/rust/prompty/src/model/events/permission_decision.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -45,12 +52,31 @@ impl PermissionDecision { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - request_id: value.get("requestId").and_then(|v| v.as_str()).map(|s| s.to_string()), - tool_call_id: value.get("toolCallId").and_then(|v| v.as_str()).map(|s| s.to_string()), - permission: value.get("permission").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - approved: value.get("approved").and_then(|v| v.as_bool()).unwrap_or(false), - reason: value.get("reason").and_then(|v| v.as_str()).map(|s| s.to_string()), - result: value.get("result").cloned().unwrap_or(serde_json::Value::Null), + request_id: value + .get("requestId") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + tool_call_id: value + .get("toolCallId") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + permission: value + .get("permission") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + approved: value + .get("approved") + .and_then(|v| v.as_bool()) + .unwrap_or(false), + reason: value + .get("reason") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + result: value + .get("result") + .cloned() + .unwrap_or(serde_json::Value::Null), } } @@ -61,15 +87,27 @@ impl PermissionDecision { let mut result = serde_json::Map::new(); // Write base fields if let Some(ref val) = self.request_id { - result.insert("requestId".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "requestId".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(ref val) = self.tool_call_id { - result.insert("toolCallId".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "toolCallId".to_string(), + serde_json::Value::String(val.clone()), + ); } if !self.permission.is_empty() { - result.insert("permission".to_string(), serde_json::Value::String(self.permission.clone())); + result.insert( + "permission".to_string(), + serde_json::Value::String(self.permission.clone()), + ); } - result.insert("approved".to_string(), serde_json::Value::Bool(self.approved)); + result.insert( + "approved".to_string(), + serde_json::Value::Bool(self.approved), + ); if let Some(ref val) = self.reason { result.insert("reason".to_string(), serde_json::Value::String(val.clone())); } @@ -93,5 +131,4 @@ impl PermissionDecision { pub fn as_result_dict(&self) -> Option<&serde_json::Map> { self.result.as_object() } - } diff --git a/runtime/rust/prompty/src/model/events/permission_request.rs b/runtime/rust/prompty/src/model/events/permission_request.rs index 7ea8788b..1c808f61 100644 --- a/runtime/rust/prompty/src/model/events/permission_request.rs +++ b/runtime/rust/prompty/src/model/events/permission_request.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -47,13 +54,35 @@ impl PermissionRequest { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - request_id: value.get("requestId").and_then(|v| v.as_str()).map(|s| s.to_string()), - tool_call_id: value.get("toolCallId").and_then(|v| v.as_str()).map(|s| s.to_string()), - permission: value.get("permission").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - target: value.get("target").and_then(|v| v.as_str()).map(|s| s.to_string()), - details: value.get("details").cloned().unwrap_or(serde_json::Value::Null), - prompt_request: value.get("promptRequest").and_then(|v| v.as_str()).map(|s| s.to_string()), - policy: value.get("policy").cloned().unwrap_or(serde_json::Value::Null), + request_id: value + .get("requestId") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + tool_call_id: value + .get("toolCallId") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + permission: value + .get("permission") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + target: value + .get("target") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + details: value + .get("details") + .cloned() + .unwrap_or(serde_json::Value::Null), + prompt_request: value + .get("promptRequest") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + policy: value + .get("policy") + .cloned() + .unwrap_or(serde_json::Value::Null), } } @@ -64,13 +93,22 @@ impl PermissionRequest { let mut result = serde_json::Map::new(); // Write base fields if let Some(ref val) = self.request_id { - result.insert("requestId".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "requestId".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(ref val) = self.tool_call_id { - result.insert("toolCallId".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "toolCallId".to_string(), + serde_json::Value::String(val.clone()), + ); } if !self.permission.is_empty() { - result.insert("permission".to_string(), serde_json::Value::String(self.permission.clone())); + result.insert( + "permission".to_string(), + serde_json::Value::String(self.permission.clone()), + ); } if let Some(ref val) = self.target { result.insert("target".to_string(), serde_json::Value::String(val.clone())); @@ -79,7 +117,10 @@ impl PermissionRequest { result.insert("details".to_string(), self.details.clone()); } if let Some(ref val) = self.prompt_request { - result.insert("promptRequest".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "promptRequest".to_string(), + serde_json::Value::String(val.clone()), + ); } if !self.policy.is_null() { result.insert("policy".to_string(), self.policy.clone()); @@ -107,5 +148,4 @@ impl PermissionRequest { pub fn as_policy_dict(&self) -> Option<&serde_json::Map> { self.policy.as_object() } - } diff --git a/runtime/rust/prompty/src/model/events/permission_requested_payload.rs b/runtime/rust/prompty/src/model/events/permission_requested_payload.rs index 43353537..e28cd971 100644 --- a/runtime/rust/prompty/src/model/events/permission_requested_payload.rs +++ b/runtime/rust/prompty/src/model/events/permission_requested_payload.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -51,14 +58,39 @@ impl PermissionRequestedPayload { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - request_id: value.get("requestId").and_then(|v| v.as_str()).map(|s| s.to_string()), - tool_call_id: value.get("toolCallId").and_then(|v| v.as_str()).map(|s| s.to_string()), - permission: value.get("permission").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - target: value.get("target").and_then(|v| v.as_str()).map(|s| s.to_string()), - details: value.get("details").cloned().unwrap_or(serde_json::Value::Null), - prompt_request: value.get("promptRequest").and_then(|v| v.as_str()).map(|s| s.to_string()), - policy: value.get("policy").cloned().unwrap_or(serde_json::Value::Null), - redaction: value.get("redaction").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| RedactionMetadata::load_from_value(v, ctx)), + request_id: value + .get("requestId") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + tool_call_id: value + .get("toolCallId") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + permission: value + .get("permission") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + target: value + .get("target") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + details: value + .get("details") + .cloned() + .unwrap_or(serde_json::Value::Null), + prompt_request: value + .get("promptRequest") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + policy: value + .get("policy") + .cloned() + .unwrap_or(serde_json::Value::Null), + redaction: value + .get("redaction") + .filter(|v| v.is_object() || v.is_array() || v.is_string()) + .map(|v| RedactionMetadata::load_from_value(v, ctx)), } } @@ -69,13 +101,22 @@ impl PermissionRequestedPayload { let mut result = serde_json::Map::new(); // Write base fields if let Some(ref val) = self.request_id { - result.insert("requestId".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "requestId".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(ref val) = self.tool_call_id { - result.insert("toolCallId".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "toolCallId".to_string(), + serde_json::Value::String(val.clone()), + ); } if !self.permission.is_empty() { - result.insert("permission".to_string(), serde_json::Value::String(self.permission.clone())); + result.insert( + "permission".to_string(), + serde_json::Value::String(self.permission.clone()), + ); } if let Some(ref val) = self.target { result.insert("target".to_string(), serde_json::Value::String(val.clone())); @@ -84,7 +125,10 @@ impl PermissionRequestedPayload { result.insert("details".to_string(), self.details.clone()); } if let Some(ref val) = self.prompt_request { - result.insert("promptRequest".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "promptRequest".to_string(), + serde_json::Value::String(val.clone()), + ); } if !self.policy.is_null() { result.insert("policy".to_string(), self.policy.clone()); @@ -118,5 +162,4 @@ impl PermissionRequestedPayload { pub fn as_policy_dict(&self) -> Option<&serde_json::Map> { self.policy.as_object() } - } diff --git a/runtime/rust/prompty/src/model/events/redacted_field.rs b/runtime/rust/prompty/src/model/events/redacted_field.rs index be21f755..ba90dd51 100644 --- a/runtime/rust/prompty/src/model/events/redacted_field.rs +++ b/runtime/rust/prompty/src/model/events/redacted_field.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -89,9 +96,20 @@ impl RedactedField { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - path: value.get("path").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - mode: value.get("mode").and_then(|v| v.as_str()).and_then(|s| RedactionMode::from_str_opt(s)).unwrap_or(RedactionMode::None), - reason: value.get("reason").and_then(|v| v.as_str()).map(|s| s.to_string()), + path: value + .get("path") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + mode: value + .get("mode") + .and_then(|v| v.as_str()) + .and_then(|s| RedactionMode::from_str_opt(s)) + .unwrap_or(RedactionMode::None), + reason: value + .get("reason") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), } } @@ -102,9 +120,15 @@ impl RedactedField { let mut result = serde_json::Map::new(); // Write base fields if !self.path.is_empty() { - result.insert("path".to_string(), serde_json::Value::String(self.path.clone())); + result.insert( + "path".to_string(), + serde_json::Value::String(self.path.clone()), + ); } - result.insert("mode".to_string(), serde_json::Value::String(self.mode.to_string())); + result.insert( + "mode".to_string(), + serde_json::Value::String(self.mode.to_string()), + ); if let Some(ref val) = self.reason { result.insert("reason".to_string(), serde_json::Value::String(val.clone())); } diff --git a/runtime/rust/prompty/src/model/events/redaction_metadata.rs b/runtime/rust/prompty/src/model/events/redaction_metadata.rs index 2a5cd8eb..f2da1343 100644 --- a/runtime/rust/prompty/src/model/events/redaction_metadata.rs +++ b/runtime/rust/prompty/src/model/events/redaction_metadata.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -42,8 +49,14 @@ impl RedactionMetadata { let value = ctx.process_input(value.clone()); Self { sanitized: value.get("sanitized").and_then(|v| v.as_bool()), - fields: value.get("fields").map(|v| Self::load_fields(v, ctx)).unwrap_or_default(), - policy: value.get("policy").and_then(|v| v.as_str()).map(|s| s.to_string()), + fields: value + .get("fields") + .map(|v| Self::load_fields(v, ctx)) + .unwrap_or_default(), + policy: value + .get("policy") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), } } @@ -79,19 +92,22 @@ impl RedactionMetadata { /// Handles both array format `[{...}]`. fn load_fields(data: &serde_json::Value, ctx: &LoadContext) -> Vec { match data { - serde_json::Value::Array(arr) => { - arr.iter().map(|v| RedactedField::load_from_value(v, ctx)).collect() - } + serde_json::Value::Array(arr) => arr + .iter() + .map(|v| RedactedField::load_from_value(v, ctx)) + .collect(), _ => Vec::new(), - } } /// Save a collection of RedactedField to a JSON value. fn save_fields(items: &[RedactedField], ctx: &SaveContext) -> serde_json::Value { - - serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()) - + serde_json::Value::Array( + items + .iter() + .map(|item| item.to_value(ctx)) + .collect::>(), + ) } } diff --git a/runtime/rust/prompty/src/model/events/retry_payload.rs b/runtime/rust/prompty/src/model/events/retry_payload.rs index 2e5b718a..03fe2df4 100644 --- a/runtime/rust/prompty/src/model/events/retry_payload.rs +++ b/runtime/rust/prompty/src/model/events/retry_payload.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -43,11 +50,21 @@ impl RetryPayload { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - operation: value.get("operation").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + operation: value + .get("operation") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), attempt: value.get("attempt").and_then(|v| v.as_i64()).unwrap_or(0) as i32, - max_attempts: value.get("maxAttempts").and_then(|v| v.as_i64()).map(|v| v as i32), + max_attempts: value + .get("maxAttempts") + .and_then(|v| v.as_i64()) + .map(|v| v as i32), delay_ms: value.get("delayMs").and_then(|v| v.as_f64()), - reason: value.get("reason").and_then(|v| v.as_str()).map(|s| s.to_string()), + reason: value + .get("reason") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), } } @@ -58,16 +75,30 @@ impl RetryPayload { let mut result = serde_json::Map::new(); // Write base fields if !self.operation.is_empty() { - result.insert("operation".to_string(), serde_json::Value::String(self.operation.clone())); + result.insert( + "operation".to_string(), + serde_json::Value::String(self.operation.clone()), + ); } if self.attempt != 0 { - result.insert("attempt".to_string(), serde_json::Value::Number(serde_json::Number::from(self.attempt))); + result.insert( + "attempt".to_string(), + serde_json::Value::Number(serde_json::Number::from(self.attempt)), + ); } if let Some(val) = self.max_attempts { - result.insert("maxAttempts".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + result.insert( + "maxAttempts".to_string(), + serde_json::Value::Number(serde_json::Number::from(val)), + ); } if let Some(val) = self.delay_ms { - result.insert("delayMs".to_string(), serde_json::Number::from_f64(val as f64).map(serde_json::Value::Number).unwrap_or(serde_json::Value::Null)); + result.insert( + "delayMs".to_string(), + serde_json::Number::from_f64(val as f64) + .map(serde_json::Value::Number) + .unwrap_or(serde_json::Value::Null), + ); } if let Some(ref val) = self.reason { result.insert("reason".to_string(), serde_json::Value::String(val.clone())); diff --git a/runtime/rust/prompty/src/model/events/session_end_payload.rs b/runtime/rust/prompty/src/model/events/session_end_payload.rs index 86e13a4c..f6dec72f 100644 --- a/runtime/rust/prompty/src/model/events/session_end_payload.rs +++ b/runtime/rust/prompty/src/model/events/session_end_payload.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -87,9 +94,18 @@ impl SessionEndPayload { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - session_id: value.get("sessionId").and_then(|v| v.as_str()).map(|s| s.to_string()), - status: value.get("status").and_then(|v| v.as_str()).and_then(|s| SessionEndStatus::from_str_opt(s)), - reason: value.get("reason").and_then(|v| v.as_str()).map(|s| s.to_string()), + session_id: value + .get("sessionId") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + status: value + .get("status") + .and_then(|v| v.as_str()) + .and_then(|s| SessionEndStatus::from_str_opt(s)), + reason: value + .get("reason") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), duration_ms: value.get("durationMs").and_then(|v| v.as_f64()), } } @@ -101,16 +117,27 @@ impl SessionEndPayload { let mut result = serde_json::Map::new(); // Write base fields if let Some(ref val) = self.session_id { - result.insert("sessionId".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "sessionId".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(ref val) = self.status { - result.insert("status".to_string(), serde_json::Value::String(val.to_string())); + result.insert( + "status".to_string(), + serde_json::Value::String(val.to_string()), + ); } if let Some(ref val) = self.reason { result.insert("reason".to_string(), serde_json::Value::String(val.clone())); } if let Some(val) = self.duration_ms { - result.insert("durationMs".to_string(), serde_json::Number::from_f64(val as f64).map(serde_json::Value::Number).unwrap_or(serde_json::Value::Null)); + result.insert( + "durationMs".to_string(), + serde_json::Number::from_f64(val as f64) + .map(serde_json::Value::Number) + .unwrap_or(serde_json::Value::Null), + ); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/events/session_event.rs b/runtime/rust/prompty/src/model/events/session_event.rs index 8ea3a7c7..89f71f6d 100644 --- a/runtime/rust/prompty/src/model/events/session_event.rs +++ b/runtime/rust/prompty/src/model/events/session_event.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -111,15 +118,45 @@ impl SessionEvent { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - id: value.get("id").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - r#type: value.get("type").and_then(|v| v.as_str()).and_then(|s| SessionEventType::from_str_opt(s)).unwrap_or(SessionEventType::Session_start), - timestamp: value.get("timestamp").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - session_id: value.get("sessionId").and_then(|v| v.as_str()).map(|s| s.to_string()), - turn_id: value.get("turnId").and_then(|v| v.as_str()).map(|s| s.to_string()), - parent_id: value.get("parentId").and_then(|v| v.as_str()).map(|s| s.to_string()), - span_id: value.get("spanId").and_then(|v| v.as_str()).map(|s| s.to_string()), - payload: value.get("payload").cloned().unwrap_or(serde_json::Value::Null), - redaction: value.get("redaction").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| RedactionMetadata::load_from_value(v, ctx)), + id: value + .get("id") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + r#type: value + .get("type") + .and_then(|v| v.as_str()) + .and_then(|s| SessionEventType::from_str_opt(s)) + .unwrap_or(SessionEventType::Session_start), + timestamp: value + .get("timestamp") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + session_id: value + .get("sessionId") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + turn_id: value + .get("turnId") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + parent_id: value + .get("parentId") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + span_id: value + .get("spanId") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + payload: value + .get("payload") + .cloned() + .unwrap_or(serde_json::Value::Null), + redaction: value + .get("redaction") + .filter(|v| v.is_object() || v.is_array() || v.is_string()) + .map(|v| RedactionMetadata::load_from_value(v, ctx)), } } @@ -132,18 +169,30 @@ impl SessionEvent { if !self.id.is_empty() { result.insert("id".to_string(), serde_json::Value::String(self.id.clone())); } - result.insert("type".to_string(), serde_json::Value::String(self.r#type.to_string())); + result.insert( + "type".to_string(), + serde_json::Value::String(self.r#type.to_string()), + ); if !self.timestamp.is_empty() { - result.insert("timestamp".to_string(), serde_json::Value::String(self.timestamp.clone())); + result.insert( + "timestamp".to_string(), + serde_json::Value::String(self.timestamp.clone()), + ); } if let Some(ref val) = self.session_id { - result.insert("sessionId".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "sessionId".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(ref val) = self.turn_id { result.insert("turnId".to_string(), serde_json::Value::String(val.clone())); } if let Some(ref val) = self.parent_id { - result.insert("parentId".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "parentId".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(ref val) = self.span_id { result.insert("spanId".to_string(), serde_json::Value::String(val.clone())); @@ -174,5 +223,4 @@ impl SessionEvent { pub fn as_payload_dict(&self) -> Option<&serde_json::Map> { self.payload.as_object() } - } diff --git a/runtime/rust/prompty/src/model/events/session_file_ref.rs b/runtime/rust/prompty/src/model/events/session_file_ref.rs index 981b0496..42b3bbd8 100644 --- a/runtime/rust/prompty/src/model/events/session_file_ref.rs +++ b/runtime/rust/prompty/src/model/events/session_file_ref.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -43,11 +50,27 @@ impl SessionFileRef { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - session_id: value.get("sessionId").and_then(|v| v.as_str()).map(|s| s.to_string()), - path: value.get("path").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - tool_name: value.get("toolName").and_then(|v| v.as_str()).map(|s| s.to_string()), - turn_index: value.get("turnIndex").and_then(|v| v.as_i64()).map(|v| v as i32), - first_seen_at: value.get("firstSeenAt").and_then(|v| v.as_str()).map(|s| s.to_string()), + session_id: value + .get("sessionId") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + path: value + .get("path") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + tool_name: value + .get("toolName") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + turn_index: value + .get("turnIndex") + .and_then(|v| v.as_i64()) + .map(|v| v as i32), + first_seen_at: value + .get("firstSeenAt") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), } } @@ -58,19 +81,34 @@ impl SessionFileRef { let mut result = serde_json::Map::new(); // Write base fields if let Some(ref val) = self.session_id { - result.insert("sessionId".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "sessionId".to_string(), + serde_json::Value::String(val.clone()), + ); } if !self.path.is_empty() { - result.insert("path".to_string(), serde_json::Value::String(self.path.clone())); + result.insert( + "path".to_string(), + serde_json::Value::String(self.path.clone()), + ); } if let Some(ref val) = self.tool_name { - result.insert("toolName".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "toolName".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(val) = self.turn_index { - result.insert("turnIndex".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + result.insert( + "turnIndex".to_string(), + serde_json::Value::Number(serde_json::Number::from(val)), + ); } if let Some(ref val) = self.first_seen_at { - result.insert("firstSeenAt".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "firstSeenAt".to_string(), + serde_json::Value::String(val.clone()), + ); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/events/session_ref.rs b/runtime/rust/prompty/src/model/events/session_ref.rs index a0018b19..6760161b 100644 --- a/runtime/rust/prompty/src/model/events/session_ref.rs +++ b/runtime/rust/prompty/src/model/events/session_ref.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -43,11 +50,28 @@ impl SessionRef { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - session_id: value.get("sessionId").and_then(|v| v.as_str()).map(|s| s.to_string()), - ref_type: value.get("refType").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - ref_value: value.get("refValue").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - turn_index: value.get("turnIndex").and_then(|v| v.as_i64()).map(|v| v as i32), - created_at: value.get("createdAt").and_then(|v| v.as_str()).map(|s| s.to_string()), + session_id: value + .get("sessionId") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + ref_type: value + .get("refType") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + ref_value: value + .get("refValue") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + turn_index: value + .get("turnIndex") + .and_then(|v| v.as_i64()) + .map(|v| v as i32), + created_at: value + .get("createdAt") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), } } @@ -58,19 +82,34 @@ impl SessionRef { let mut result = serde_json::Map::new(); // Write base fields if let Some(ref val) = self.session_id { - result.insert("sessionId".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "sessionId".to_string(), + serde_json::Value::String(val.clone()), + ); } if !self.ref_type.is_empty() { - result.insert("refType".to_string(), serde_json::Value::String(self.ref_type.clone())); + result.insert( + "refType".to_string(), + serde_json::Value::String(self.ref_type.clone()), + ); } if !self.ref_value.is_empty() { - result.insert("refValue".to_string(), serde_json::Value::String(self.ref_value.clone())); + result.insert( + "refValue".to_string(), + serde_json::Value::String(self.ref_value.clone()), + ); } if let Some(val) = self.turn_index { - result.insert("turnIndex".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + result.insert( + "turnIndex".to_string(), + serde_json::Value::Number(serde_json::Number::from(val)), + ); } if let Some(ref val) = self.created_at { - result.insert("createdAt".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "createdAt".to_string(), + serde_json::Value::String(val.clone()), + ); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/events/session_start_payload.rs b/runtime/rust/prompty/src/model/events/session_start_payload.rs index a98a03f6..e6b20c75 100644 --- a/runtime/rust/prompty/src/model/events/session_start_payload.rs +++ b/runtime/rust/prompty/src/model/events/session_start_payload.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -53,15 +60,43 @@ impl SessionStartPayload { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - session_id: value.get("sessionId").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - schema_version: value.get("schemaVersion").and_then(|v| v.as_str()).map(|s| s.to_string()), - producer: value.get("producer").and_then(|v| v.as_str()).map(|s| s.to_string()), - runtime: value.get("runtime").and_then(|v| v.as_str()).map(|s| s.to_string()), - prompty_version: value.get("promptyVersion").and_then(|v| v.as_str()).map(|s| s.to_string()), - start_time: value.get("startTime").and_then(|v| v.as_str()).map(|s| s.to_string()), - selected_model: value.get("selectedModel").and_then(|v| v.as_str()).map(|s| s.to_string()), - reasoning_effort: value.get("reasoningEffort").and_then(|v| v.as_str()).map(|s| s.to_string()), - context: value.get("context").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| HarnessContext::load_from_value(v, ctx)), + session_id: value + .get("sessionId") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + schema_version: value + .get("schemaVersion") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + producer: value + .get("producer") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + runtime: value + .get("runtime") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + prompty_version: value + .get("promptyVersion") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + start_time: value + .get("startTime") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + selected_model: value + .get("selectedModel") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + reasoning_effort: value + .get("reasoningEffort") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + context: value + .get("context") + .filter(|v| v.is_object() || v.is_array() || v.is_string()) + .map(|v| HarnessContext::load_from_value(v, ctx)), } } @@ -72,28 +107,52 @@ impl SessionStartPayload { let mut result = serde_json::Map::new(); // Write base fields if !self.session_id.is_empty() { - result.insert("sessionId".to_string(), serde_json::Value::String(self.session_id.clone())); + result.insert( + "sessionId".to_string(), + serde_json::Value::String(self.session_id.clone()), + ); } if let Some(ref val) = self.schema_version { - result.insert("schemaVersion".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "schemaVersion".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(ref val) = self.producer { - result.insert("producer".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "producer".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(ref val) = self.runtime { - result.insert("runtime".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "runtime".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(ref val) = self.prompty_version { - result.insert("promptyVersion".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "promptyVersion".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(ref val) = self.start_time { - result.insert("startTime".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "startTime".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(ref val) = self.selected_model { - result.insert("selectedModel".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "selectedModel".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(ref val) = self.reasoning_effort { - result.insert("reasoningEffort".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "reasoningEffort".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(ref val) = self.context { let nested = val.to_value(ctx); diff --git a/runtime/rust/prompty/src/model/events/session_summary.rs b/runtime/rust/prompty/src/model/events/session_summary.rs index 2aafb579..23669d39 100644 --- a/runtime/rust/prompty/src/model/events/session_summary.rs +++ b/runtime/rust/prompty/src/model/events/session_summary.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -93,11 +100,27 @@ impl SessionSummary { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - session_id: value.get("sessionId").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - status: value.get("status").and_then(|v| v.as_str()).and_then(|s| SessionSummaryStatus::from_str_opt(s)), - turns: value.get("turns").and_then(|v| v.as_i64()).map(|v| v as i32), - checkpoints: value.get("checkpoints").and_then(|v| v.as_i64()).map(|v| v as i32), - usage: value.get("usage").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| TokenUsage::load_from_value(v, ctx)), + session_id: value + .get("sessionId") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + status: value + .get("status") + .and_then(|v| v.as_str()) + .and_then(|s| SessionSummaryStatus::from_str_opt(s)), + turns: value + .get("turns") + .and_then(|v| v.as_i64()) + .map(|v| v as i32), + checkpoints: value + .get("checkpoints") + .and_then(|v| v.as_i64()) + .map(|v| v as i32), + usage: value + .get("usage") + .filter(|v| v.is_object() || v.is_array() || v.is_string()) + .map(|v| TokenUsage::load_from_value(v, ctx)), duration_ms: value.get("durationMs").and_then(|v| v.as_f64()), } } @@ -109,16 +132,28 @@ impl SessionSummary { let mut result = serde_json::Map::new(); // Write base fields if !self.session_id.is_empty() { - result.insert("sessionId".to_string(), serde_json::Value::String(self.session_id.clone())); + result.insert( + "sessionId".to_string(), + serde_json::Value::String(self.session_id.clone()), + ); } if let Some(ref val) = self.status { - result.insert("status".to_string(), serde_json::Value::String(val.to_string())); + result.insert( + "status".to_string(), + serde_json::Value::String(val.to_string()), + ); } if let Some(val) = self.turns { - result.insert("turns".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + result.insert( + "turns".to_string(), + serde_json::Value::Number(serde_json::Number::from(val)), + ); } if let Some(val) = self.checkpoints { - result.insert("checkpoints".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + result.insert( + "checkpoints".to_string(), + serde_json::Value::Number(serde_json::Number::from(val)), + ); } if let Some(ref val) = self.usage { let nested = val.to_value(ctx); @@ -127,7 +162,12 @@ impl SessionSummary { } } if let Some(val) = self.duration_ms { - result.insert("durationMs".to_string(), serde_json::Number::from_f64(val as f64).map(serde_json::Value::Number).unwrap_or(serde_json::Value::Null)); + result.insert( + "durationMs".to_string(), + serde_json::Number::from_f64(val as f64) + .map(serde_json::Value::Number) + .unwrap_or(serde_json::Value::Null), + ); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/events/session_trace.rs b/runtime/rust/prompty/src/model/events/session_trace.rs index 5b9a1a8b..d4c51be1 100644 --- a/runtime/rust/prompty/src/model/events/session_trace.rs +++ b/runtime/rust/prompty/src/model/events/session_trace.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -69,17 +76,51 @@ impl SessionTrace { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - version: value.get("version").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - runtime: value.get("runtime").and_then(|v| v.as_str()).map(|s| s.to_string()), - prompty_version: value.get("promptyVersion").and_then(|v| v.as_str()).map(|s| s.to_string()), - session_id: value.get("sessionId").and_then(|v| v.as_str()).map(|s| s.to_string()), - events: value.get("events").map(|v| Self::load_events(v, ctx)).unwrap_or_default(), - turns: value.get("turns").map(|v| Self::load_turns(v, ctx)).unwrap_or_default(), - checkpoints: value.get("checkpoints").map(|v| Self::load_checkpoints(v, ctx)).unwrap_or_default(), - trajectory: value.get("trajectory").map(|v| Self::load_trajectory(v, ctx)).unwrap_or_default(), - files: value.get("files").map(|v| Self::load_files(v, ctx)).unwrap_or_default(), - refs: value.get("refs").map(|v| Self::load_refs(v, ctx)).unwrap_or_default(), - summary: value.get("summary").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| SessionSummary::load_from_value(v, ctx)), + version: value + .get("version") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + runtime: value + .get("runtime") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + prompty_version: value + .get("promptyVersion") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + session_id: value + .get("sessionId") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + events: value + .get("events") + .map(|v| Self::load_events(v, ctx)) + .unwrap_or_default(), + turns: value + .get("turns") + .map(|v| Self::load_turns(v, ctx)) + .unwrap_or_default(), + checkpoints: value + .get("checkpoints") + .map(|v| Self::load_checkpoints(v, ctx)) + .unwrap_or_default(), + trajectory: value + .get("trajectory") + .map(|v| Self::load_trajectory(v, ctx)) + .unwrap_or_default(), + files: value + .get("files") + .map(|v| Self::load_files(v, ctx)) + .unwrap_or_default(), + refs: value + .get("refs") + .map(|v| Self::load_refs(v, ctx)) + .unwrap_or_default(), + summary: value + .get("summary") + .filter(|v| v.is_object() || v.is_array() || v.is_string()) + .map(|v| SessionSummary::load_from_value(v, ctx)), } } @@ -90,16 +131,28 @@ impl SessionTrace { let mut result = serde_json::Map::new(); // Write base fields if !self.version.is_empty() { - result.insert("version".to_string(), serde_json::Value::String(self.version.clone())); + result.insert( + "version".to_string(), + serde_json::Value::String(self.version.clone()), + ); } if let Some(ref val) = self.runtime { - result.insert("runtime".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "runtime".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(ref val) = self.prompty_version { - result.insert("promptyVersion".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "promptyVersion".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(ref val) = self.session_id { - result.insert("sessionId".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "sessionId".to_string(), + serde_json::Value::String(val.clone()), + ); } if !self.events.is_empty() { result.insert("events".to_string(), Self::save_events(&self.events, ctx)); @@ -108,10 +161,16 @@ impl SessionTrace { result.insert("turns".to_string(), Self::save_turns(&self.turns, ctx)); } if !self.checkpoints.is_empty() { - result.insert("checkpoints".to_string(), Self::save_checkpoints(&self.checkpoints, ctx)); + result.insert( + "checkpoints".to_string(), + Self::save_checkpoints(&self.checkpoints, ctx), + ); } if !self.trajectory.is_empty() { - result.insert("trajectory".to_string(), Self::save_trajectory(&self.trajectory, ctx)); + result.insert( + "trajectory".to_string(), + Self::save_trajectory(&self.trajectory, ctx), + ); } if !self.files.is_empty() { result.insert("files".to_string(), Self::save_files(&self.files, ctx)); @@ -142,119 +201,137 @@ impl SessionTrace { /// Handles both array format `[{...}]`. fn load_events(data: &serde_json::Value, ctx: &LoadContext) -> Vec { match data { - serde_json::Value::Array(arr) => { - arr.iter().map(|v| SessionEvent::load_from_value(v, ctx)).collect() - } + serde_json::Value::Array(arr) => arr + .iter() + .map(|v| SessionEvent::load_from_value(v, ctx)) + .collect(), _ => Vec::new(), - } } /// Save a collection of SessionEvent to a JSON value. fn save_events(items: &[SessionEvent], ctx: &SaveContext) -> serde_json::Value { - - serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()) - + serde_json::Value::Array( + items + .iter() + .map(|item| item.to_value(ctx)) + .collect::>(), + ) } /// Load a collection of TurnTrace from a JSON value. /// Handles both array format `[{...}]`. fn load_turns(data: &serde_json::Value, ctx: &LoadContext) -> Vec { match data { - serde_json::Value::Array(arr) => { - arr.iter().map(|v| TurnTrace::load_from_value(v, ctx)).collect() - } + serde_json::Value::Array(arr) => arr + .iter() + .map(|v| TurnTrace::load_from_value(v, ctx)) + .collect(), _ => Vec::new(), - } } /// Save a collection of TurnTrace to a JSON value. fn save_turns(items: &[TurnTrace], ctx: &SaveContext) -> serde_json::Value { - - serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()) - + serde_json::Value::Array( + items + .iter() + .map(|item| item.to_value(ctx)) + .collect::>(), + ) } /// Load a collection of Checkpoint from a JSON value. /// Handles both array format `[{...}]`. fn load_checkpoints(data: &serde_json::Value, ctx: &LoadContext) -> Vec { match data { - serde_json::Value::Array(arr) => { - arr.iter().map(|v| Checkpoint::load_from_value(v, ctx)).collect() - } + serde_json::Value::Array(arr) => arr + .iter() + .map(|v| Checkpoint::load_from_value(v, ctx)) + .collect(), _ => Vec::new(), - } } /// Save a collection of Checkpoint to a JSON value. fn save_checkpoints(items: &[Checkpoint], ctx: &SaveContext) -> serde_json::Value { - - serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()) - + serde_json::Value::Array( + items + .iter() + .map(|item| item.to_value(ctx)) + .collect::>(), + ) } /// Load a collection of TrajectoryEvent from a JSON value. /// Handles both array format `[{...}]`. fn load_trajectory(data: &serde_json::Value, ctx: &LoadContext) -> Vec { match data { - serde_json::Value::Array(arr) => { - arr.iter().map(|v| TrajectoryEvent::load_from_value(v, ctx)).collect() - } + serde_json::Value::Array(arr) => arr + .iter() + .map(|v| TrajectoryEvent::load_from_value(v, ctx)) + .collect(), _ => Vec::new(), - } } /// Save a collection of TrajectoryEvent to a JSON value. fn save_trajectory(items: &[TrajectoryEvent], ctx: &SaveContext) -> serde_json::Value { - - serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()) - + serde_json::Value::Array( + items + .iter() + .map(|item| item.to_value(ctx)) + .collect::>(), + ) } /// Load a collection of SessionFileRef from a JSON value. /// Handles both array format `[{...}]`. fn load_files(data: &serde_json::Value, ctx: &LoadContext) -> Vec { match data { - serde_json::Value::Array(arr) => { - arr.iter().map(|v| SessionFileRef::load_from_value(v, ctx)).collect() - } + serde_json::Value::Array(arr) => arr + .iter() + .map(|v| SessionFileRef::load_from_value(v, ctx)) + .collect(), _ => Vec::new(), - } } /// Save a collection of SessionFileRef to a JSON value. fn save_files(items: &[SessionFileRef], ctx: &SaveContext) -> serde_json::Value { - - serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()) - + serde_json::Value::Array( + items + .iter() + .map(|item| item.to_value(ctx)) + .collect::>(), + ) } /// Load a collection of SessionRef from a JSON value. /// Handles both array format `[{...}]`. fn load_refs(data: &serde_json::Value, ctx: &LoadContext) -> Vec { match data { - serde_json::Value::Array(arr) => { - arr.iter().map(|v| SessionRef::load_from_value(v, ctx)).collect() - } + serde_json::Value::Array(arr) => arr + .iter() + .map(|v| SessionRef::load_from_value(v, ctx)) + .collect(), _ => Vec::new(), - } } /// Save a collection of SessionRef to a JSON value. fn save_refs(items: &[SessionRef], ctx: &SaveContext) -> serde_json::Value { - - serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()) - + serde_json::Value::Array( + items + .iter() + .map(|item| item.to_value(ctx)) + .collect::>(), + ) } } diff --git a/runtime/rust/prompty/src/model/events/session_warning_payload.rs b/runtime/rust/prompty/src/model/events/session_warning_payload.rs index 27b8fd8d..899465ec 100644 --- a/runtime/rust/prompty/src/model/events/session_warning_payload.rs +++ b/runtime/rust/prompty/src/model/events/session_warning_payload.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -39,9 +46,20 @@ impl SessionWarningPayload { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - warning_type: value.get("warningType").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - message: value.get("message").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - details: value.get("details").cloned().unwrap_or(serde_json::Value::Null), + warning_type: value + .get("warningType") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + message: value + .get("message") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + details: value + .get("details") + .cloned() + .unwrap_or(serde_json::Value::Null), } } @@ -52,10 +70,16 @@ impl SessionWarningPayload { let mut result = serde_json::Map::new(); // Write base fields if !self.warning_type.is_empty() { - result.insert("warningType".to_string(), serde_json::Value::String(self.warning_type.clone())); + result.insert( + "warningType".to_string(), + serde_json::Value::String(self.warning_type.clone()), + ); } if !self.message.is_empty() { - result.insert("message".to_string(), serde_json::Value::String(self.message.clone())); + result.insert( + "message".to_string(), + serde_json::Value::String(self.message.clone()), + ); } if !self.details.is_null() { result.insert("details".to_string(), self.details.clone()); @@ -77,5 +101,4 @@ impl SessionWarningPayload { pub fn as_details_dict(&self) -> Option<&serde_json::Map> { self.details.as_object() } - } diff --git a/runtime/rust/prompty/src/model/events/status_event_payload.rs b/runtime/rust/prompty/src/model/events/status_event_payload.rs index e2150318..266b5503 100644 --- a/runtime/rust/prompty/src/model/events/status_event_payload.rs +++ b/runtime/rust/prompty/src/model/events/status_event_payload.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -35,7 +42,11 @@ impl StatusEventPayload { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - message: value.get("message").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + message: value + .get("message") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), } } @@ -46,7 +57,10 @@ impl StatusEventPayload { let mut result = serde_json::Map::new(); // Write base fields if !self.message.is_empty() { - result.insert("message".to_string(), serde_json::Value::String(self.message.clone())); + result.insert( + "message".to_string(), + serde_json::Value::String(self.message.clone()), + ); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/events/stream_chunk.rs b/runtime/rust/prompty/src/model/events/stream_chunk.rs index f76b4eb4..427fcf54 100644 --- a/runtime/rust/prompty/src/model/events/stream_chunk.rs +++ b/runtime/rust/prompty/src/model/events/stream_chunk.rs @@ -1,12 +1,18 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; use super::super::conversation::tool_call::ToolCall; - /// Variant-specific data for [`StreamChunk`], discriminated by `kind`. #[derive(Debug, Clone)] pub enum StreamChunkKind { @@ -72,22 +78,36 @@ impl StreamChunk { let kind_str = value.get("kind").and_then(|v| v.as_str()).unwrap_or(""); let kind = match kind_str { "text" => StreamChunkKind::TextChunk { - value: value.get("value").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + value: value + .get("value") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), }, "thinking" => StreamChunkKind::ThinkingChunk { - value: value.get("value").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + value: value + .get("value") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), }, "tool" => StreamChunkKind::ToolChunk { - tool_call: value.get("toolCall").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| ToolCall::load_from_value(v, ctx)).unwrap_or_default(), + tool_call: value + .get("toolCall") + .filter(|v| v.is_object() || v.is_array() || v.is_string()) + .map(|v| ToolCall::load_from_value(v, ctx)) + .unwrap_or_default(), }, "error" => StreamChunkKind::ErrorChunk { - message: value.get("message").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + message: value + .get("message") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), }, _ => StreamChunkKind::default(), }; - Self { - kind: kind, - } + Self { kind: kind } } /// Returns the `kind` discriminator string for this instance. @@ -106,31 +126,41 @@ impl StreamChunk { pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { let mut result = serde_json::Map::new(); // Write the discriminator - result.insert("kind".to_string(), serde_json::Value::String(self.kind_str().to_string())); + result.insert( + "kind".to_string(), + serde_json::Value::String(self.kind_str().to_string()), + ); // Write base fields // Write variant-specific fields match &self.kind { - StreamChunkKind::TextChunk { value, .. } => { + StreamChunkKind::TextChunk { value, .. } => { if !value.is_empty() { - result.insert("value".to_string(), serde_json::Value::String(value.clone())); + result.insert( + "value".to_string(), + serde_json::Value::String(value.clone()), + ); } } - StreamChunkKind::ThinkingChunk { value, .. } => { + StreamChunkKind::ThinkingChunk { value, .. } => { if !value.is_empty() { - result.insert("value".to_string(), serde_json::Value::String(value.clone())); + result.insert( + "value".to_string(), + serde_json::Value::String(value.clone()), + ); } } - StreamChunkKind::ToolChunk { tool_call, .. } => { - { - let nested = tool_call.to_value(ctx); - if !nested.is_null() { - result.insert("toolCall".to_string(), nested); - } + StreamChunkKind::ToolChunk { tool_call, .. } => { + let nested = tool_call.to_value(ctx); + if !nested.is_null() { + result.insert("toolCall".to_string(), nested); } } - StreamChunkKind::ErrorChunk { message, .. } => { + StreamChunkKind::ErrorChunk { message, .. } => { if !message.is_empty() { - result.insert("message".to_string(), serde_json::Value::String(message.clone())); + result.insert( + "message".to_string(), + serde_json::Value::String(message.clone()), + ); } } } diff --git a/runtime/rust/prompty/src/model/events/thinking_event_payload.rs b/runtime/rust/prompty/src/model/events/thinking_event_payload.rs index a5613146..9b440896 100644 --- a/runtime/rust/prompty/src/model/events/thinking_event_payload.rs +++ b/runtime/rust/prompty/src/model/events/thinking_event_payload.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -35,7 +42,11 @@ impl ThinkingEventPayload { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - token: value.get("token").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + token: value + .get("token") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), } } @@ -46,7 +57,10 @@ impl ThinkingEventPayload { let mut result = serde_json::Map::new(); // Write base fields if !self.token.is_empty() { - result.insert("token".to_string(), serde_json::Value::String(self.token.clone())); + result.insert( + "token".to_string(), + serde_json::Value::String(self.token.clone()), + ); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/events/token_event_payload.rs b/runtime/rust/prompty/src/model/events/token_event_payload.rs index fc0fc29b..9376a1c3 100644 --- a/runtime/rust/prompty/src/model/events/token_event_payload.rs +++ b/runtime/rust/prompty/src/model/events/token_event_payload.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -35,7 +42,11 @@ impl TokenEventPayload { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - token: value.get("token").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + token: value + .get("token") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), } } @@ -46,7 +57,10 @@ impl TokenEventPayload { let mut result = serde_json::Map::new(); // Write base fields if !self.token.is_empty() { - result.insert("token".to_string(), serde_json::Value::String(self.token.clone())); + result.insert( + "token".to_string(), + serde_json::Value::String(self.token.clone()), + ); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/events/tool_call_complete_payload.rs b/runtime/rust/prompty/src/model/events/tool_call_complete_payload.rs index 639ff869..6322fc76 100644 --- a/runtime/rust/prompty/src/model/events/tool_call_complete_payload.rs +++ b/runtime/rust/prompty/src/model/events/tool_call_complete_payload.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -47,12 +54,28 @@ impl ToolCallCompletePayload { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - id: value.get("id").and_then(|v| v.as_str()).map(|s| s.to_string()), - name: value.get("name").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - success: value.get("success").and_then(|v| v.as_bool()).unwrap_or(false), - result: value.get("result").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| ToolResult::load_from_value(v, ctx)), + id: value + .get("id") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + name: value + .get("name") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + success: value + .get("success") + .and_then(|v| v.as_bool()) + .unwrap_or(false), + result: value + .get("result") + .filter(|v| v.is_object() || v.is_array() || v.is_string()) + .map(|v| ToolResult::load_from_value(v, ctx)), duration_ms: value.get("durationMs").and_then(|v| v.as_f64()), - error_kind: value.get("errorKind").and_then(|v| v.as_str()).map(|s| s.to_string()), + error_kind: value + .get("errorKind") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), } } @@ -66,7 +89,10 @@ impl ToolCallCompletePayload { result.insert("id".to_string(), serde_json::Value::String(val.clone())); } if !self.name.is_empty() { - result.insert("name".to_string(), serde_json::Value::String(self.name.clone())); + result.insert( + "name".to_string(), + serde_json::Value::String(self.name.clone()), + ); } result.insert("success".to_string(), serde_json::Value::Bool(self.success)); if let Some(ref val) = self.result { @@ -76,10 +102,18 @@ impl ToolCallCompletePayload { } } if let Some(val) = self.duration_ms { - result.insert("durationMs".to_string(), serde_json::Number::from_f64(val as f64).map(serde_json::Value::Number).unwrap_or(serde_json::Value::Null)); + result.insert( + "durationMs".to_string(), + serde_json::Number::from_f64(val as f64) + .map(serde_json::Value::Number) + .unwrap_or(serde_json::Value::Null), + ); } if let Some(ref val) = self.error_kind { - result.insert("errorKind".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "errorKind".to_string(), + serde_json::Value::String(val.clone()), + ); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/events/tool_call_start_payload.rs b/runtime/rust/prompty/src/model/events/tool_call_start_payload.rs index 0582fb2c..4a396113 100644 --- a/runtime/rust/prompty/src/model/events/tool_call_start_payload.rs +++ b/runtime/rust/prompty/src/model/events/tool_call_start_payload.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -39,9 +46,20 @@ impl ToolCallStartPayload { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - id: value.get("id").and_then(|v| v.as_str()).map(|s| s.to_string()), - name: value.get("name").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - arguments: value.get("arguments").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + id: value + .get("id") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + name: value + .get("name") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + arguments: value + .get("arguments") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), } } @@ -55,10 +73,16 @@ impl ToolCallStartPayload { result.insert("id".to_string(), serde_json::Value::String(val.clone())); } if !self.name.is_empty() { - result.insert("name".to_string(), serde_json::Value::String(self.name.clone())); + result.insert( + "name".to_string(), + serde_json::Value::String(self.name.clone()), + ); } if !self.arguments.is_empty() { - result.insert("arguments".to_string(), serde_json::Value::String(self.arguments.clone())); + result.insert( + "arguments".to_string(), + serde_json::Value::String(self.arguments.clone()), + ); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/events/tool_execution_complete_payload.rs b/runtime/rust/prompty/src/model/events/tool_execution_complete_payload.rs index 7abb8ae8..72790c92 100644 --- a/runtime/rust/prompty/src/model/events/tool_execution_complete_payload.rs +++ b/runtime/rust/prompty/src/model/events/tool_execution_complete_payload.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -55,16 +62,41 @@ impl ToolExecutionCompletePayload { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - request_id: value.get("requestId").and_then(|v| v.as_str()).map(|s| s.to_string()), - tool_call_id: value.get("toolCallId").and_then(|v| v.as_str()).map(|s| s.to_string()), - tool_name: value.get("toolName").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - success: value.get("success").and_then(|v| v.as_bool()).unwrap_or(false), + request_id: value + .get("requestId") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + tool_call_id: value + .get("toolCallId") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + tool_name: value + .get("toolName") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + success: value + .get("success") + .and_then(|v| v.as_bool()) + .unwrap_or(false), result: value.get("result").cloned(), - exit_code: value.get("exitCode").and_then(|v| v.as_i64()).map(|v| v as i32), + exit_code: value + .get("exitCode") + .and_then(|v| v.as_i64()) + .map(|v| v as i32), duration_ms: value.get("durationMs").and_then(|v| v.as_f64()), - error_kind: value.get("errorKind").and_then(|v| v.as_str()).map(|s| s.to_string()), - telemetry: value.get("telemetry").cloned().unwrap_or(serde_json::Value::Null), - redaction: value.get("redaction").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| RedactionMetadata::load_from_value(v, ctx)), + error_kind: value + .get("errorKind") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + telemetry: value + .get("telemetry") + .cloned() + .unwrap_or(serde_json::Value::Null), + redaction: value + .get("redaction") + .filter(|v| v.is_object() || v.is_array() || v.is_string()) + .map(|v| RedactionMetadata::load_from_value(v, ctx)), } } @@ -75,26 +107,46 @@ impl ToolExecutionCompletePayload { let mut result = serde_json::Map::new(); // Write base fields if let Some(ref val) = self.request_id { - result.insert("requestId".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "requestId".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(ref val) = self.tool_call_id { - result.insert("toolCallId".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "toolCallId".to_string(), + serde_json::Value::String(val.clone()), + ); } if !self.tool_name.is_empty() { - result.insert("toolName".to_string(), serde_json::Value::String(self.tool_name.clone())); + result.insert( + "toolName".to_string(), + serde_json::Value::String(self.tool_name.clone()), + ); } result.insert("success".to_string(), serde_json::Value::Bool(self.success)); if let Some(ref val) = self.result { result.insert("result".to_string(), val.clone()); } if let Some(val) = self.exit_code { - result.insert("exitCode".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + result.insert( + "exitCode".to_string(), + serde_json::Value::Number(serde_json::Number::from(val)), + ); } if let Some(val) = self.duration_ms { - result.insert("durationMs".to_string(), serde_json::Number::from_f64(val as f64).map(serde_json::Value::Number).unwrap_or(serde_json::Value::Null)); + result.insert( + "durationMs".to_string(), + serde_json::Number::from_f64(val as f64) + .map(serde_json::Value::Number) + .unwrap_or(serde_json::Value::Null), + ); } if let Some(ref val) = self.error_kind { - result.insert("errorKind".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "errorKind".to_string(), + serde_json::Value::String(val.clone()), + ); } if !self.telemetry.is_null() { result.insert("telemetry".to_string(), self.telemetry.clone()); @@ -122,5 +174,4 @@ impl ToolExecutionCompletePayload { pub fn as_telemetry_dict(&self) -> Option<&serde_json::Map> { self.telemetry.as_object() } - } diff --git a/runtime/rust/prompty/src/model/events/tool_execution_start_payload.rs b/runtime/rust/prompty/src/model/events/tool_execution_start_payload.rs index 6458188a..b37e3194 100644 --- a/runtime/rust/prompty/src/model/events/tool_execution_start_payload.rs +++ b/runtime/rust/prompty/src/model/events/tool_execution_start_payload.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -47,12 +54,31 @@ impl ToolExecutionStartPayload { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - request_id: value.get("requestId").and_then(|v| v.as_str()).map(|s| s.to_string()), - tool_call_id: value.get("toolCallId").and_then(|v| v.as_str()).map(|s| s.to_string()), - tool_name: value.get("toolName").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - arguments: value.get("arguments").cloned().unwrap_or(serde_json::Value::Null), - working_directory: value.get("workingDirectory").and_then(|v| v.as_str()).map(|s| s.to_string()), - redaction: value.get("redaction").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| RedactionMetadata::load_from_value(v, ctx)), + request_id: value + .get("requestId") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + tool_call_id: value + .get("toolCallId") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + tool_name: value + .get("toolName") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + arguments: value + .get("arguments") + .cloned() + .unwrap_or(serde_json::Value::Null), + working_directory: value + .get("workingDirectory") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + redaction: value + .get("redaction") + .filter(|v| v.is_object() || v.is_array() || v.is_string()) + .map(|v| RedactionMetadata::load_from_value(v, ctx)), } } @@ -63,19 +89,31 @@ impl ToolExecutionStartPayload { let mut result = serde_json::Map::new(); // Write base fields if let Some(ref val) = self.request_id { - result.insert("requestId".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "requestId".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(ref val) = self.tool_call_id { - result.insert("toolCallId".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "toolCallId".to_string(), + serde_json::Value::String(val.clone()), + ); } if !self.tool_name.is_empty() { - result.insert("toolName".to_string(), serde_json::Value::String(self.tool_name.clone())); + result.insert( + "toolName".to_string(), + serde_json::Value::String(self.tool_name.clone()), + ); } if !self.arguments.is_null() { result.insert("arguments".to_string(), self.arguments.clone()); } if let Some(ref val) = self.working_directory { - result.insert("workingDirectory".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "workingDirectory".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(ref val) = self.redaction { let nested = val.to_value(ctx); @@ -100,5 +138,4 @@ impl ToolExecutionStartPayload { pub fn as_arguments_dict(&self) -> Option<&serde_json::Map> { self.arguments.as_object() } - } diff --git a/runtime/rust/prompty/src/model/events/tool_result_payload.rs b/runtime/rust/prompty/src/model/events/tool_result_payload.rs index b91fd1bb..ebc4a6dc 100644 --- a/runtime/rust/prompty/src/model/events/tool_result_payload.rs +++ b/runtime/rust/prompty/src/model/events/tool_result_payload.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -39,8 +46,16 @@ impl ToolResultPayload { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - name: value.get("name").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - result: value.get("result").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| ToolResult::load_from_value(v, ctx)).unwrap_or_default(), + name: value + .get("name") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + result: value + .get("result") + .filter(|v| v.is_object() || v.is_array() || v.is_string()) + .map(|v| ToolResult::load_from_value(v, ctx)) + .unwrap_or_default(), } } @@ -51,7 +66,10 @@ impl ToolResultPayload { let mut result = serde_json::Map::new(); // Write base fields if !self.name.is_empty() { - result.insert("name".to_string(), serde_json::Value::String(self.name.clone())); + result.insert( + "name".to_string(), + serde_json::Value::String(self.name.clone()), + ); } { let nested = self.result.to_value(ctx); diff --git a/runtime/rust/prompty/src/model/events/trajectory_event.rs b/runtime/rust/prompty/src/model/events/trajectory_event.rs index 0af08b52..1fc69d4c 100644 --- a/runtime/rust/prompty/src/model/events/trajectory_event.rs +++ b/runtime/rust/prompty/src/model/events/trajectory_event.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -53,15 +60,43 @@ impl TrajectoryEvent { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - id: value.get("id").and_then(|v| v.as_str()).map(|s| s.to_string()), - session_id: value.get("sessionId").and_then(|v| v.as_str()).map(|s| s.to_string()), - turn_id: value.get("turnId").and_then(|v| v.as_str()).map(|s| s.to_string()), - tool_call_id: value.get("toolCallId").and_then(|v| v.as_str()).map(|s| s.to_string()), - turn_index: value.get("turnIndex").and_then(|v| v.as_i64()).map(|v| v as i32), - event_type: value.get("eventType").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - data: value.get("data").cloned().unwrap_or(serde_json::Value::Null), - created_at: value.get("createdAt").and_then(|v| v.as_str()).map(|s| s.to_string()), - redaction: value.get("redaction").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| RedactionMetadata::load_from_value(v, ctx)), + id: value + .get("id") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + session_id: value + .get("sessionId") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + turn_id: value + .get("turnId") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + tool_call_id: value + .get("toolCallId") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + turn_index: value + .get("turnIndex") + .and_then(|v| v.as_i64()) + .map(|v| v as i32), + event_type: value + .get("eventType") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + data: value + .get("data") + .cloned() + .unwrap_or(serde_json::Value::Null), + created_at: value + .get("createdAt") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + redaction: value + .get("redaction") + .filter(|v| v.is_object() || v.is_array() || v.is_string()) + .map(|v| RedactionMetadata::load_from_value(v, ctx)), } } @@ -75,25 +110,40 @@ impl TrajectoryEvent { result.insert("id".to_string(), serde_json::Value::String(val.clone())); } if let Some(ref val) = self.session_id { - result.insert("sessionId".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "sessionId".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(ref val) = self.turn_id { result.insert("turnId".to_string(), serde_json::Value::String(val.clone())); } if let Some(ref val) = self.tool_call_id { - result.insert("toolCallId".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "toolCallId".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(val) = self.turn_index { - result.insert("turnIndex".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + result.insert( + "turnIndex".to_string(), + serde_json::Value::Number(serde_json::Number::from(val)), + ); } if !self.event_type.is_empty() { - result.insert("eventType".to_string(), serde_json::Value::String(self.event_type.clone())); + result.insert( + "eventType".to_string(), + serde_json::Value::String(self.event_type.clone()), + ); } if !self.data.is_null() { result.insert("data".to_string(), self.data.clone()); } if let Some(ref val) = self.created_at { - result.insert("createdAt".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "createdAt".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(ref val) = self.redaction { let nested = val.to_value(ctx); @@ -118,5 +168,4 @@ impl TrajectoryEvent { pub fn as_data_dict(&self) -> Option<&serde_json::Map> { self.data.as_object() } - } diff --git a/runtime/rust/prompty/src/model/events/turn_end_payload.rs b/runtime/rust/prompty/src/model/events/turn_end_payload.rs index 1bd23791..97dceb42 100644 --- a/runtime/rust/prompty/src/model/events/turn_end_payload.rs +++ b/runtime/rust/prompty/src/model/events/turn_end_payload.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -83,8 +90,14 @@ impl TurnEndPayload { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - iterations: value.get("iterations").and_then(|v| v.as_i64()).map(|v| v as i32), - status: value.get("status").and_then(|v| v.as_str()).and_then(|s| TurnStatus::from_str_opt(s)), + iterations: value + .get("iterations") + .and_then(|v| v.as_i64()) + .map(|v| v as i32), + status: value + .get("status") + .and_then(|v| v.as_str()) + .and_then(|s| TurnStatus::from_str_opt(s)), response: value.get("response").cloned(), duration_ms: value.get("durationMs").and_then(|v| v.as_f64()), } @@ -97,16 +110,27 @@ impl TurnEndPayload { let mut result = serde_json::Map::new(); // Write base fields if let Some(val) = self.iterations { - result.insert("iterations".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + result.insert( + "iterations".to_string(), + serde_json::Value::Number(serde_json::Number::from(val)), + ); } if let Some(ref val) = self.status { - result.insert("status".to_string(), serde_json::Value::String(val.to_string())); + result.insert( + "status".to_string(), + serde_json::Value::String(val.to_string()), + ); } if let Some(ref val) = self.response { result.insert("response".to_string(), val.clone()); } if let Some(val) = self.duration_ms { - result.insert("durationMs".to_string(), serde_json::Number::from_f64(val as f64).map(serde_json::Value::Number).unwrap_or(serde_json::Value::Null)); + result.insert( + "durationMs".to_string(), + serde_json::Number::from_f64(val as f64) + .map(serde_json::Value::Number) + .unwrap_or(serde_json::Value::Null), + ); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/events/turn_event.rs b/runtime/rust/prompty/src/model/events/turn_event.rs index 266d8531..b633cd71 100644 --- a/runtime/rust/prompty/src/model/events/turn_event.rs +++ b/runtime/rust/prompty/src/model/events/turn_event.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -175,14 +182,41 @@ impl TurnEvent { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - id: value.get("id").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - r#type: value.get("type").and_then(|v| v.as_str()).and_then(|s| TurnEventType::from_str_opt(s)).unwrap_or(TurnEventType::Turn_start), - timestamp: value.get("timestamp").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - turn_id: value.get("turnId").and_then(|v| v.as_str()).map(|s| s.to_string()), - iteration: value.get("iteration").and_then(|v| v.as_i64()).map(|v| v as i32), - parent_id: value.get("parentId").and_then(|v| v.as_str()).map(|s| s.to_string()), - span_id: value.get("spanId").and_then(|v| v.as_str()).map(|s| s.to_string()), - payload: value.get("payload").cloned().unwrap_or(serde_json::Value::Null), + id: value + .get("id") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + r#type: value + .get("type") + .and_then(|v| v.as_str()) + .and_then(|s| TurnEventType::from_str_opt(s)) + .unwrap_or(TurnEventType::Turn_start), + timestamp: value + .get("timestamp") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + turn_id: value + .get("turnId") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + iteration: value + .get("iteration") + .and_then(|v| v.as_i64()) + .map(|v| v as i32), + parent_id: value + .get("parentId") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + span_id: value + .get("spanId") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + payload: value + .get("payload") + .cloned() + .unwrap_or(serde_json::Value::Null), } } @@ -195,18 +229,30 @@ impl TurnEvent { if !self.id.is_empty() { result.insert("id".to_string(), serde_json::Value::String(self.id.clone())); } - result.insert("type".to_string(), serde_json::Value::String(self.r#type.to_string())); + result.insert( + "type".to_string(), + serde_json::Value::String(self.r#type.to_string()), + ); if !self.timestamp.is_empty() { - result.insert("timestamp".to_string(), serde_json::Value::String(self.timestamp.clone())); + result.insert( + "timestamp".to_string(), + serde_json::Value::String(self.timestamp.clone()), + ); } if let Some(ref val) = self.turn_id { result.insert("turnId".to_string(), serde_json::Value::String(val.clone())); } if let Some(val) = self.iteration { - result.insert("iteration".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + result.insert( + "iteration".to_string(), + serde_json::Value::Number(serde_json::Number::from(val)), + ); } if let Some(ref val) = self.parent_id { - result.insert("parentId".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "parentId".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(ref val) = self.span_id { result.insert("spanId".to_string(), serde_json::Value::String(val.clone())); @@ -231,5 +277,4 @@ impl TurnEvent { pub fn as_payload_dict(&self) -> Option<&serde_json::Map> { self.payload.as_object() } - } diff --git a/runtime/rust/prompty/src/model/events/turn_start_payload.rs b/runtime/rust/prompty/src/model/events/turn_start_payload.rs index 019bd1af..1db23a53 100644 --- a/runtime/rust/prompty/src/model/events/turn_start_payload.rs +++ b/runtime/rust/prompty/src/model/events/turn_start_payload.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -39,9 +46,18 @@ impl TurnStartPayload { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - agent: value.get("agent").and_then(|v| v.as_str()).map(|s| s.to_string()), - inputs: value.get("inputs").cloned().unwrap_or(serde_json::Value::Null), - max_iterations: value.get("maxIterations").and_then(|v| v.as_i64()).map(|v| v as i32), + agent: value + .get("agent") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + inputs: value + .get("inputs") + .cloned() + .unwrap_or(serde_json::Value::Null), + max_iterations: value + .get("maxIterations") + .and_then(|v| v.as_i64()) + .map(|v| v as i32), } } @@ -58,7 +74,10 @@ impl TurnStartPayload { result.insert("inputs".to_string(), self.inputs.clone()); } if let Some(val) = self.max_iterations { - result.insert("maxIterations".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + result.insert( + "maxIterations".to_string(), + serde_json::Value::Number(serde_json::Number::from(val)), + ); } ctx.process_dict(serde_json::Value::Object(result)) } @@ -77,5 +96,4 @@ impl TurnStartPayload { pub fn as_inputs_dict(&self) -> Option<&serde_json::Map> { self.inputs.as_object() } - } diff --git a/runtime/rust/prompty/src/model/events/turn_summary.rs b/runtime/rust/prompty/src/model/events/turn_summary.rs index cbde60df..176f3c83 100644 --- a/runtime/rust/prompty/src/model/events/turn_summary.rs +++ b/runtime/rust/prompty/src/model/events/turn_summary.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -51,13 +58,36 @@ impl TurnSummary { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - turn_id: value.get("turnId").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - status: value.get("status").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - iterations: value.get("iterations").and_then(|v| v.as_i64()).unwrap_or(0) as i32, - llm_calls: value.get("llmCalls").and_then(|v| v.as_i64()).map(|v| v as i32), - tool_calls: value.get("toolCalls").and_then(|v| v.as_i64()).map(|v| v as i32), - retries: value.get("retries").and_then(|v| v.as_i64()).map(|v| v as i32), - usage: value.get("usage").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| TokenUsage::load_from_value(v, ctx)), + turn_id: value + .get("turnId") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + status: value + .get("status") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + iterations: value + .get("iterations") + .and_then(|v| v.as_i64()) + .unwrap_or(0) as i32, + llm_calls: value + .get("llmCalls") + .and_then(|v| v.as_i64()) + .map(|v| v as i32), + tool_calls: value + .get("toolCalls") + .and_then(|v| v.as_i64()) + .map(|v| v as i32), + retries: value + .get("retries") + .and_then(|v| v.as_i64()) + .map(|v| v as i32), + usage: value + .get("usage") + .filter(|v| v.is_object() || v.is_array() || v.is_string()) + .map(|v| TokenUsage::load_from_value(v, ctx)), duration_ms: value.get("durationMs").and_then(|v| v.as_f64()), } } @@ -69,22 +99,40 @@ impl TurnSummary { let mut result = serde_json::Map::new(); // Write base fields if !self.turn_id.is_empty() { - result.insert("turnId".to_string(), serde_json::Value::String(self.turn_id.clone())); + result.insert( + "turnId".to_string(), + serde_json::Value::String(self.turn_id.clone()), + ); } if !self.status.is_empty() { - result.insert("status".to_string(), serde_json::Value::String(self.status.clone())); + result.insert( + "status".to_string(), + serde_json::Value::String(self.status.clone()), + ); } if self.iterations != 0 { - result.insert("iterations".to_string(), serde_json::Value::Number(serde_json::Number::from(self.iterations))); + result.insert( + "iterations".to_string(), + serde_json::Value::Number(serde_json::Number::from(self.iterations)), + ); } if let Some(val) = self.llm_calls { - result.insert("llmCalls".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + result.insert( + "llmCalls".to_string(), + serde_json::Value::Number(serde_json::Number::from(val)), + ); } if let Some(val) = self.tool_calls { - result.insert("toolCalls".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + result.insert( + "toolCalls".to_string(), + serde_json::Value::Number(serde_json::Number::from(val)), + ); } if let Some(val) = self.retries { - result.insert("retries".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + result.insert( + "retries".to_string(), + serde_json::Value::Number(serde_json::Number::from(val)), + ); } if let Some(ref val) = self.usage { let nested = val.to_value(ctx); @@ -93,7 +141,12 @@ impl TurnSummary { } } if let Some(val) = self.duration_ms { - result.insert("durationMs".to_string(), serde_json::Number::from_f64(val as f64).map(serde_json::Value::Number).unwrap_or(serde_json::Value::Null)); + result.insert( + "durationMs".to_string(), + serde_json::Number::from_f64(val as f64) + .map(serde_json::Value::Number) + .unwrap_or(serde_json::Value::Null), + ); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/events/turn_trace.rs b/runtime/rust/prompty/src/model/events/turn_trace.rs index 7e4cfdff..261d8d49 100644 --- a/runtime/rust/prompty/src/model/events/turn_trace.rs +++ b/runtime/rust/prompty/src/model/events/turn_trace.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -47,11 +54,27 @@ impl TurnTrace { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - version: value.get("version").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - runtime: value.get("runtime").and_then(|v| v.as_str()).map(|s| s.to_string()), - prompty_version: value.get("promptyVersion").and_then(|v| v.as_str()).map(|s| s.to_string()), - events: value.get("events").map(|v| Self::load_events(v, ctx)).unwrap_or_default(), - summary: value.get("summary").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| TurnSummary::load_from_value(v, ctx)), + version: value + .get("version") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + runtime: value + .get("runtime") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + prompty_version: value + .get("promptyVersion") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + events: value + .get("events") + .map(|v| Self::load_events(v, ctx)) + .unwrap_or_default(), + summary: value + .get("summary") + .filter(|v| v.is_object() || v.is_array() || v.is_string()) + .map(|v| TurnSummary::load_from_value(v, ctx)), } } @@ -62,13 +85,22 @@ impl TurnTrace { let mut result = serde_json::Map::new(); // Write base fields if !self.version.is_empty() { - result.insert("version".to_string(), serde_json::Value::String(self.version.clone())); + result.insert( + "version".to_string(), + serde_json::Value::String(self.version.clone()), + ); } if let Some(ref val) = self.runtime { - result.insert("runtime".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "runtime".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(ref val) = self.prompty_version { - result.insert("promptyVersion".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "promptyVersion".to_string(), + serde_json::Value::String(val.clone()), + ); } if !self.events.is_empty() { result.insert("events".to_string(), Self::save_events(&self.events, ctx)); @@ -96,19 +128,22 @@ impl TurnTrace { /// Handles both array format `[{...}]`. fn load_events(data: &serde_json::Value, ctx: &LoadContext) -> Vec { match data { - serde_json::Value::Array(arr) => { - arr.iter().map(|v| TurnEvent::load_from_value(v, ctx)).collect() - } + serde_json::Value::Array(arr) => arr + .iter() + .map(|v| TurnEvent::load_from_value(v, ctx)) + .collect(), _ => Vec::new(), - } } /// Save a collection of TurnEvent to a JSON value. fn save_events(items: &[TurnEvent], ctx: &SaveContext) -> serde_json::Value { - - serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()) - + serde_json::Value::Array( + items + .iter() + .map(|item| item.to_value(ctx)) + .collect::>(), + ) } } diff --git a/runtime/rust/prompty/src/model/mod.rs b/runtime/rust/prompty/src/model/mod.rs index af91b666..1420aa28 100644 --- a/runtime/rust/prompty/src/model/mod.rs +++ b/runtime/rust/prompty/src/model/mod.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. - -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +// +// Code generated by Typra emitter; DO NOT EDIT. + +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] pub mod context; pub use context::*; diff --git a/runtime/rust/prompty/src/model/model/mod.rs b/runtime/rust/prompty/src/model/model/mod.rs index e0e6fe59..c3210380 100644 --- a/runtime/rust/prompty/src/model/model/mod.rs +++ b/runtime/rust/prompty/src/model/model/mod.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] pub mod model_options; pub use model_options::*; diff --git a/runtime/rust/prompty/src/model/model/model.rs b/runtime/rust/prompty/src/model/model/model.rs index e90286f9..e12c63ab 100644 --- a/runtime/rust/prompty/src/model/model/model.rs +++ b/runtime/rust/prompty/src/model/model/model.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -98,14 +105,33 @@ impl Model { let value = ctx.process_input(value.clone()); if let Some(s) = value.as_str() { let value = s.to_string(); - return Model { id: value.into(), ..Default::default() }; + return Model { + id: value.into(), + ..Default::default() + }; } Self { - id: value.get("id").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - provider: value.get("provider").and_then(|v| v.as_str()).map(|s| s.to_string()), - api_type: value.get("apiType").and_then(|v| v.as_str()).and_then(|s| apiType::from_str_opt(s)), - connection: value.get("connection").cloned().unwrap_or(serde_json::Value::Null), - options: value.get("options").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| ModelOptions::load_from_value(v, ctx)), + id: value + .get("id") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + provider: value + .get("provider") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + api_type: value + .get("apiType") + .and_then(|v| v.as_str()) + .and_then(|s| apiType::from_str_opt(s)), + connection: value + .get("connection") + .cloned() + .unwrap_or(serde_json::Value::Null), + options: value + .get("options") + .filter(|v| v.is_object() || v.is_array() || v.is_string()) + .map(|v| ModelOptions::load_from_value(v, ctx)), } } @@ -119,10 +145,16 @@ impl Model { result.insert("id".to_string(), serde_json::Value::String(self.id.clone())); } if let Some(ref val) = self.provider { - result.insert("provider".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "provider".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(ref val) = self.api_type { - result.insert("apiType".to_string(), serde_json::Value::String(val.to_string())); + result.insert( + "apiType".to_string(), + serde_json::Value::String(val.to_string()), + ); } if !self.connection.is_null() { result.insert("connection".to_string(), self.connection.clone()); diff --git a/runtime/rust/prompty/src/model/model/model_info.rs b/runtime/rust/prompty/src/model/model/model_info.rs index 291abc9a..d3a0ab37 100644 --- a/runtime/rust/prompty/src/model/model/model_info.rs +++ b/runtime/rust/prompty/src/model/model/model_info.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -47,13 +54,43 @@ impl ModelInfo { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - id: value.get("id").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - display_name: value.get("displayName").and_then(|v| v.as_str()).map(|s| s.to_string()), - owned_by: value.get("ownedBy").and_then(|v| v.as_str()).map(|s| s.to_string()), - context_window: value.get("contextWindow").and_then(|v| v.as_i64()).map(|v| v as i32), - input_modalities: value.get("inputModalities").and_then(|v| v.as_array()).map(|arr| arr.iter().filter_map(|v| v.as_str().map(|s| s.to_string())).collect()), - output_modalities: value.get("outputModalities").and_then(|v| v.as_array()).map(|arr| arr.iter().filter_map(|v| v.as_str().map(|s| s.to_string())).collect()), - additional_properties: value.get("additionalProperties").cloned().unwrap_or(serde_json::Value::Null), + id: value + .get("id") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + display_name: value + .get("displayName") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + owned_by: value + .get("ownedBy") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + context_window: value + .get("contextWindow") + .and_then(|v| v.as_i64()) + .map(|v| v as i32), + input_modalities: value + .get("inputModalities") + .and_then(|v| v.as_array()) + .map(|arr| { + arr.iter() + .filter_map(|v| v.as_str().map(|s| s.to_string())) + .collect() + }), + output_modalities: value + .get("outputModalities") + .and_then(|v| v.as_array()) + .map(|arr| { + arr.iter() + .filter_map(|v| v.as_str().map(|s| s.to_string())) + .collect() + }), + additional_properties: value + .get("additionalProperties") + .cloned() + .unwrap_or(serde_json::Value::Null), } } @@ -67,22 +104,40 @@ impl ModelInfo { result.insert("id".to_string(), serde_json::Value::String(self.id.clone())); } if let Some(ref val) = self.display_name { - result.insert("displayName".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "displayName".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(ref val) = self.owned_by { - result.insert("ownedBy".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "ownedBy".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(val) = self.context_window { - result.insert("contextWindow".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + result.insert( + "contextWindow".to_string(), + serde_json::Value::Number(serde_json::Number::from(val)), + ); } if let Some(ref items) = self.input_modalities { - result.insert("inputModalities".to_string(), serde_json::to_value(items).unwrap_or(serde_json::Value::Null)); + result.insert( + "inputModalities".to_string(), + serde_json::to_value(items).unwrap_or(serde_json::Value::Null), + ); } if let Some(ref items) = self.output_modalities { - result.insert("outputModalities".to_string(), serde_json::to_value(items).unwrap_or(serde_json::Value::Null)); + result.insert( + "outputModalities".to_string(), + serde_json::to_value(items).unwrap_or(serde_json::Value::Null), + ); } if !self.additional_properties.is_null() { - result.insert("additionalProperties".to_string(), self.additional_properties.clone()); + result.insert( + "additionalProperties".to_string(), + self.additional_properties.clone(), + ); } ctx.process_dict(serde_json::Value::Object(result)) } @@ -98,8 +153,9 @@ impl ModelInfo { } /// Returns typed reference to the map if the field is an object. /// Returns `None` if the field is null or not an object. - pub fn as_additional_properties_dict(&self) -> Option<&serde_json::Map> { + pub fn as_additional_properties_dict( + &self, + ) -> Option<&serde_json::Map> { self.additional_properties.as_object() } - } diff --git a/runtime/rust/prompty/src/model/model/model_options.rs b/runtime/rust/prompty/src/model/model/model_options.rs index 2ec4ca0f..03ac772a 100644 --- a/runtime/rust/prompty/src/model/model/model_options.rs +++ b/runtime/rust/prompty/src/model/model/model_options.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -54,16 +61,40 @@ impl ModelOptions { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - frequency_penalty: value.get("frequencyPenalty").and_then(|v| v.as_f64()).map(|v| v as f32), - max_output_tokens: value.get("maxOutputTokens").and_then(|v| v.as_i64()).map(|v| v as i32), - presence_penalty: value.get("presencePenalty").and_then(|v| v.as_f64()).map(|v| v as f32), + frequency_penalty: value + .get("frequencyPenalty") + .and_then(|v| v.as_f64()) + .map(|v| v as f32), + max_output_tokens: value + .get("maxOutputTokens") + .and_then(|v| v.as_i64()) + .map(|v| v as i32), + presence_penalty: value + .get("presencePenalty") + .and_then(|v| v.as_f64()) + .map(|v| v as f32), seed: value.get("seed").and_then(|v| v.as_i64()).map(|v| v as i32), - temperature: value.get("temperature").and_then(|v| v.as_f64()).map(|v| v as f32), + temperature: value + .get("temperature") + .and_then(|v| v.as_f64()) + .map(|v| v as f32), top_k: value.get("topK").and_then(|v| v.as_i64()).map(|v| v as i32), top_p: value.get("topP").and_then(|v| v.as_f64()).map(|v| v as f32), - stop_sequences: value.get("stopSequences").and_then(|v| v.as_array()).map(|arr| arr.iter().filter_map(|v| v.as_str().map(|s| s.to_string())).collect()), - allow_multiple_tool_calls: value.get("allowMultipleToolCalls").and_then(|v| v.as_bool()), - additional_properties: value.get("additionalProperties").cloned().unwrap_or(serde_json::Value::Null), + stop_sequences: value + .get("stopSequences") + .and_then(|v| v.as_array()) + .map(|arr| { + arr.iter() + .filter_map(|v| v.as_str().map(|s| s.to_string())) + .collect() + }), + allow_multiple_tool_calls: value + .get("allowMultipleToolCalls") + .and_then(|v| v.as_bool()), + additional_properties: value + .get("additionalProperties") + .cloned() + .unwrap_or(serde_json::Value::Null), } } @@ -74,34 +105,72 @@ impl ModelOptions { let mut result = serde_json::Map::new(); // Write base fields if let Some(val) = self.frequency_penalty { - result.insert("frequencyPenalty".to_string(), serde_json::Number::from_f64(val as f64).map(serde_json::Value::Number).unwrap_or(serde_json::Value::Null)); + result.insert( + "frequencyPenalty".to_string(), + serde_json::Number::from_f64(val as f64) + .map(serde_json::Value::Number) + .unwrap_or(serde_json::Value::Null), + ); } if let Some(val) = self.max_output_tokens { - result.insert("maxOutputTokens".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + result.insert( + "maxOutputTokens".to_string(), + serde_json::Value::Number(serde_json::Number::from(val)), + ); } if let Some(val) = self.presence_penalty { - result.insert("presencePenalty".to_string(), serde_json::Number::from_f64(val as f64).map(serde_json::Value::Number).unwrap_or(serde_json::Value::Null)); + result.insert( + "presencePenalty".to_string(), + serde_json::Number::from_f64(val as f64) + .map(serde_json::Value::Number) + .unwrap_or(serde_json::Value::Null), + ); } if let Some(val) = self.seed { - result.insert("seed".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + result.insert( + "seed".to_string(), + serde_json::Value::Number(serde_json::Number::from(val)), + ); } if let Some(val) = self.temperature { - result.insert("temperature".to_string(), serde_json::Number::from_f64(val as f64).map(serde_json::Value::Number).unwrap_or(serde_json::Value::Null)); + result.insert( + "temperature".to_string(), + serde_json::Number::from_f64(val as f64) + .map(serde_json::Value::Number) + .unwrap_or(serde_json::Value::Null), + ); } if let Some(val) = self.top_k { - result.insert("topK".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + result.insert( + "topK".to_string(), + serde_json::Value::Number(serde_json::Number::from(val)), + ); } if let Some(val) = self.top_p { - result.insert("topP".to_string(), serde_json::Number::from_f64(val as f64).map(serde_json::Value::Number).unwrap_or(serde_json::Value::Null)); + result.insert( + "topP".to_string(), + serde_json::Number::from_f64(val as f64) + .map(serde_json::Value::Number) + .unwrap_or(serde_json::Value::Null), + ); } if let Some(ref items) = self.stop_sequences { - result.insert("stopSequences".to_string(), serde_json::to_value(items).unwrap_or(serde_json::Value::Null)); + result.insert( + "stopSequences".to_string(), + serde_json::to_value(items).unwrap_or(serde_json::Value::Null), + ); } if let Some(val) = self.allow_multiple_tool_calls { - result.insert("allowMultipleToolCalls".to_string(), serde_json::Value::Bool(val)); + result.insert( + "allowMultipleToolCalls".to_string(), + serde_json::Value::Bool(val), + ); } if !self.additional_properties.is_null() { - result.insert("additionalProperties".to_string(), self.additional_properties.clone()); + result.insert( + "additionalProperties".to_string(), + self.additional_properties.clone(), + ); } ctx.process_dict(serde_json::Value::Object(result)) } @@ -120,17 +189,60 @@ impl ModelOptions { pub fn to_wire(&self, provider: &str) -> serde_json::Value { let data = serde_json::to_value(self).unwrap_or_default(); let mut result = serde_json::Map::new(); - let wire_map: std::collections::HashMap<&str, std::collections::HashMap<&str, &str>> = std::collections::HashMap::from([ - ("frequencyPenalty", std::collections::HashMap::from([("openai", "frequency_penalty")])), - ("maxOutputTokens", std::collections::HashMap::from([("openai", "max_completion_tokens"), ("responses", "max_output_tokens"), ("anthropic", "max_tokens")])), - ("presencePenalty", std::collections::HashMap::from([("openai", "presence_penalty")])), - ("seed", std::collections::HashMap::from([("openai", "seed")])), - ("temperature", std::collections::HashMap::from([("openai", "temperature"), ("responses", "temperature"), ("anthropic", "temperature")])), - ("topK", std::collections::HashMap::from([("openai", "top_k"), ("anthropic", "top_k")])), - ("topP", std::collections::HashMap::from([("openai", "top_p"), ("responses", "top_p"), ("anthropic", "top_p")])), - ("stopSequences", std::collections::HashMap::from([("openai", "stop"), ("anthropic", "stop_sequences")])), - ("allowMultipleToolCalls", std::collections::HashMap::from([("openai", "parallel_tool_calls")])), - ]); + let wire_map: std::collections::HashMap<&str, std::collections::HashMap<&str, &str>> = + std::collections::HashMap::from([ + ( + "frequencyPenalty", + std::collections::HashMap::from([("openai", "frequency_penalty")]), + ), + ( + "maxOutputTokens", + std::collections::HashMap::from([ + ("openai", "max_completion_tokens"), + ("responses", "max_output_tokens"), + ("anthropic", "max_tokens"), + ]), + ), + ( + "presencePenalty", + std::collections::HashMap::from([("openai", "presence_penalty")]), + ), + ( + "seed", + std::collections::HashMap::from([("openai", "seed")]), + ), + ( + "temperature", + std::collections::HashMap::from([ + ("openai", "temperature"), + ("responses", "temperature"), + ("anthropic", "temperature"), + ]), + ), + ( + "topK", + std::collections::HashMap::from([("openai", "top_k"), ("anthropic", "top_k")]), + ), + ( + "topP", + std::collections::HashMap::from([ + ("openai", "top_p"), + ("responses", "top_p"), + ("anthropic", "top_p"), + ]), + ), + ( + "stopSequences", + std::collections::HashMap::from([ + ("openai", "stop"), + ("anthropic", "stop_sequences"), + ]), + ), + ( + "allowMultipleToolCalls", + std::collections::HashMap::from([("openai", "parallel_tool_calls")]), + ), + ]); if let serde_json::Value::Object(map) = data { for (key, value) in map { if let Some(mapping) = wire_map.get(key.as_str()) { @@ -144,8 +256,9 @@ impl ModelOptions { } /// Returns typed reference to the map if the field is an object. /// Returns `None` if the field is null or not an object. - pub fn as_additional_properties_dict(&self) -> Option<&serde_json::Map> { + pub fn as_additional_properties_dict( + &self, + ) -> Option<&serde_json::Map> { self.additional_properties.as_object() } - } diff --git a/runtime/rust/prompty/src/model/model/token_usage.rs b/runtime/rust/prompty/src/model/model/token_usage.rs index 986626ee..08cdec33 100644 --- a/runtime/rust/prompty/src/model/model/token_usage.rs +++ b/runtime/rust/prompty/src/model/model/token_usage.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -40,9 +47,18 @@ impl TokenUsage { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - prompt_tokens: value.get("promptTokens").and_then(|v| v.as_i64()).map(|v| v as i32), - completion_tokens: value.get("completionTokens").and_then(|v| v.as_i64()).map(|v| v as i32), - total_tokens: value.get("totalTokens").and_then(|v| v.as_i64()).map(|v| v as i32), + prompt_tokens: value + .get("promptTokens") + .and_then(|v| v.as_i64()) + .map(|v| v as i32), + completion_tokens: value + .get("completionTokens") + .and_then(|v| v.as_i64()) + .map(|v| v as i32), + total_tokens: value + .get("totalTokens") + .and_then(|v| v.as_i64()) + .map(|v| v as i32), } } @@ -53,13 +69,22 @@ impl TokenUsage { let mut result = serde_json::Map::new(); // Write base fields if let Some(val) = self.prompt_tokens { - result.insert("promptTokens".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + result.insert( + "promptTokens".to_string(), + serde_json::Value::Number(serde_json::Number::from(val)), + ); } if let Some(val) = self.completion_tokens { - result.insert("completionTokens".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + result.insert( + "completionTokens".to_string(), + serde_json::Value::Number(serde_json::Number::from(val)), + ); } if let Some(val) = self.total_tokens { - result.insert("totalTokens".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + result.insert( + "totalTokens".to_string(), + serde_json::Value::Number(serde_json::Number::from(val)), + ); } ctx.process_dict(serde_json::Value::Object(result)) } @@ -78,11 +103,27 @@ impl TokenUsage { pub fn to_wire(&self, provider: &str) -> serde_json::Value { let data = serde_json::to_value(self).unwrap_or_default(); let mut result = serde_json::Map::new(); - let wire_map: std::collections::HashMap<&str, std::collections::HashMap<&str, &str>> = std::collections::HashMap::from([ - ("promptTokens", std::collections::HashMap::from([("openai", "prompt_tokens"), ("anthropic", "input_tokens")])), - ("completionTokens", std::collections::HashMap::from([("openai", "completion_tokens"), ("anthropic", "output_tokens")])), - ("totalTokens", std::collections::HashMap::from([("openai", "total_tokens")])), - ]); + let wire_map: std::collections::HashMap<&str, std::collections::HashMap<&str, &str>> = + std::collections::HashMap::from([ + ( + "promptTokens", + std::collections::HashMap::from([ + ("openai", "prompt_tokens"), + ("anthropic", "input_tokens"), + ]), + ), + ( + "completionTokens", + std::collections::HashMap::from([ + ("openai", "completion_tokens"), + ("anthropic", "output_tokens"), + ]), + ), + ( + "totalTokens", + std::collections::HashMap::from([("openai", "total_tokens")]), + ), + ]); if let serde_json::Value::Object(map) = data { for (key, value) in map { if let Some(mapping) = wire_map.get(key.as_str()) { diff --git a/runtime/rust/prompty/src/model/pipeline/checkpoint_store.rs b/runtime/rust/prompty/src/model/pipeline/checkpoint_store.rs index 3c494b57..14946be0 100644 --- a/runtime/rust/prompty/src/model/pipeline/checkpoint_store.rs +++ b/runtime/rust/prompty/src/model/pipeline/checkpoint_store.rs @@ -1,7 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. - -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +// +// Code generated by Typra emitter; DO NOT EDIT. +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::events::checkpoint::Checkpoint; @@ -9,9 +15,19 @@ use super::super::events::checkpoint::Checkpoint; #[async_trait::async_trait] pub trait CheckpointStore: Send + Sync { /// Persist a session checkpoint and return the stored checkpoint - async fn save(&self, checkpoint: &Checkpoint) -> Result>; + async fn save( + &self, + checkpoint: &Checkpoint, + ) -> Result>; /// Load a checkpoint by session and checkpoint identifier - async fn load(&self, session_id: &String, checkpoint_id: &String) -> Result, Box>; + async fn load( + &self, + session_id: &String, + checkpoint_id: &String, + ) -> Result, Box>; /// List checkpoints for a session - async fn list_checkpoints(&self, session_id: &String) -> Result, Box>; + async fn list_checkpoints( + &self, + session_id: &String, + ) -> Result, Box>; } diff --git a/runtime/rust/prompty/src/model/pipeline/compaction_config.rs b/runtime/rust/prompty/src/model/pipeline/compaction_config.rs index ba3b2594..288c1d8f 100644 --- a/runtime/rust/prompty/src/model/pipeline/compaction_config.rs +++ b/runtime/rust/prompty/src/model/pipeline/compaction_config.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -39,9 +46,18 @@ impl CompactionConfig { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - strategy: value.get("strategy").and_then(|v| v.as_str()).map(|s| s.to_string()), - budget: value.get("budget").and_then(|v| v.as_i64()).map(|v| v as i32), - options: value.get("options").cloned().unwrap_or(serde_json::Value::Null), + strategy: value + .get("strategy") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + budget: value + .get("budget") + .and_then(|v| v.as_i64()) + .map(|v| v as i32), + options: value + .get("options") + .cloned() + .unwrap_or(serde_json::Value::Null), } } @@ -52,10 +68,16 @@ impl CompactionConfig { let mut result = serde_json::Map::new(); // Write base fields if let Some(ref val) = self.strategy { - result.insert("strategy".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "strategy".to_string(), + serde_json::Value::String(val.clone()), + ); } if let Some(val) = self.budget { - result.insert("budget".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + result.insert( + "budget".to_string(), + serde_json::Value::Number(serde_json::Number::from(val)), + ); } if !self.options.is_null() { result.insert("options".to_string(), self.options.clone()); @@ -77,5 +99,4 @@ impl CompactionConfig { pub fn as_options_dict(&self) -> Option<&serde_json::Map> { self.options.as_object() } - } diff --git a/runtime/rust/prompty/src/model/pipeline/event_journal_writer.rs b/runtime/rust/prompty/src/model/pipeline/event_journal_writer.rs index 823f2adc..1bb35ecb 100644 --- a/runtime/rust/prompty/src/model/pipeline/event_journal_writer.rs +++ b/runtime/rust/prompty/src/model/pipeline/event_journal_writer.rs @@ -1,7 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. - -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +// +// Code generated by Typra emitter; DO NOT EDIT. +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::events::session_event::SessionEvent; diff --git a/runtime/rust/prompty/src/model/pipeline/event_sink.rs b/runtime/rust/prompty/src/model/pipeline/event_sink.rs index 77646e7e..7b3d694e 100644 --- a/runtime/rust/prompty/src/model/pipeline/event_sink.rs +++ b/runtime/rust/prompty/src/model/pipeline/event_sink.rs @@ -1,7 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. - -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +// +// Code generated by Typra emitter; DO NOT EDIT. +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::events::session_event::SessionEvent; diff --git a/runtime/rust/prompty/src/model/pipeline/executor.rs b/runtime/rust/prompty/src/model/pipeline/executor.rs index e52c6999..de48cd8b 100644 --- a/runtime/rust/prompty/src/model/pipeline/executor.rs +++ b/runtime/rust/prompty/src/model/pipeline/executor.rs @@ -1,7 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. - -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +// +// Code generated by Typra emitter; DO NOT EDIT. +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::conversation::message::Message; @@ -13,11 +19,25 @@ use super::super::conversation::tool_call::ToolCall; #[async_trait::async_trait] pub trait Executor: Send + Sync { /// Call an LLM provider with messages and return the raw response - async fn execute(&self, agent: &Prompty, messages: &Vec) -> Result>; + async fn execute( + &self, + agent: &Prompty, + messages: &Vec, + ) -> Result>; /// Call an LLM provider and return a streaming response. Returns a language-specific async iterable/stream of raw chunks. Not all providers support streaming; the default implementation should signal lack of support. - async fn execute_stream(&self, agent: &Prompty, messages: &Vec) -> Result> { + async fn execute_stream( + &self, + agent: &Prompty, + messages: &Vec, + ) -> Result> { Err("not supported".into()) } /// Format tool call results into messages for the next iteration - fn format_tool_messages(&self, raw_response: &serde_json::Value, tool_calls: &Vec, tool_results: &Vec, text_content: &Option) -> Vec; + fn format_tool_messages( + &self, + raw_response: &serde_json::Value, + tool_calls: &Vec, + tool_results: &Vec, + text_content: &Option, + ) -> Vec; } diff --git a/runtime/rust/prompty/src/model/pipeline/host_tool_executor.rs b/runtime/rust/prompty/src/model/pipeline/host_tool_executor.rs index 5d72087a..73d49ec4 100644 --- a/runtime/rust/prompty/src/model/pipeline/host_tool_executor.rs +++ b/runtime/rust/prompty/src/model/pipeline/host_tool_executor.rs @@ -1,7 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. - -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +// +// Code generated by Typra emitter; DO NOT EDIT. +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::events::host_tool_request::HostToolRequest; @@ -11,5 +17,8 @@ use super::super::events::host_tool_result::HostToolResult; #[async_trait::async_trait] pub trait HostToolExecutor: Send + Sync { /// Execute a concrete host tool request and return its completion payload - async fn execute(&self, request: &HostToolRequest) -> Result>; + async fn execute( + &self, + request: &HostToolRequest, + ) -> Result>; } diff --git a/runtime/rust/prompty/src/model/pipeline/mod.rs b/runtime/rust/prompty/src/model/pipeline/mod.rs index ab94dce0..bb255f31 100644 --- a/runtime/rust/prompty/src/model/pipeline/mod.rs +++ b/runtime/rust/prompty/src/model/pipeline/mod.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. - -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +// +// Code generated by Typra emitter; DO NOT EDIT. + +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] pub mod compaction_config; pub use compaction_config::*; diff --git a/runtime/rust/prompty/src/model/pipeline/parser.rs b/runtime/rust/prompty/src/model/pipeline/parser.rs index 4158dfd5..9d72e205 100644 --- a/runtime/rust/prompty/src/model/pipeline/parser.rs +++ b/runtime/rust/prompty/src/model/pipeline/parser.rs @@ -1,7 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. - -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +// +// Code generated by Typra emitter; DO NOT EDIT. +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::conversation::message::Message; @@ -15,5 +21,10 @@ pub trait Parser: Send + Sync { None } /// Parse rendered text into a structured message array - async fn parse(&self, agent: &Prompty, rendered: &String, context: &Option) -> Result, Box>; + async fn parse( + &self, + agent: &Prompty, + rendered: &String, + context: &Option, + ) -> Result, Box>; } diff --git a/runtime/rust/prompty/src/model/pipeline/permission_resolver.rs b/runtime/rust/prompty/src/model/pipeline/permission_resolver.rs index 43aa3808..a1632afb 100644 --- a/runtime/rust/prompty/src/model/pipeline/permission_resolver.rs +++ b/runtime/rust/prompty/src/model/pipeline/permission_resolver.rs @@ -1,7 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. - -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +// +// Code generated by Typra emitter; DO NOT EDIT. +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::events::permission_decision::PermissionDecision; @@ -11,5 +17,8 @@ use super::super::events::permission_request::PermissionRequest; #[async_trait::async_trait] pub trait PermissionResolver: Send + Sync { /// Resolve a host permission request - async fn request(&self, request: &PermissionRequest) -> Result>; + async fn request( + &self, + request: &PermissionRequest, + ) -> Result>; } diff --git a/runtime/rust/prompty/src/model/pipeline/processor.rs b/runtime/rust/prompty/src/model/pipeline/processor.rs index 1dc21209..e24cba85 100644 --- a/runtime/rust/prompty/src/model/pipeline/processor.rs +++ b/runtime/rust/prompty/src/model/pipeline/processor.rs @@ -1,7 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. - -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +// +// Code generated by Typra emitter; DO NOT EDIT. +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::agent::prompty::Prompty; @@ -9,9 +15,16 @@ use super::super::agent::prompty::Prompty; #[async_trait::async_trait] pub trait Processor: Send + Sync { /// Extract a clean result from a raw LLM response - async fn process(&self, agent: &Prompty, response: &serde_json::Value) -> Result>; + async fn process( + &self, + agent: &Prompty, + response: &serde_json::Value, + ) -> Result>; /// Process a streaming response into a stream of StreamChunk items. Takes raw chunks from the executor and yields processed text, thinking, tool, or error chunks. Not all providers support streaming; the default implementation should signal lack of support. - async fn process_stream(&self, stream: &serde_json::Value) -> Result> { + async fn process_stream( + &self, + stream: &serde_json::Value, + ) -> Result> { Err("not supported".into()) } } diff --git a/runtime/rust/prompty/src/model/pipeline/renderer.rs b/runtime/rust/prompty/src/model/pipeline/renderer.rs index a4bfff80..4b033097 100644 --- a/runtime/rust/prompty/src/model/pipeline/renderer.rs +++ b/runtime/rust/prompty/src/model/pipeline/renderer.rs @@ -1,7 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. - -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +// +// Code generated by Typra emitter; DO NOT EDIT. +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::agent::prompty::Prompty; @@ -9,5 +15,10 @@ use super::super::agent::prompty::Prompty; #[async_trait::async_trait] pub trait Renderer: Send + Sync { /// Render the template string with input values - async fn render(&self, agent: &Prompty, template: &String, inputs: &serde_json::Value) -> Result>; + async fn render( + &self, + agent: &Prompty, + template: &String, + inputs: &serde_json::Value, + ) -> Result>; } diff --git a/runtime/rust/prompty/src/model/pipeline/turn_options.rs b/runtime/rust/prompty/src/model/pipeline/turn_options.rs index a26bbcde..3c8eed09 100644 --- a/runtime/rust/prompty/src/model/pipeline/turn_options.rs +++ b/runtime/rust/prompty/src/model/pipeline/turn_options.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -49,13 +56,25 @@ impl TurnOptions { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - max_iterations: value.get("maxIterations").and_then(|v| v.as_i64()).map(|v| v as i32), - max_llm_retries: value.get("maxLlmRetries").and_then(|v| v.as_i64()).map(|v| v as i32), - context_budget: value.get("contextBudget").and_then(|v| v.as_i64()).map(|v| v as i32), + max_iterations: value + .get("maxIterations") + .and_then(|v| v.as_i64()) + .map(|v| v as i32), + max_llm_retries: value + .get("maxLlmRetries") + .and_then(|v| v.as_i64()) + .map(|v| v as i32), + context_budget: value + .get("contextBudget") + .and_then(|v| v.as_i64()) + .map(|v| v as i32), parallel_tool_calls: value.get("parallelToolCalls").and_then(|v| v.as_bool()), raw: value.get("raw").and_then(|v| v.as_bool()), turn: value.get("turn").and_then(|v| v.as_i64()).map(|v| v as i32), - compaction: value.get("compaction").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| CompactionConfig::load_from_value(v, ctx)), + compaction: value + .get("compaction") + .filter(|v| v.is_object() || v.is_array() || v.is_string()) + .map(|v| CompactionConfig::load_from_value(v, ctx)), } } @@ -66,22 +85,37 @@ impl TurnOptions { let mut result = serde_json::Map::new(); // Write base fields if let Some(val) = self.max_iterations { - result.insert("maxIterations".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + result.insert( + "maxIterations".to_string(), + serde_json::Value::Number(serde_json::Number::from(val)), + ); } if let Some(val) = self.max_llm_retries { - result.insert("maxLlmRetries".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + result.insert( + "maxLlmRetries".to_string(), + serde_json::Value::Number(serde_json::Number::from(val)), + ); } if let Some(val) = self.context_budget { - result.insert("contextBudget".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + result.insert( + "contextBudget".to_string(), + serde_json::Value::Number(serde_json::Number::from(val)), + ); } if let Some(val) = self.parallel_tool_calls { - result.insert("parallelToolCalls".to_string(), serde_json::Value::Bool(val)); + result.insert( + "parallelToolCalls".to_string(), + serde_json::Value::Bool(val), + ); } if let Some(val) = self.raw { result.insert("raw".to_string(), serde_json::Value::Bool(val)); } if let Some(val) = self.turn { - result.insert("turn".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + result.insert( + "turn".to_string(), + serde_json::Value::Number(serde_json::Number::from(val)), + ); } if let Some(ref val) = self.compaction { let nested = val.to_value(ctx); diff --git a/runtime/rust/prompty/src/model/streaming/mod.rs b/runtime/rust/prompty/src/model/streaming/mod.rs index 7c6c11e4..9a49d672 100644 --- a/runtime/rust/prompty/src/model/streaming/mod.rs +++ b/runtime/rust/prompty/src/model/streaming/mod.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] pub mod stream_options; pub use stream_options::*; diff --git a/runtime/rust/prompty/src/model/streaming/stream_options.rs b/runtime/rust/prompty/src/model/streaming/stream_options.rs index 35329205..c829adf2 100644 --- a/runtime/rust/prompty/src/model/streaming/stream_options.rs +++ b/runtime/rust/prompty/src/model/streaming/stream_options.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; diff --git a/runtime/rust/prompty/src/model/template/format_config.rs b/runtime/rust/prompty/src/model/template/format_config.rs index 96674a07..9a18bbc8 100644 --- a/runtime/rust/prompty/src/model/template/format_config.rs +++ b/runtime/rust/prompty/src/model/template/format_config.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -40,12 +47,22 @@ impl FormatConfig { let value = ctx.process_input(value.clone()); if let Some(s) = value.as_str() { let value = s.to_string(); - return FormatConfig { kind: value.into(), ..Default::default() }; + return FormatConfig { + kind: value.into(), + ..Default::default() + }; } Self { - kind: value.get("kind").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + kind: value + .get("kind") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), strict: value.get("strict").and_then(|v| v.as_bool()), - options: value.get("options").cloned().unwrap_or(serde_json::Value::Null), + options: value + .get("options") + .cloned() + .unwrap_or(serde_json::Value::Null), } } @@ -56,7 +73,10 @@ impl FormatConfig { let mut result = serde_json::Map::new(); // Write base fields if !self.kind.is_empty() { - result.insert("kind".to_string(), serde_json::Value::String(self.kind.clone())); + result.insert( + "kind".to_string(), + serde_json::Value::String(self.kind.clone()), + ); } if let Some(val) = self.strict { result.insert("strict".to_string(), serde_json::Value::Bool(val)); @@ -81,5 +101,4 @@ impl FormatConfig { pub fn as_options_dict(&self) -> Option<&serde_json::Map> { self.options.as_object() } - } diff --git a/runtime/rust/prompty/src/model/template/mod.rs b/runtime/rust/prompty/src/model/template/mod.rs index dd0c9598..1ad857df 100644 --- a/runtime/rust/prompty/src/model/template/mod.rs +++ b/runtime/rust/prompty/src/model/template/mod.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] pub mod format_config; pub use format_config::*; diff --git a/runtime/rust/prompty/src/model/template/parser_config.rs b/runtime/rust/prompty/src/model/template/parser_config.rs index 1fe09579..0b10ae9d 100644 --- a/runtime/rust/prompty/src/model/template/parser_config.rs +++ b/runtime/rust/prompty/src/model/template/parser_config.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -38,11 +45,21 @@ impl ParserConfig { let value = ctx.process_input(value.clone()); if let Some(s) = value.as_str() { let value = s.to_string(); - return ParserConfig { kind: value.into(), ..Default::default() }; + return ParserConfig { + kind: value.into(), + ..Default::default() + }; } Self { - kind: value.get("kind").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - options: value.get("options").cloned().unwrap_or(serde_json::Value::Null), + kind: value + .get("kind") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + options: value + .get("options") + .cloned() + .unwrap_or(serde_json::Value::Null), } } @@ -53,7 +70,10 @@ impl ParserConfig { let mut result = serde_json::Map::new(); // Write base fields if !self.kind.is_empty() { - result.insert("kind".to_string(), serde_json::Value::String(self.kind.clone())); + result.insert( + "kind".to_string(), + serde_json::Value::String(self.kind.clone()), + ); } if !self.options.is_null() { result.insert("options".to_string(), self.options.clone()); @@ -75,5 +95,4 @@ impl ParserConfig { pub fn as_options_dict(&self) -> Option<&serde_json::Map> { self.options.as_object() } - } diff --git a/runtime/rust/prompty/src/model/template/template.rs b/runtime/rust/prompty/src/model/template/template.rs index 13354b81..f7c5daa6 100644 --- a/runtime/rust/prompty/src/model/template/template.rs +++ b/runtime/rust/prompty/src/model/template/template.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -41,8 +48,16 @@ impl Template { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - format: value.get("format").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| FormatConfig::load_from_value(v, ctx)).unwrap_or_default(), - parser: value.get("parser").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| ParserConfig::load_from_value(v, ctx)).unwrap_or_default(), + format: value + .get("format") + .filter(|v| v.is_object() || v.is_array() || v.is_string()) + .map(|v| FormatConfig::load_from_value(v, ctx)) + .unwrap_or_default(), + parser: value + .get("parser") + .filter(|v| v.is_object() || v.is_array() || v.is_string()) + .map(|v| ParserConfig::load_from_value(v, ctx)) + .unwrap_or_default(), } } diff --git a/runtime/rust/prompty/src/model/tools/binding.rs b/runtime/rust/prompty/src/model/tools/binding.rs index f526582e..d2cd6c35 100644 --- a/runtime/rust/prompty/src/model/tools/binding.rs +++ b/runtime/rust/prompty/src/model/tools/binding.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -38,11 +45,22 @@ impl Binding { let value = ctx.process_input(value.clone()); if let Some(s) = value.as_str() { let value = s.to_string(); - return Binding { input: value.into(), ..Default::default() }; + return Binding { + input: value.into(), + ..Default::default() + }; } Self { - name: value.get("name").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - input: value.get("input").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + name: value + .get("name") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + input: value + .get("input") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), } } @@ -53,10 +71,16 @@ impl Binding { let mut result = serde_json::Map::new(); // Write base fields if !self.name.is_empty() { - result.insert("name".to_string(), serde_json::Value::String(self.name.clone())); + result.insert( + "name".to_string(), + serde_json::Value::String(self.name.clone()), + ); } if !self.input.is_empty() { - result.insert("input".to_string(), serde_json::Value::String(self.input.clone())); + result.insert( + "input".to_string(), + serde_json::Value::String(self.input.clone()), + ); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/tools/mcp_approval_mode.rs b/runtime/rust/prompty/src/model/tools/mcp_approval_mode.rs index 9588b51a..ccdc2062 100644 --- a/runtime/rust/prompty/src/model/tools/mcp_approval_mode.rs +++ b/runtime/rust/prompty/src/model/tools/mcp_approval_mode.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -82,12 +89,34 @@ impl McpApprovalMode { let value = ctx.process_input(value.clone()); if let Some(s) = value.as_str() { let value = s.to_string(); - return McpApprovalMode { kind: mcpApprovalModeKind::from_str_opt(&value).unwrap_or(mcpApprovalModeKind::Always), ..Default::default() }; + return McpApprovalMode { + kind: mcpApprovalModeKind::from_str_opt(&value) + .unwrap_or(mcpApprovalModeKind::Always), + ..Default::default() + }; } Self { - kind: value.get("kind").and_then(|v| v.as_str()).and_then(|s| mcpApprovalModeKind::from_str_opt(s)).unwrap_or(mcpApprovalModeKind::Always), - always_require_approval_tools: value.get("alwaysRequireApprovalTools").and_then(|v| v.as_array()).map(|arr| arr.iter().filter_map(|v| v.as_str().map(|s| s.to_string())).collect()), - never_require_approval_tools: value.get("neverRequireApprovalTools").and_then(|v| v.as_array()).map(|arr| arr.iter().filter_map(|v| v.as_str().map(|s| s.to_string())).collect()), + kind: value + .get("kind") + .and_then(|v| v.as_str()) + .and_then(|s| mcpApprovalModeKind::from_str_opt(s)) + .unwrap_or(mcpApprovalModeKind::Always), + always_require_approval_tools: value + .get("alwaysRequireApprovalTools") + .and_then(|v| v.as_array()) + .map(|arr| { + arr.iter() + .filter_map(|v| v.as_str().map(|s| s.to_string())) + .collect() + }), + never_require_approval_tools: value + .get("neverRequireApprovalTools") + .and_then(|v| v.as_array()) + .map(|arr| { + arr.iter() + .filter_map(|v| v.as_str().map(|s| s.to_string())) + .collect() + }), } } @@ -97,12 +126,21 @@ impl McpApprovalMode { pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { let mut result = serde_json::Map::new(); // Write base fields - result.insert("kind".to_string(), serde_json::Value::String(self.kind.to_string())); + result.insert( + "kind".to_string(), + serde_json::Value::String(self.kind.to_string()), + ); if let Some(ref items) = self.always_require_approval_tools { - result.insert("alwaysRequireApprovalTools".to_string(), serde_json::to_value(items).unwrap_or(serde_json::Value::Null)); + result.insert( + "alwaysRequireApprovalTools".to_string(), + serde_json::to_value(items).unwrap_or(serde_json::Value::Null), + ); } if let Some(ref items) = self.never_require_approval_tools { - result.insert("neverRequireApprovalTools".to_string(), serde_json::to_value(items).unwrap_or(serde_json::Value::Null)); + result.insert( + "neverRequireApprovalTools".to_string(), + serde_json::to_value(items).unwrap_or(serde_json::Value::Null), + ); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/tools/mod.rs b/runtime/rust/prompty/src/model/tools/mod.rs index e294fa1f..5e15401c 100644 --- a/runtime/rust/prompty/src/model/tools/mod.rs +++ b/runtime/rust/prompty/src/model/tools/mod.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] pub mod binding; pub use binding::*; diff --git a/runtime/rust/prompty/src/model/tools/tool.rs b/runtime/rust/prompty/src/model/tools/tool.rs index cfe10da8..34d6000a 100644 --- a/runtime/rust/prompty/src/model/tools/tool.rs +++ b/runtime/rust/prompty/src/model/tools/tool.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -12,7 +19,6 @@ use super::mcp_approval_mode::McpApprovalMode; use super::super::core::property::Property; - /// Variant-specific data for [`Tool`], discriminated by `kind`. #[derive(Debug, Clone)] pub enum ToolKind { @@ -109,34 +115,89 @@ impl Tool { let kind_str = value.get("kind").and_then(|v| v.as_str()).unwrap_or(""); let kind = match kind_str { "function" => ToolKind::Function { - parameters: value.get("parameters").map(|v| Self::load_parameters(v, ctx)).unwrap_or_default(), + parameters: value + .get("parameters") + .map(|v| Self::load_parameters(v, ctx)) + .unwrap_or_default(), strict: value.get("strict").and_then(|v| v.as_bool()), }, "mcp" => ToolKind::Mcp { - connection: value.get("connection").cloned().unwrap_or(serde_json::Value::Null), - server_name: value.get("serverName").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - server_description: value.get("serverDescription").and_then(|v| v.as_str()).map(|s| s.to_string()), - approval_mode: value.get("approvalMode").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| McpApprovalMode::load_from_value(v, ctx)).unwrap_or_default(), - allowed_tools: value.get("allowedTools").and_then(|v| v.as_array()).map(|arr| arr.iter().filter_map(|v| v.as_str().map(|s| s.to_string())).collect()), + connection: value + .get("connection") + .cloned() + .unwrap_or(serde_json::Value::Null), + server_name: value + .get("serverName") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + server_description: value + .get("serverDescription") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + approval_mode: value + .get("approvalMode") + .filter(|v| v.is_object() || v.is_array() || v.is_string()) + .map(|v| McpApprovalMode::load_from_value(v, ctx)) + .unwrap_or_default(), + allowed_tools: value + .get("allowedTools") + .and_then(|v| v.as_array()) + .map(|arr| { + arr.iter() + .filter_map(|v| v.as_str().map(|s| s.to_string())) + .collect() + }), }, "openapi" => ToolKind::OpenApi { - connection: value.get("connection").cloned().unwrap_or(serde_json::Value::Null), - specification: value.get("specification").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + connection: value + .get("connection") + .cloned() + .unwrap_or(serde_json::Value::Null), + specification: value + .get("specification") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), }, "prompty" => ToolKind::Prompty { - path: value.get("path").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - mode: value.get("mode").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + path: value + .get("path") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + mode: value + .get("mode") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), }, _ => ToolKind::Custom { - connection: value.get("connection").cloned().unwrap_or(serde_json::Value::Null), - options: value.get("options").cloned().unwrap_or(serde_json::Value::Null), + connection: value + .get("connection") + .cloned() + .unwrap_or(serde_json::Value::Null), + options: value + .get("options") + .cloned() + .unwrap_or(serde_json::Value::Null), kind_name: kind_str.to_string(), }, }; Self { - name: value.get("name").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - description: value.get("description").and_then(|v| v.as_str()).map(|s| s.to_string()), - bindings: value.get("bindings").map(|v| Self::load_bindings(v, ctx)).unwrap_or_default(), + name: value + .get("name") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + description: value + .get("description") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + bindings: value + .get("bindings") + .map(|v| Self::load_bindings(v, ctx)) + .unwrap_or_default(), kind: kind, } } @@ -158,36 +219,68 @@ impl Tool { pub fn to_value(&self, ctx: &SaveContext) -> serde_json::Value { let mut result = serde_json::Map::new(); // Write the discriminator - result.insert("kind".to_string(), serde_json::Value::String(self.kind_str().to_string())); + result.insert( + "kind".to_string(), + serde_json::Value::String(self.kind_str().to_string()), + ); // Write base fields if !self.name.is_empty() { - result.insert("name".to_string(), serde_json::Value::String(self.name.clone())); + result.insert( + "name".to_string(), + serde_json::Value::String(self.name.clone()), + ); } if let Some(ref val) = self.description { - result.insert("description".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "description".to_string(), + serde_json::Value::String(val.clone()), + ); } if !self.bindings.is_empty() { - result.insert("bindings".to_string(), Self::save_bindings(&self.bindings, ctx)); + result.insert( + "bindings".to_string(), + Self::save_bindings(&self.bindings, ctx), + ); } // Write variant-specific fields match &self.kind { - ToolKind::Function { parameters, strict, .. } => { + ToolKind::Function { + parameters, strict, .. + } => { if !parameters.is_empty() { - result.insert("parameters".to_string(), serde_json::Value::Array(parameters.iter().map(|item| item.to_value(ctx)).collect())); + result.insert( + "parameters".to_string(), + serde_json::Value::Array( + parameters.iter().map(|item| item.to_value(ctx)).collect(), + ), + ); } if let Some(val) = strict { result.insert("strict".to_string(), serde_json::Value::Bool(*val)); } } - ToolKind::Mcp { connection, server_name, server_description, approval_mode, allowed_tools, .. } => { + ToolKind::Mcp { + connection, + server_name, + server_description, + approval_mode, + allowed_tools, + .. + } => { if !connection.is_null() { result.insert("connection".to_string(), connection.clone()); } if !server_name.is_empty() { - result.insert("serverName".to_string(), serde_json::Value::String(server_name.clone())); + result.insert( + "serverName".to_string(), + serde_json::Value::String(server_name.clone()), + ); } if let Some(val) = server_description { - result.insert("serverDescription".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "serverDescription".to_string(), + serde_json::Value::String(val.clone()), + ); } { let nested = approval_mode.to_value(ctx); @@ -196,18 +289,28 @@ impl Tool { } } if let Some(items) = allowed_tools { - result.insert("allowedTools".to_string(), serde_json::to_value(items).unwrap_or(serde_json::Value::Null)); + result.insert( + "allowedTools".to_string(), + serde_json::to_value(items).unwrap_or(serde_json::Value::Null), + ); } } - ToolKind::OpenApi { connection, specification, .. } => { + ToolKind::OpenApi { + connection, + specification, + .. + } => { if !connection.is_null() { result.insert("connection".to_string(), connection.clone()); } if !specification.is_empty() { - result.insert("specification".to_string(), serde_json::Value::String(specification.clone())); + result.insert( + "specification".to_string(), + serde_json::Value::String(specification.clone()), + ); } } - ToolKind::Prompty { path, mode, .. } => { + ToolKind::Prompty { path, mode, .. } => { if !path.is_empty() { result.insert("path".to_string(), serde_json::Value::String(path.clone())); } @@ -215,7 +318,12 @@ impl Tool { result.insert("mode".to_string(), serde_json::Value::String(mode.clone())); } } - ToolKind::Custom { connection, options, kind_name: _, .. } => { + ToolKind::Custom { + connection, + options, + kind_name: _, + .. + } => { if !connection.is_null() { result.insert("connection".to_string(), connection.clone()); } @@ -241,71 +349,81 @@ impl Tool { /// Handles both array format `[{...}]` and dict format `{"name": {...}}`. fn load_bindings(data: &serde_json::Value, ctx: &LoadContext) -> Vec { match data { - serde_json::Value::Array(arr) => { - arr.iter().map(|v| Binding::load_from_value(v, ctx)).collect() - } + serde_json::Value::Array(arr) => arr + .iter() + .map(|v| Binding::load_from_value(v, ctx)) + .collect(), - serde_json::Value::Object(obj) => { - obj.iter() - .filter_map(|(name, value)| { - if value.is_array() { - return None; - } - let mut v = if value.is_object() { - value.clone() - } else { - serde_json::json!({ "input": value }) - }; - if let serde_json::Value::Object(ref mut m) = v { - m.entry("name".to_string()).or_insert_with(|| serde_json::Value::String(name.clone())); - } - Some(Binding::load_from_value(&v, ctx)) - }) - .collect() - } + serde_json::Value::Object(obj) => obj + .iter() + .filter_map(|(name, value)| { + if value.is_array() { + return None; + } + let mut v = if value.is_object() { + value.clone() + } else { + serde_json::json!({ "input": value }) + }; + if let serde_json::Value::Object(ref mut m) = v { + m.entry("name".to_string()) + .or_insert_with(|| serde_json::Value::String(name.clone())); + } + Some(Binding::load_from_value(&v, ctx)) + }) + .collect(), _ => Vec::new(), - } } /// Save a collection of Binding to a JSON value. fn save_bindings(items: &[Binding], ctx: &SaveContext) -> serde_json::Value { - if ctx.collection_format == "array" { - return serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()); + return serde_json::Value::Array( + items + .iter() + .map(|item| item.to_value(ctx)) + .collect::>(), + ); } // Object format: use name as key let mut result = serde_json::Map::new(); for item in items { let mut item_data = match item.to_value(ctx) { serde_json::Value::Object(m) => m, - other => { let mut m = serde_json::Map::new(); m.insert("value".to_string(), other); m }, + other => { + let mut m = serde_json::Map::new(); + m.insert("value".to_string(), other); + m + } }; if let Some(serde_json::Value::String(name)) = item_data.remove("name") { result.insert(name, serde_json::Value::Object(item_data)); } } serde_json::Value::Object(result) - } /// Load a collection of Property from a JSON value. /// Handles both array format `[{...}]`. fn load_parameters(data: &serde_json::Value, ctx: &LoadContext) -> Vec { match data { - serde_json::Value::Array(arr) => { - arr.iter().map(|v| Property::load_from_value(v, ctx)).collect() - } + serde_json::Value::Array(arr) => arr + .iter() + .map(|v| Property::load_from_value(v, ctx)) + .collect(), _ => Vec::new(), - } } /// Save a collection of Property to a JSON value. fn save_parameters(items: &[Property], ctx: &SaveContext) -> serde_json::Value { - - serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()) - + serde_json::Value::Array( + items + .iter() + .map(|item| item.to_value(ctx)) + .collect::>(), + ) } } diff --git a/runtime/rust/prompty/src/model/tools/tool_context.rs b/runtime/rust/prompty/src/model/tools/tool_context.rs index 7338948b..21c7f726 100644 --- a/runtime/rust/prompty/src/model/tools/tool_context.rs +++ b/runtime/rust/prompty/src/model/tools/tool_context.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -39,8 +46,14 @@ impl ToolContext { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - messages: value.get("messages").map(|v| Self::load_messages(v, ctx)).unwrap_or_default(), - metadata: value.get("metadata").cloned().unwrap_or(serde_json::Value::Null), + messages: value + .get("messages") + .map(|v| Self::load_messages(v, ctx)) + .unwrap_or_default(), + metadata: value + .get("metadata") + .cloned() + .unwrap_or(serde_json::Value::Null), } } @@ -51,7 +64,10 @@ impl ToolContext { let mut result = serde_json::Map::new(); // Write base fields if !self.messages.is_empty() { - result.insert("messages".to_string(), Self::save_messages(&self.messages, ctx)); + result.insert( + "messages".to_string(), + Self::save_messages(&self.messages, ctx), + ); } if !self.metadata.is_null() { result.insert("metadata".to_string(), self.metadata.clone()); @@ -74,24 +90,26 @@ impl ToolContext { self.metadata.as_object() } - /// Load a collection of Message from a JSON value. /// Handles both array format `[{...}]`. fn load_messages(data: &serde_json::Value, ctx: &LoadContext) -> Vec { match data { - serde_json::Value::Array(arr) => { - arr.iter().map(|v| Message::load_from_value(v, ctx)).collect() - } + serde_json::Value::Array(arr) => arr + .iter() + .map(|v| Message::load_from_value(v, ctx)) + .collect(), _ => Vec::new(), - } } /// Save a collection of Message to a JSON value. fn save_messages(items: &[Message], ctx: &SaveContext) -> serde_json::Value { - - serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()) - + serde_json::Value::Array( + items + .iter() + .map(|item| item.to_value(ctx)) + .collect::>(), + ) } } diff --git a/runtime/rust/prompty/src/model/tools/tool_dispatch_result.rs b/runtime/rust/prompty/src/model/tools/tool_dispatch_result.rs index a7fa5d48..618b02c2 100644 --- a/runtime/rust/prompty/src/model/tools/tool_dispatch_result.rs +++ b/runtime/rust/prompty/src/model/tools/tool_dispatch_result.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -41,9 +48,21 @@ impl ToolDispatchResult { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - tool_call_id: value.get("toolCallId").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - name: value.get("name").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - result: value.get("result").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| ToolResult::load_from_value(v, ctx)).unwrap_or_default(), + tool_call_id: value + .get("toolCallId") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + name: value + .get("name") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + result: value + .get("result") + .filter(|v| v.is_object() || v.is_array() || v.is_string()) + .map(|v| ToolResult::load_from_value(v, ctx)) + .unwrap_or_default(), } } @@ -54,10 +73,16 @@ impl ToolDispatchResult { let mut result = serde_json::Map::new(); // Write base fields if !self.tool_call_id.is_empty() { - result.insert("toolCallId".to_string(), serde_json::Value::String(self.tool_call_id.clone())); + result.insert( + "toolCallId".to_string(), + serde_json::Value::String(self.tool_call_id.clone()), + ); } if !self.name.is_empty() { - result.insert("name".to_string(), serde_json::Value::String(self.name.clone())); + result.insert( + "name".to_string(), + serde_json::Value::String(self.name.clone()), + ); } { let nested = self.result.to_value(ctx); diff --git a/runtime/rust/prompty/src/model/tracing/mod.rs b/runtime/rust/prompty/src/model/tracing/mod.rs index 501ff5cc..67313584 100644 --- a/runtime/rust/prompty/src/model/tracing/mod.rs +++ b/runtime/rust/prompty/src/model/tracing/mod.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] pub mod trace_time; pub use trace_time::*; diff --git a/runtime/rust/prompty/src/model/tracing/trace_file.rs b/runtime/rust/prompty/src/model/tracing/trace_file.rs index e5416b63..f4619c7e 100644 --- a/runtime/rust/prompty/src/model/tracing/trace_file.rs +++ b/runtime/rust/prompty/src/model/tracing/trace_file.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -41,9 +48,21 @@ impl TraceFile { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - runtime: value.get("runtime").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - version: value.get("version").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - trace: value.get("trace").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| TraceSpan::load_from_value(v, ctx)).unwrap_or_default(), + runtime: value + .get("runtime") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + version: value + .get("version") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + trace: value + .get("trace") + .filter(|v| v.is_object() || v.is_array() || v.is_string()) + .map(|v| TraceSpan::load_from_value(v, ctx)) + .unwrap_or_default(), } } @@ -54,10 +73,16 @@ impl TraceFile { let mut result = serde_json::Map::new(); // Write base fields if !self.runtime.is_empty() { - result.insert("runtime".to_string(), serde_json::Value::String(self.runtime.clone())); + result.insert( + "runtime".to_string(), + serde_json::Value::String(self.runtime.clone()), + ); } if !self.version.is_empty() { - result.insert("version".to_string(), serde_json::Value::String(self.version.clone())); + result.insert( + "version".to_string(), + serde_json::Value::String(self.version.clone()), + ); } { let nested = self.trace.to_value(ctx); diff --git a/runtime/rust/prompty/src/model/tracing/trace_span.rs b/runtime/rust/prompty/src/model/tracing/trace_span.rs index d79153ef..6e5f5ccc 100644 --- a/runtime/rust/prompty/src/model/tracing/trace_span.rs +++ b/runtime/rust/prompty/src/model/tracing/trace_span.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -55,15 +62,41 @@ impl TraceSpan { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - name: value.get("name").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - __time: value.get("__time").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| TraceTime::load_from_value(v, ctx)).unwrap_or_default(), - signature: value.get("signature").and_then(|v| v.as_str()).map(|s| s.to_string()), - inputs: value.get("inputs").cloned().unwrap_or(serde_json::Value::Null), + name: value + .get("name") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + __time: value + .get("__time") + .filter(|v| v.is_object() || v.is_array() || v.is_string()) + .map(|v| TraceTime::load_from_value(v, ctx)) + .unwrap_or_default(), + signature: value + .get("signature") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + inputs: value + .get("inputs") + .cloned() + .unwrap_or(serde_json::Value::Null), output: value.get("output").cloned(), - error: value.get("error").and_then(|v| v.as_str()).map(|s| s.to_string()), - __usage: value.get("__usage").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| TokenUsage::load_from_value(v, ctx)), - attributes: value.get("attributes").cloned().unwrap_or(serde_json::Value::Null), - __frames: value.get("__frames").and_then(|v| v.as_array()).map(|arr| arr.to_vec()), + error: value + .get("error") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + __usage: value + .get("__usage") + .filter(|v| v.is_object() || v.is_array() || v.is_string()) + .map(|v| TokenUsage::load_from_value(v, ctx)), + attributes: value + .get("attributes") + .cloned() + .unwrap_or(serde_json::Value::Null), + __frames: value + .get("__frames") + .and_then(|v| v.as_array()) + .map(|arr| arr.to_vec()), } } @@ -74,7 +107,10 @@ impl TraceSpan { let mut result = serde_json::Map::new(); // Write base fields if !self.name.is_empty() { - result.insert("name".to_string(), serde_json::Value::String(self.name.clone())); + result.insert( + "name".to_string(), + serde_json::Value::String(self.name.clone()), + ); } { let nested = self.__time.to_value(ctx); @@ -83,7 +119,10 @@ impl TraceSpan { } } if let Some(ref val) = self.signature { - result.insert("signature".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "signature".to_string(), + serde_json::Value::String(val.clone()), + ); } if !self.inputs.is_null() { result.insert("inputs".to_string(), self.inputs.clone()); @@ -104,7 +143,10 @@ impl TraceSpan { result.insert("attributes".to_string(), self.attributes.clone()); } if let Some(ref items) = self.__frames { - result.insert("__frames".to_string(), serde_json::to_value(items).unwrap_or(serde_json::Value::Null)); + result.insert( + "__frames".to_string(), + serde_json::to_value(items).unwrap_or(serde_json::Value::Null), + ); } ctx.process_dict(serde_json::Value::Object(result)) } @@ -129,5 +171,4 @@ impl TraceSpan { pub fn as_attributes_dict(&self) -> Option<&serde_json::Map> { self.attributes.as_object() } - } diff --git a/runtime/rust/prompty/src/model/tracing/trace_time.rs b/runtime/rust/prompty/src/model/tracing/trace_time.rs index e982402c..b79e8c2d 100644 --- a/runtime/rust/prompty/src/model/tracing/trace_time.rs +++ b/runtime/rust/prompty/src/model/tracing/trace_time.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -39,9 +46,20 @@ impl TraceTime { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - start: value.get("start").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - end: value.get("end").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - duration: value.get("duration").and_then(|v| v.as_f64()).unwrap_or(0.0), + start: value + .get("start") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + end: value + .get("end") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + duration: value + .get("duration") + .and_then(|v| v.as_f64()) + .unwrap_or(0.0), } } @@ -52,13 +70,24 @@ impl TraceTime { let mut result = serde_json::Map::new(); // Write base fields if !self.start.is_empty() { - result.insert("start".to_string(), serde_json::Value::String(self.start.clone())); + result.insert( + "start".to_string(), + serde_json::Value::String(self.start.clone()), + ); } if !self.end.is_empty() { - result.insert("end".to_string(), serde_json::Value::String(self.end.clone())); + result.insert( + "end".to_string(), + serde_json::Value::String(self.end.clone()), + ); } if self.duration != 0.0 { - result.insert("duration".to_string(), serde_json::Number::from_f64(self.duration as f64).map(serde_json::Value::Number).unwrap_or(serde_json::Value::Null)); + result.insert( + "duration".to_string(), + serde_json::Number::from_f64(self.duration as f64) + .map(serde_json::Value::Number) + .unwrap_or(serde_json::Value::Null), + ); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/wire/anthropic_image_block.rs b/runtime/rust/prompty/src/model/wire/anthropic_image_block.rs index 9a3fa68c..eb56b137 100644 --- a/runtime/rust/prompty/src/model/wire/anthropic_image_block.rs +++ b/runtime/rust/prompty/src/model/wire/anthropic_image_block.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -39,8 +46,16 @@ impl AnthropicImageBlock { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - r#type: value.get("type").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - source: value.get("source").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| AnthropicImageSource::load_from_value(v, ctx)).unwrap_or_default(), + r#type: value + .get("type") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + source: value + .get("source") + .filter(|v| v.is_object() || v.is_array() || v.is_string()) + .map(|v| AnthropicImageSource::load_from_value(v, ctx)) + .unwrap_or_default(), } } @@ -51,7 +66,10 @@ impl AnthropicImageBlock { let mut result = serde_json::Map::new(); // Write base fields if !self.r#type.is_empty() { - result.insert("type".to_string(), serde_json::Value::String(self.r#type.clone())); + result.insert( + "type".to_string(), + serde_json::Value::String(self.r#type.clone()), + ); } { let nested = self.source.to_value(ctx); diff --git a/runtime/rust/prompty/src/model/wire/anthropic_image_source.rs b/runtime/rust/prompty/src/model/wire/anthropic_image_source.rs index 6b5140ca..9dc00352 100644 --- a/runtime/rust/prompty/src/model/wire/anthropic_image_source.rs +++ b/runtime/rust/prompty/src/model/wire/anthropic_image_source.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -39,9 +46,21 @@ impl AnthropicImageSource { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - r#type: value.get("type").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - media_type: value.get("media_type").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - data: value.get("data").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + r#type: value + .get("type") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + media_type: value + .get("media_type") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + data: value + .get("data") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), } } @@ -52,13 +71,22 @@ impl AnthropicImageSource { let mut result = serde_json::Map::new(); // Write base fields if !self.r#type.is_empty() { - result.insert("type".to_string(), serde_json::Value::String(self.r#type.clone())); + result.insert( + "type".to_string(), + serde_json::Value::String(self.r#type.clone()), + ); } if !self.media_type.is_empty() { - result.insert("media_type".to_string(), serde_json::Value::String(self.media_type.clone())); + result.insert( + "media_type".to_string(), + serde_json::Value::String(self.media_type.clone()), + ); } if !self.data.is_empty() { - result.insert("data".to_string(), serde_json::Value::String(self.data.clone())); + result.insert( + "data".to_string(), + serde_json::Value::String(self.data.clone()), + ); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/wire/anthropic_messages_request.rs b/runtime/rust/prompty/src/model/wire/anthropic_messages_request.rs index 75ebfa54..3164f0d2 100644 --- a/runtime/rust/prompty/src/model/wire/anthropic_messages_request.rs +++ b/runtime/rust/prompty/src/model/wire/anthropic_messages_request.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -55,15 +62,47 @@ impl AnthropicMessagesRequest { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - model: value.get("model").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - messages: value.get("messages").map(|v| Self::load_messages(v, ctx)).unwrap_or_default(), - max_tokens: value.get("max_tokens").and_then(|v| v.as_i64()).unwrap_or(0) as i32, - system: value.get("system").and_then(|v| v.as_str()).map(|s| s.to_string()), - temperature: value.get("temperature").and_then(|v| v.as_f64()).map(|v| v as f32), - top_p: value.get("top_p").and_then(|v| v.as_f64()).map(|v| v as f32), - top_k: value.get("top_k").and_then(|v| v.as_i64()).map(|v| v as i32), - stop_sequences: value.get("stop_sequences").and_then(|v| v.as_array()).map(|arr| arr.iter().filter_map(|v| v.as_str().map(|s| s.to_string())).collect()), - tools: value.get("tools").map(|v| Self::load_tools(v, ctx)).unwrap_or_default(), + model: value + .get("model") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + messages: value + .get("messages") + .map(|v| Self::load_messages(v, ctx)) + .unwrap_or_default(), + max_tokens: value + .get("max_tokens") + .and_then(|v| v.as_i64()) + .unwrap_or(0) as i32, + system: value + .get("system") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + temperature: value + .get("temperature") + .and_then(|v| v.as_f64()) + .map(|v| v as f32), + top_p: value + .get("top_p") + .and_then(|v| v.as_f64()) + .map(|v| v as f32), + top_k: value + .get("top_k") + .and_then(|v| v.as_i64()) + .map(|v| v as i32), + stop_sequences: value + .get("stop_sequences") + .and_then(|v| v.as_array()) + .map(|arr| { + arr.iter() + .filter_map(|v| v.as_str().map(|s| s.to_string())) + .collect() + }), + tools: value + .get("tools") + .map(|v| Self::load_tools(v, ctx)) + .unwrap_or_default(), } } @@ -74,28 +113,53 @@ impl AnthropicMessagesRequest { let mut result = serde_json::Map::new(); // Write base fields if !self.model.is_empty() { - result.insert("model".to_string(), serde_json::Value::String(self.model.clone())); + result.insert( + "model".to_string(), + serde_json::Value::String(self.model.clone()), + ); } if !self.messages.is_empty() { - result.insert("messages".to_string(), Self::save_messages(&self.messages, ctx)); + result.insert( + "messages".to_string(), + Self::save_messages(&self.messages, ctx), + ); } if self.max_tokens != 0 { - result.insert("max_tokens".to_string(), serde_json::Value::Number(serde_json::Number::from(self.max_tokens))); + result.insert( + "max_tokens".to_string(), + serde_json::Value::Number(serde_json::Number::from(self.max_tokens)), + ); } if let Some(ref val) = self.system { result.insert("system".to_string(), serde_json::Value::String(val.clone())); } if let Some(val) = self.temperature { - result.insert("temperature".to_string(), serde_json::Number::from_f64(val as f64).map(serde_json::Value::Number).unwrap_or(serde_json::Value::Null)); + result.insert( + "temperature".to_string(), + serde_json::Number::from_f64(val as f64) + .map(serde_json::Value::Number) + .unwrap_or(serde_json::Value::Null), + ); } if let Some(val) = self.top_p { - result.insert("top_p".to_string(), serde_json::Number::from_f64(val as f64).map(serde_json::Value::Number).unwrap_or(serde_json::Value::Null)); + result.insert( + "top_p".to_string(), + serde_json::Number::from_f64(val as f64) + .map(serde_json::Value::Number) + .unwrap_or(serde_json::Value::Null), + ); } if let Some(val) = self.top_k { - result.insert("top_k".to_string(), serde_json::Value::Number(serde_json::Number::from(val))); + result.insert( + "top_k".to_string(), + serde_json::Value::Number(serde_json::Number::from(val)), + ); } if let Some(ref items) = self.stop_sequences { - result.insert("stop_sequences".to_string(), serde_json::to_value(items).unwrap_or(serde_json::Value::Null)); + result.insert( + "stop_sequences".to_string(), + serde_json::to_value(items).unwrap_or(serde_json::Value::Null), + ); } if !self.tools.is_empty() { result.insert("tools".to_string(), Self::save_tools(&self.tools, ctx)); @@ -117,71 +181,81 @@ impl AnthropicMessagesRequest { /// Handles both array format `[{...}]`. fn load_messages(data: &serde_json::Value, ctx: &LoadContext) -> Vec { match data { - serde_json::Value::Array(arr) => { - arr.iter().map(|v| AnthropicWireMessage::load_from_value(v, ctx)).collect() - } + serde_json::Value::Array(arr) => arr + .iter() + .map(|v| AnthropicWireMessage::load_from_value(v, ctx)) + .collect(), _ => Vec::new(), - } } /// Save a collection of AnthropicWireMessage to a JSON value. fn save_messages(items: &[AnthropicWireMessage], ctx: &SaveContext) -> serde_json::Value { - - serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()) - + serde_json::Value::Array( + items + .iter() + .map(|item| item.to_value(ctx)) + .collect::>(), + ) } /// Load a collection of AnthropicToolDefinition from a JSON value. /// Handles both array format `[{...}]` and dict format `{"name": {...}}`. fn load_tools(data: &serde_json::Value, ctx: &LoadContext) -> Vec { match data { - serde_json::Value::Array(arr) => { - arr.iter().map(|v| AnthropicToolDefinition::load_from_value(v, ctx)).collect() - } + serde_json::Value::Array(arr) => arr + .iter() + .map(|v| AnthropicToolDefinition::load_from_value(v, ctx)) + .collect(), - serde_json::Value::Object(obj) => { - obj.iter() - .filter_map(|(name, value)| { - if value.is_array() { - return None; - } - let mut v = if value.is_object() { - value.clone() - } else { - serde_json::json!({ "description": value }) - }; - if let serde_json::Value::Object(ref mut m) = v { - m.entry("name".to_string()).or_insert_with(|| serde_json::Value::String(name.clone())); - } - Some(AnthropicToolDefinition::load_from_value(&v, ctx)) - }) - .collect() - } + serde_json::Value::Object(obj) => obj + .iter() + .filter_map(|(name, value)| { + if value.is_array() { + return None; + } + let mut v = if value.is_object() { + value.clone() + } else { + serde_json::json!({ "description": value }) + }; + if let serde_json::Value::Object(ref mut m) = v { + m.entry("name".to_string()) + .or_insert_with(|| serde_json::Value::String(name.clone())); + } + Some(AnthropicToolDefinition::load_from_value(&v, ctx)) + }) + .collect(), _ => Vec::new(), - } } /// Save a collection of AnthropicToolDefinition to a JSON value. fn save_tools(items: &[AnthropicToolDefinition], ctx: &SaveContext) -> serde_json::Value { - if ctx.collection_format == "array" { - return serde_json::Value::Array(items.iter().map(|item| item.to_value(ctx)).collect::>()); + return serde_json::Value::Array( + items + .iter() + .map(|item| item.to_value(ctx)) + .collect::>(), + ); } // Object format: use name as key let mut result = serde_json::Map::new(); for item in items { let mut item_data = match item.to_value(ctx) { serde_json::Value::Object(m) => m, - other => { let mut m = serde_json::Map::new(); m.insert("value".to_string(), other); m }, + other => { + let mut m = serde_json::Map::new(); + m.insert("value".to_string(), other); + m + } }; if let Some(serde_json::Value::String(name)) = item_data.remove("name") { result.insert(name, serde_json::Value::Object(item_data)); } } serde_json::Value::Object(result) - } } diff --git a/runtime/rust/prompty/src/model/wire/anthropic_messages_response.rs b/runtime/rust/prompty/src/model/wire/anthropic_messages_response.rs index fd665d05..9fa5b133 100644 --- a/runtime/rust/prompty/src/model/wire/anthropic_messages_response.rs +++ b/runtime/rust/prompty/src/model/wire/anthropic_messages_response.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -49,13 +56,41 @@ impl AnthropicMessagesResponse { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - id: value.get("id").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - r#type: value.get("type").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - role: value.get("role").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - content: value.get("content").and_then(|v| v.as_array()).map(|arr| arr.to_vec()).unwrap_or_default(), - model: value.get("model").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - stop_reason: value.get("stop_reason").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - usage: value.get("usage").filter(|v| v.is_object() || v.is_array() || v.is_string()).map(|v| AnthropicUsage::load_from_value(v, ctx)).unwrap_or_default(), + id: value + .get("id") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + r#type: value + .get("type") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + role: value + .get("role") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + content: value + .get("content") + .and_then(|v| v.as_array()) + .map(|arr| arr.to_vec()) + .unwrap_or_default(), + model: value + .get("model") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + stop_reason: value + .get("stop_reason") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + usage: value + .get("usage") + .filter(|v| v.is_object() || v.is_array() || v.is_string()) + .map(|v| AnthropicUsage::load_from_value(v, ctx)) + .unwrap_or_default(), } } @@ -69,19 +104,34 @@ impl AnthropicMessagesResponse { result.insert("id".to_string(), serde_json::Value::String(self.id.clone())); } if !self.r#type.is_empty() { - result.insert("type".to_string(), serde_json::Value::String(self.r#type.clone())); + result.insert( + "type".to_string(), + serde_json::Value::String(self.r#type.clone()), + ); } if !self.role.is_empty() { - result.insert("role".to_string(), serde_json::Value::String(self.role.clone())); + result.insert( + "role".to_string(), + serde_json::Value::String(self.role.clone()), + ); } if !self.content.is_empty() { - result.insert("content".to_string(), serde_json::to_value(&self.content).unwrap_or(serde_json::Value::Null)); + result.insert( + "content".to_string(), + serde_json::to_value(&self.content).unwrap_or(serde_json::Value::Null), + ); } if !self.model.is_empty() { - result.insert("model".to_string(), serde_json::Value::String(self.model.clone())); + result.insert( + "model".to_string(), + serde_json::Value::String(self.model.clone()), + ); } if !self.stop_reason.is_empty() { - result.insert("stop_reason".to_string(), serde_json::Value::String(self.stop_reason.clone())); + result.insert( + "stop_reason".to_string(), + serde_json::Value::String(self.stop_reason.clone()), + ); } { let nested = self.usage.to_value(ctx); diff --git a/runtime/rust/prompty/src/model/wire/anthropic_text_block.rs b/runtime/rust/prompty/src/model/wire/anthropic_text_block.rs index 7d0d779c..0721944f 100644 --- a/runtime/rust/prompty/src/model/wire/anthropic_text_block.rs +++ b/runtime/rust/prompty/src/model/wire/anthropic_text_block.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -37,8 +44,16 @@ impl AnthropicTextBlock { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - r#type: value.get("type").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - text: value.get("text").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + r#type: value + .get("type") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + text: value + .get("text") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), } } @@ -49,10 +64,16 @@ impl AnthropicTextBlock { let mut result = serde_json::Map::new(); // Write base fields if !self.r#type.is_empty() { - result.insert("type".to_string(), serde_json::Value::String(self.r#type.clone())); + result.insert( + "type".to_string(), + serde_json::Value::String(self.r#type.clone()), + ); } if !self.text.is_empty() { - result.insert("text".to_string(), serde_json::Value::String(self.text.clone())); + result.insert( + "text".to_string(), + serde_json::Value::String(self.text.clone()), + ); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/wire/anthropic_tool_definition.rs b/runtime/rust/prompty/src/model/wire/anthropic_tool_definition.rs index 88554614..9bc271b6 100644 --- a/runtime/rust/prompty/src/model/wire/anthropic_tool_definition.rs +++ b/runtime/rust/prompty/src/model/wire/anthropic_tool_definition.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -39,9 +46,19 @@ impl AnthropicToolDefinition { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - name: value.get("name").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - description: value.get("description").and_then(|v| v.as_str()).map(|s| s.to_string()), - input_schema: value.get("input_schema").cloned().unwrap_or(serde_json::Value::Null), + name: value + .get("name") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + description: value + .get("description") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()), + input_schema: value + .get("input_schema") + .cloned() + .unwrap_or(serde_json::Value::Null), } } @@ -52,10 +69,16 @@ impl AnthropicToolDefinition { let mut result = serde_json::Map::new(); // Write base fields if !self.name.is_empty() { - result.insert("name".to_string(), serde_json::Value::String(self.name.clone())); + result.insert( + "name".to_string(), + serde_json::Value::String(self.name.clone()), + ); } if let Some(ref val) = self.description { - result.insert("description".to_string(), serde_json::Value::String(val.clone())); + result.insert( + "description".to_string(), + serde_json::Value::String(val.clone()), + ); } if !self.input_schema.is_null() { result.insert("input_schema".to_string(), self.input_schema.clone()); @@ -77,5 +100,4 @@ impl AnthropicToolDefinition { pub fn as_input_schema_dict(&self) -> Option<&serde_json::Map> { self.input_schema.as_object() } - } diff --git a/runtime/rust/prompty/src/model/wire/anthropic_tool_result_block.rs b/runtime/rust/prompty/src/model/wire/anthropic_tool_result_block.rs index 7cb82dba..244bb47c 100644 --- a/runtime/rust/prompty/src/model/wire/anthropic_tool_result_block.rs +++ b/runtime/rust/prompty/src/model/wire/anthropic_tool_result_block.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -39,9 +46,21 @@ impl AnthropicToolResultBlock { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - r#type: value.get("type").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - tool_use_id: value.get("tool_use_id").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - content: value.get("content").and_then(|v| v.as_str()).unwrap_or_default().to_string(), + r#type: value + .get("type") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + tool_use_id: value + .get("tool_use_id") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + content: value + .get("content") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), } } @@ -52,13 +71,22 @@ impl AnthropicToolResultBlock { let mut result = serde_json::Map::new(); // Write base fields if !self.r#type.is_empty() { - result.insert("type".to_string(), serde_json::Value::String(self.r#type.clone())); + result.insert( + "type".to_string(), + serde_json::Value::String(self.r#type.clone()), + ); } if !self.tool_use_id.is_empty() { - result.insert("tool_use_id".to_string(), serde_json::Value::String(self.tool_use_id.clone())); + result.insert( + "tool_use_id".to_string(), + serde_json::Value::String(self.tool_use_id.clone()), + ); } if !self.content.is_empty() { - result.insert("content".to_string(), serde_json::Value::String(self.content.clone())); + result.insert( + "content".to_string(), + serde_json::Value::String(self.content.clone()), + ); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/wire/anthropic_tool_use_block.rs b/runtime/rust/prompty/src/model/wire/anthropic_tool_use_block.rs index 86d26cb8..8e1ecc57 100644 --- a/runtime/rust/prompty/src/model/wire/anthropic_tool_use_block.rs +++ b/runtime/rust/prompty/src/model/wire/anthropic_tool_use_block.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -41,10 +48,25 @@ impl AnthropicToolUseBlock { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - r#type: value.get("type").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - id: value.get("id").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - name: value.get("name").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - input: value.get("input").cloned().unwrap_or(serde_json::Value::Null), + r#type: value + .get("type") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + id: value + .get("id") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + name: value + .get("name") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + input: value + .get("input") + .cloned() + .unwrap_or(serde_json::Value::Null), } } @@ -55,13 +77,19 @@ impl AnthropicToolUseBlock { let mut result = serde_json::Map::new(); // Write base fields if !self.r#type.is_empty() { - result.insert("type".to_string(), serde_json::Value::String(self.r#type.clone())); + result.insert( + "type".to_string(), + serde_json::Value::String(self.r#type.clone()), + ); } if !self.id.is_empty() { result.insert("id".to_string(), serde_json::Value::String(self.id.clone())); } if !self.name.is_empty() { - result.insert("name".to_string(), serde_json::Value::String(self.name.clone())); + result.insert( + "name".to_string(), + serde_json::Value::String(self.name.clone()), + ); } if !self.input.is_null() { result.insert("input".to_string(), self.input.clone()); @@ -83,5 +111,4 @@ impl AnthropicToolUseBlock { pub fn as_input_dict(&self) -> Option<&serde_json::Map> { self.input.as_object() } - } diff --git a/runtime/rust/prompty/src/model/wire/anthropic_usage.rs b/runtime/rust/prompty/src/model/wire/anthropic_usage.rs index 42109577..2b5b050a 100644 --- a/runtime/rust/prompty/src/model/wire/anthropic_usage.rs +++ b/runtime/rust/prompty/src/model/wire/anthropic_usage.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -37,8 +44,14 @@ impl AnthropicUsage { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - input_tokens: value.get("input_tokens").and_then(|v| v.as_i64()).unwrap_or(0) as i32, - output_tokens: value.get("output_tokens").and_then(|v| v.as_i64()).unwrap_or(0) as i32, + input_tokens: value + .get("input_tokens") + .and_then(|v| v.as_i64()) + .unwrap_or(0) as i32, + output_tokens: value + .get("output_tokens") + .and_then(|v| v.as_i64()) + .unwrap_or(0) as i32, } } @@ -49,10 +62,16 @@ impl AnthropicUsage { let mut result = serde_json::Map::new(); // Write base fields if self.input_tokens != 0 { - result.insert("input_tokens".to_string(), serde_json::Value::Number(serde_json::Number::from(self.input_tokens))); + result.insert( + "input_tokens".to_string(), + serde_json::Value::Number(serde_json::Number::from(self.input_tokens)), + ); } if self.output_tokens != 0 { - result.insert("output_tokens".to_string(), serde_json::Value::Number(serde_json::Number::from(self.output_tokens))); + result.insert( + "output_tokens".to_string(), + serde_json::Value::Number(serde_json::Number::from(self.output_tokens)), + ); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/wire/anthropic_wire_message.rs b/runtime/rust/prompty/src/model/wire/anthropic_wire_message.rs index 9e16d3fd..fbfb370a 100644 --- a/runtime/rust/prompty/src/model/wire/anthropic_wire_message.rs +++ b/runtime/rust/prompty/src/model/wire/anthropic_wire_message.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use super::super::context::{LoadContext, SaveContext}; @@ -37,8 +44,16 @@ impl AnthropicWireMessage { pub fn load_from_value(value: &serde_json::Value, ctx: &LoadContext) -> Self { let value = ctx.process_input(value.clone()); Self { - role: value.get("role").and_then(|v| v.as_str()).unwrap_or_default().to_string(), - content: value.get("content").and_then(|v| v.as_array()).map(|arr| arr.to_vec()).unwrap_or_default(), + role: value + .get("role") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + content: value + .get("content") + .and_then(|v| v.as_array()) + .map(|arr| arr.to_vec()) + .unwrap_or_default(), } } @@ -49,10 +64,16 @@ impl AnthropicWireMessage { let mut result = serde_json::Map::new(); // Write base fields if !self.role.is_empty() { - result.insert("role".to_string(), serde_json::Value::String(self.role.clone())); + result.insert( + "role".to_string(), + serde_json::Value::String(self.role.clone()), + ); } if !self.content.is_empty() { - result.insert("content".to_string(), serde_json::to_value(&self.content).unwrap_or(serde_json::Value::Null)); + result.insert( + "content".to_string(), + serde_json::to_value(&self.content).unwrap_or(serde_json::Value::Null), + ); } ctx.process_dict(serde_json::Value::Object(result)) } diff --git a/runtime/rust/prompty/src/model/wire/mod.rs b/runtime/rust/prompty/src/model/wire/mod.rs index db9e6906..606b3679 100644 --- a/runtime/rust/prompty/src/model/wire/mod.rs +++ b/runtime/rust/prompty/src/model/wire/mod.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. - -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +// +// Code generated by Typra emitter; DO NOT EDIT. + +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] pub mod anthropic_text_block; pub use anthropic_text_block::*; diff --git a/runtime/rust/prompty/tests/harness_adapters.rs b/runtime/rust/prompty/tests/harness_adapters.rs index 82732ee9..6ffcd402 100644 --- a/runtime/rust/prompty/tests/harness_adapters.rs +++ b/runtime/rust/prompty/tests/harness_adapters.rs @@ -16,8 +16,9 @@ use prompty::model::events::{ turn_event::{TurnEvent, TurnEventType}, }; use prompty::model::pipeline::{ - checkpoint_store::CheckpointStore, event_journal_writer::EventJournalWriter, event_sink::EventSink, - host_tool_executor::HostToolExecutor, permission_resolver::PermissionResolver, + checkpoint_store::CheckpointStore, event_journal_writer::EventJournalWriter, + event_sink::EventSink, host_tool_executor::HostToolExecutor, + permission_resolver::PermissionResolver, }; use serde_json::{Value, json}; diff --git a/runtime/rust/prompty/tests/model/agent/guardrail_result_test.rs b/runtime/rust/prompty/tests/model/agent/guardrail_result_test.rs index 356762a9..b1a8e6fb 100644 --- a/runtime/rust/prompty/tests/model/agent/guardrail_result_test.rs +++ b/runtime/rust/prompty/tests/model/agent/guardrail_result_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::GuardrailResult; use prompty::model::context::{LoadContext, SaveContext}; @@ -15,7 +22,11 @@ fn test_guardrail_result_load_json() { "####; let ctx = LoadContext::default(); let result = GuardrailResult::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.allowed, true); assert!(instance.reason.is_some(), "Expected reason to be Some"); @@ -31,7 +42,11 @@ reason: Content is safe "####; let ctx = LoadContext::default(); let result = GuardrailResult::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.allowed, true); assert!(instance.reason.is_some(), "Expected reason to be Some"); @@ -51,7 +66,11 @@ fn test_guardrail_result_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } #[test] diff --git a/runtime/rust/prompty/tests/model/agent/mod.rs b/runtime/rust/prompty/tests/model/agent/mod.rs index b08de0af..c7d7ad39 100644 --- a/runtime/rust/prompty/tests/model/agent/mod.rs +++ b/runtime/rust/prompty/tests/model/agent/mod.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] -mod prompty_test; mod guardrail_result_test; +mod prompty_test; diff --git a/runtime/rust/prompty/tests/model/agent/prompty_test.rs b/runtime/rust/prompty/tests/model/agent/prompty_test.rs index f60e1409..f3f47d02 100644 --- a/runtime/rust/prompty/tests/model/agent/prompty_test.rs +++ b/runtime/rust/prompty/tests/model/agent/prompty_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::Prompty; use prompty::model::context::{LoadContext, SaveContext}; @@ -76,15 +83,34 @@ fn test_prompty_load_json() { "####; let ctx = LoadContext::default(); let result = Prompty::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.name, "basic-prompt"); - assert!(instance.display_name.is_some(), "Expected display_name to be Some"); + assert!( + instance.display_name.is_some(), + "Expected display_name to be Some" + ); assert_eq!(instance.display_name.as_ref().unwrap(), &"Basic Prompt"); - assert!(instance.description.is_some(), "Expected description to be Some"); - assert_eq!(instance.description.as_ref().unwrap(), &"A basic prompt that uses the GPT-3 chat API to answer questions"); - assert!(instance.instructions.is_some(), "Expected instructions to be Some"); - assert_eq!(instance.instructions.as_ref().unwrap(), &"system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}"); + assert!( + instance.description.is_some(), + "Expected description to be Some" + ); + assert_eq!( + instance.description.as_ref().unwrap(), + &"A basic prompt that uses the GPT-3 chat API to answer questions" + ); + assert!( + instance.instructions.is_some(), + "Expected instructions to be Some" + ); + assert_eq!( + instance.instructions.as_ref().unwrap(), + &"system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" + ); } #[test] @@ -158,12 +184,25 @@ instructions: "system: "####; let ctx = LoadContext::default(); let result = Prompty::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.name, "basic-prompt"); - assert!(instance.display_name.is_some(), "Expected display_name to be Some"); - assert!(instance.description.is_some(), "Expected description to be Some"); - assert!(instance.instructions.is_some(), "Expected instructions to be Some"); + assert!( + instance.display_name.is_some(), + "Expected display_name to be Some" + ); + assert!( + instance.description.is_some(), + "Expected description to be Some" + ); + assert!( + instance.instructions.is_some(), + "Expected instructions to be Some" + ); } #[test] @@ -241,7 +280,11 @@ fn test_prompty_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } #[test] @@ -314,15 +357,34 @@ fn test_prompty_load_json_1() { "####; let ctx = LoadContext::default(); let result = Prompty::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.name, "basic-prompt"); - assert!(instance.display_name.is_some(), "Expected display_name to be Some"); + assert!( + instance.display_name.is_some(), + "Expected display_name to be Some" + ); assert_eq!(instance.display_name.as_ref().unwrap(), &"Basic Prompt"); - assert!(instance.description.is_some(), "Expected description to be Some"); - assert_eq!(instance.description.as_ref().unwrap(), &"A basic prompt that uses the GPT-3 chat API to answer questions"); - assert!(instance.instructions.is_some(), "Expected instructions to be Some"); - assert_eq!(instance.instructions.as_ref().unwrap(), &"system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}"); + assert!( + instance.description.is_some(), + "Expected description to be Some" + ); + assert_eq!( + instance.description.as_ref().unwrap(), + &"A basic prompt that uses the GPT-3 chat API to answer questions" + ); + assert!( + instance.instructions.is_some(), + "Expected instructions to be Some" + ); + assert_eq!( + instance.instructions.as_ref().unwrap(), + &"system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" + ); } #[test] @@ -396,12 +458,25 @@ instructions: "system: "####; let ctx = LoadContext::default(); let result = Prompty::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.name, "basic-prompt"); - assert!(instance.display_name.is_some(), "Expected display_name to be Some"); - assert!(instance.description.is_some(), "Expected description to be Some"); - assert!(instance.instructions.is_some(), "Expected instructions to be Some"); + assert!( + instance.display_name.is_some(), + "Expected display_name to be Some" + ); + assert!( + instance.description.is_some(), + "Expected description to be Some" + ); + assert!( + instance.instructions.is_some(), + "Expected instructions to be Some" + ); } #[test] @@ -478,7 +553,11 @@ fn test_prompty_roundtrip_1() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } #[test] @@ -553,15 +632,34 @@ fn test_prompty_load_json_2() { "####; let ctx = LoadContext::default(); let result = Prompty::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.name, "basic-prompt"); - assert!(instance.display_name.is_some(), "Expected display_name to be Some"); + assert!( + instance.display_name.is_some(), + "Expected display_name to be Some" + ); assert_eq!(instance.display_name.as_ref().unwrap(), &"Basic Prompt"); - assert!(instance.description.is_some(), "Expected description to be Some"); - assert_eq!(instance.description.as_ref().unwrap(), &"A basic prompt that uses the GPT-3 chat API to answer questions"); - assert!(instance.instructions.is_some(), "Expected instructions to be Some"); - assert_eq!(instance.instructions.as_ref().unwrap(), &"system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}"); + assert!( + instance.description.is_some(), + "Expected description to be Some" + ); + assert_eq!( + instance.description.as_ref().unwrap(), + &"A basic prompt that uses the GPT-3 chat API to answer questions" + ); + assert!( + instance.instructions.is_some(), + "Expected instructions to be Some" + ); + assert_eq!( + instance.instructions.as_ref().unwrap(), + &"system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" + ); } #[test] @@ -635,12 +733,25 @@ instructions: "system: "####; let ctx = LoadContext::default(); let result = Prompty::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.name, "basic-prompt"); - assert!(instance.display_name.is_some(), "Expected display_name to be Some"); - assert!(instance.description.is_some(), "Expected description to be Some"); - assert!(instance.instructions.is_some(), "Expected instructions to be Some"); + assert!( + instance.display_name.is_some(), + "Expected display_name to be Some" + ); + assert!( + instance.description.is_some(), + "Expected description to be Some" + ); + assert!( + instance.instructions.is_some(), + "Expected instructions to be Some" + ); } #[test] @@ -719,7 +830,11 @@ fn test_prompty_roundtrip_2() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } #[test] @@ -793,15 +908,34 @@ fn test_prompty_load_json_3() { "####; let ctx = LoadContext::default(); let result = Prompty::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.name, "basic-prompt"); - assert!(instance.display_name.is_some(), "Expected display_name to be Some"); + assert!( + instance.display_name.is_some(), + "Expected display_name to be Some" + ); assert_eq!(instance.display_name.as_ref().unwrap(), &"Basic Prompt"); - assert!(instance.description.is_some(), "Expected description to be Some"); - assert_eq!(instance.description.as_ref().unwrap(), &"A basic prompt that uses the GPT-3 chat API to answer questions"); - assert!(instance.instructions.is_some(), "Expected instructions to be Some"); - assert_eq!(instance.instructions.as_ref().unwrap(), &"system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}"); + assert!( + instance.description.is_some(), + "Expected description to be Some" + ); + assert_eq!( + instance.description.as_ref().unwrap(), + &"A basic prompt that uses the GPT-3 chat API to answer questions" + ); + assert!( + instance.instructions.is_some(), + "Expected instructions to be Some" + ); + assert_eq!( + instance.instructions.as_ref().unwrap(), + &"system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" + ); } #[test] @@ -875,12 +1009,25 @@ instructions: "system: "####; let ctx = LoadContext::default(); let result = Prompty::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.name, "basic-prompt"); - assert!(instance.display_name.is_some(), "Expected display_name to be Some"); - assert!(instance.description.is_some(), "Expected description to be Some"); - assert!(instance.instructions.is_some(), "Expected instructions to be Some"); + assert!( + instance.display_name.is_some(), + "Expected display_name to be Some" + ); + assert!( + instance.description.is_some(), + "Expected description to be Some" + ); + assert!( + instance.instructions.is_some(), + "Expected instructions to be Some" + ); } #[test] @@ -958,7 +1105,11 @@ fn test_prompty_roundtrip_3() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } #[test] @@ -1035,15 +1186,34 @@ fn test_prompty_load_json_4() { "####; let ctx = LoadContext::default(); let result = Prompty::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.name, "basic-prompt"); - assert!(instance.display_name.is_some(), "Expected display_name to be Some"); + assert!( + instance.display_name.is_some(), + "Expected display_name to be Some" + ); assert_eq!(instance.display_name.as_ref().unwrap(), &"Basic Prompt"); - assert!(instance.description.is_some(), "Expected description to be Some"); - assert_eq!(instance.description.as_ref().unwrap(), &"A basic prompt that uses the GPT-3 chat API to answer questions"); - assert!(instance.instructions.is_some(), "Expected instructions to be Some"); - assert_eq!(instance.instructions.as_ref().unwrap(), &"system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}"); + assert!( + instance.description.is_some(), + "Expected description to be Some" + ); + assert_eq!( + instance.description.as_ref().unwrap(), + &"A basic prompt that uses the GPT-3 chat API to answer questions" + ); + assert!( + instance.instructions.is_some(), + "Expected instructions to be Some" + ); + assert_eq!( + instance.instructions.as_ref().unwrap(), + &"system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" + ); } #[test] @@ -1117,12 +1287,25 @@ instructions: "system: "####; let ctx = LoadContext::default(); let result = Prompty::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.name, "basic-prompt"); - assert!(instance.display_name.is_some(), "Expected display_name to be Some"); - assert!(instance.description.is_some(), "Expected description to be Some"); - assert!(instance.instructions.is_some(), "Expected instructions to be Some"); + assert!( + instance.display_name.is_some(), + "Expected display_name to be Some" + ); + assert!( + instance.description.is_some(), + "Expected description to be Some" + ); + assert!( + instance.instructions.is_some(), + "Expected instructions to be Some" + ); } #[test] @@ -1203,7 +1386,11 @@ fn test_prompty_roundtrip_4() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } #[test] @@ -1279,15 +1466,34 @@ fn test_prompty_load_json_5() { "####; let ctx = LoadContext::default(); let result = Prompty::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.name, "basic-prompt"); - assert!(instance.display_name.is_some(), "Expected display_name to be Some"); + assert!( + instance.display_name.is_some(), + "Expected display_name to be Some" + ); assert_eq!(instance.display_name.as_ref().unwrap(), &"Basic Prompt"); - assert!(instance.description.is_some(), "Expected description to be Some"); - assert_eq!(instance.description.as_ref().unwrap(), &"A basic prompt that uses the GPT-3 chat API to answer questions"); - assert!(instance.instructions.is_some(), "Expected instructions to be Some"); - assert_eq!(instance.instructions.as_ref().unwrap(), &"system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}"); + assert!( + instance.description.is_some(), + "Expected description to be Some" + ); + assert_eq!( + instance.description.as_ref().unwrap(), + &"A basic prompt that uses the GPT-3 chat API to answer questions" + ); + assert!( + instance.instructions.is_some(), + "Expected instructions to be Some" + ); + assert_eq!( + instance.instructions.as_ref().unwrap(), + &"system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" + ); } #[test] @@ -1361,12 +1567,25 @@ instructions: "system: "####; let ctx = LoadContext::default(); let result = Prompty::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.name, "basic-prompt"); - assert!(instance.display_name.is_some(), "Expected display_name to be Some"); - assert!(instance.description.is_some(), "Expected description to be Some"); - assert!(instance.instructions.is_some(), "Expected instructions to be Some"); + assert!( + instance.display_name.is_some(), + "Expected display_name to be Some" + ); + assert!( + instance.description.is_some(), + "Expected description to be Some" + ); + assert!( + instance.instructions.is_some(), + "Expected instructions to be Some" + ); } #[test] @@ -1446,7 +1665,11 @@ fn test_prompty_roundtrip_5() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } #[test] @@ -1524,15 +1747,34 @@ fn test_prompty_load_json_6() { "####; let ctx = LoadContext::default(); let result = Prompty::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.name, "basic-prompt"); - assert!(instance.display_name.is_some(), "Expected display_name to be Some"); + assert!( + instance.display_name.is_some(), + "Expected display_name to be Some" + ); assert_eq!(instance.display_name.as_ref().unwrap(), &"Basic Prompt"); - assert!(instance.description.is_some(), "Expected description to be Some"); - assert_eq!(instance.description.as_ref().unwrap(), &"A basic prompt that uses the GPT-3 chat API to answer questions"); - assert!(instance.instructions.is_some(), "Expected instructions to be Some"); - assert_eq!(instance.instructions.as_ref().unwrap(), &"system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}"); + assert!( + instance.description.is_some(), + "Expected description to be Some" + ); + assert_eq!( + instance.description.as_ref().unwrap(), + &"A basic prompt that uses the GPT-3 chat API to answer questions" + ); + assert!( + instance.instructions.is_some(), + "Expected instructions to be Some" + ); + assert_eq!( + instance.instructions.as_ref().unwrap(), + &"system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" + ); } #[test] @@ -1606,12 +1848,25 @@ instructions: "system: "####; let ctx = LoadContext::default(); let result = Prompty::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.name, "basic-prompt"); - assert!(instance.display_name.is_some(), "Expected display_name to be Some"); - assert!(instance.description.is_some(), "Expected description to be Some"); - assert!(instance.instructions.is_some(), "Expected instructions to be Some"); + assert!( + instance.display_name.is_some(), + "Expected display_name to be Some" + ); + assert!( + instance.description.is_some(), + "Expected description to be Some" + ); + assert!( + instance.instructions.is_some(), + "Expected instructions to be Some" + ); } #[test] @@ -1693,7 +1948,11 @@ fn test_prompty_roundtrip_6() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } #[test] @@ -1770,15 +2029,34 @@ fn test_prompty_load_json_7() { "####; let ctx = LoadContext::default(); let result = Prompty::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.name, "basic-prompt"); - assert!(instance.display_name.is_some(), "Expected display_name to be Some"); + assert!( + instance.display_name.is_some(), + "Expected display_name to be Some" + ); assert_eq!(instance.display_name.as_ref().unwrap(), &"Basic Prompt"); - assert!(instance.description.is_some(), "Expected description to be Some"); - assert_eq!(instance.description.as_ref().unwrap(), &"A basic prompt that uses the GPT-3 chat API to answer questions"); - assert!(instance.instructions.is_some(), "Expected instructions to be Some"); - assert_eq!(instance.instructions.as_ref().unwrap(), &"system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}"); + assert!( + instance.description.is_some(), + "Expected description to be Some" + ); + assert_eq!( + instance.description.as_ref().unwrap(), + &"A basic prompt that uses the GPT-3 chat API to answer questions" + ); + assert!( + instance.instructions.is_some(), + "Expected instructions to be Some" + ); + assert_eq!( + instance.instructions.as_ref().unwrap(), + &"system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" + ); } #[test] @@ -1852,12 +2130,25 @@ instructions: "system: "####; let ctx = LoadContext::default(); let result = Prompty::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.name, "basic-prompt"); - assert!(instance.display_name.is_some(), "Expected display_name to be Some"); - assert!(instance.description.is_some(), "Expected description to be Some"); - assert!(instance.instructions.is_some(), "Expected instructions to be Some"); + assert!( + instance.display_name.is_some(), + "Expected display_name to be Some" + ); + assert!( + instance.description.is_some(), + "Expected description to be Some" + ); + assert!( + instance.instructions.is_some(), + "Expected instructions to be Some" + ); } #[test] @@ -1938,5 +2229,9 @@ fn test_prompty_roundtrip_7() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/connection/connection_test.rs b/runtime/rust/prompty/tests/model/connection/connection_test.rs index 761b394c..8d267f97 100644 --- a/runtime/rust/prompty/tests/model/connection/connection_test.rs +++ b/runtime/rust/prompty/tests/model/connection/connection_test.rs @@ -1,9 +1,16 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] -use prompty::model::Connection; use prompty::model::AuthenticationMode; +use prompty::model::Connection; use prompty::model::context::{LoadContext, SaveContext}; #[test] @@ -17,7 +24,11 @@ fn test_connection_load_json() { "####; let ctx = LoadContext::default(); let result = Connection::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); } #[test] @@ -30,7 +41,11 @@ usageDescription: This will allow the agent to respond to an email on your behal "####; let ctx = LoadContext::default(); let result = Connection::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); } #[test] diff --git a/runtime/rust/prompty/tests/model/connection/mod.rs b/runtime/rust/prompty/tests/model/connection/mod.rs index 93848f6f..7edbe079 100644 --- a/runtime/rust/prompty/tests/model/connection/mod.rs +++ b/runtime/rust/prompty/tests/model/connection/mod.rs @@ -1,5 +1,12 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] mod connection_test; diff --git a/runtime/rust/prompty/tests/model/conversation/content_part_test.rs b/runtime/rust/prompty/tests/model/conversation/content_part_test.rs index c0b31726..0eb3b128 100644 --- a/runtime/rust/prompty/tests/model/conversation/content_part_test.rs +++ b/runtime/rust/prompty/tests/model/conversation/content_part_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::ContentPart; use prompty::model::context::{LoadContext, SaveContext}; diff --git a/runtime/rust/prompty/tests/model/conversation/message_test.rs b/runtime/rust/prompty/tests/model/conversation/message_test.rs index 1f6d48e7..a241f55e 100644 --- a/runtime/rust/prompty/tests/model/conversation/message_test.rs +++ b/runtime/rust/prompty/tests/model/conversation/message_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::Message; use prompty::model::Role; @@ -24,7 +31,11 @@ fn test_message_load_json() { "####; let ctx = LoadContext::default(); let result = Message::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.role, Role::User); } @@ -42,7 +53,11 @@ metadata: "####; let ctx = LoadContext::default(); let result = Message::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.role, Role::User); } @@ -69,7 +84,11 @@ fn test_message_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } #[test] diff --git a/runtime/rust/prompty/tests/model/conversation/mod.rs b/runtime/rust/prompty/tests/model/conversation/mod.rs index d53dcc22..57cf9d46 100644 --- a/runtime/rust/prompty/tests/model/conversation/mod.rs +++ b/runtime/rust/prompty/tests/model/conversation/mod.rs @@ -1,9 +1,16 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] mod content_part_test; mod message_test; -mod tool_result_test; -mod tool_call_test; mod thread_marker_test; +mod tool_call_test; +mod tool_result_test; diff --git a/runtime/rust/prompty/tests/model/conversation/thread_marker_test.rs b/runtime/rust/prompty/tests/model/conversation/thread_marker_test.rs index 172951e7..e87587b8 100644 --- a/runtime/rust/prompty/tests/model/conversation/thread_marker_test.rs +++ b/runtime/rust/prompty/tests/model/conversation/thread_marker_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::ThreadMarker; use prompty::model::context::{LoadContext, SaveContext}; @@ -15,7 +22,11 @@ fn test_thread_marker_load_json() { "####; let ctx = LoadContext::default(); let result = ThreadMarker::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.name, "thread"); assert_eq!(instance.kind, "thread"); @@ -30,7 +41,11 @@ kind: thread "####; let ctx = LoadContext::default(); let result = ThreadMarker::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.name, "thread"); assert_eq!(instance.kind, "thread"); @@ -50,5 +65,9 @@ fn test_thread_marker_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/conversation/tool_call_test.rs b/runtime/rust/prompty/tests/model/conversation/tool_call_test.rs index e7496125..9a1c8bcd 100644 --- a/runtime/rust/prompty/tests/model/conversation/tool_call_test.rs +++ b/runtime/rust/prompty/tests/model/conversation/tool_call_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::ToolCall; use prompty::model::context::{LoadContext, SaveContext}; @@ -16,7 +23,11 @@ fn test_tool_call_load_json() { "####; let ctx = LoadContext::default(); let result = ToolCall::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.id, "call_abc123"); assert_eq!(instance.name, "get_weather"); @@ -33,7 +44,11 @@ arguments: "{\"city\": \"Paris\"}" "####; let ctx = LoadContext::default(); let result = ToolCall::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.id, "call_abc123"); assert_eq!(instance.name, "get_weather"); @@ -55,5 +70,9 @@ fn test_tool_call_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/conversation/tool_result_test.rs b/runtime/rust/prompty/tests/model/conversation/tool_result_test.rs index 8ecb3460..f3a49b09 100644 --- a/runtime/rust/prompty/tests/model/conversation/tool_result_test.rs +++ b/runtime/rust/prompty/tests/model/conversation/tool_result_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::ToolResult; use prompty::model::ToolResultStatus; @@ -23,13 +30,29 @@ fn test_tool_result_load_json() { "####; let ctx = LoadContext::default(); let result = ToolResult::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); - assert!(instance.error_kind.is_some(), "Expected error_kind to be Some"); + assert!( + instance.error_kind.is_some(), + "Expected error_kind to be Some" + ); assert_eq!(instance.error_kind.as_ref().unwrap(), &"missing_tool"); - assert!(instance.error_message.is_some(), "Expected error_message to be Some"); - assert_eq!(instance.error_message.as_ref().unwrap(), &"Tool 'get_weather' is not registered"); - assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); + assert!( + instance.error_message.is_some(), + "Expected error_message to be Some" + ); + assert_eq!( + instance.error_message.as_ref().unwrap(), + &"Tool 'get_weather' is not registered" + ); + assert!( + instance.duration_ms.is_some(), + "Expected duration_ms to be Some" + ); assert_eq!(instance.duration_ms.as_ref().unwrap(), &42.0); } @@ -46,11 +69,24 @@ durationMs: 42 "####; let ctx = LoadContext::default(); let result = ToolResult::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); - assert!(instance.error_kind.is_some(), "Expected error_kind to be Some"); - assert!(instance.error_message.is_some(), "Expected error_message to be Some"); - assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); + assert!( + instance.error_kind.is_some(), + "Expected error_kind to be Some" + ); + assert!( + instance.error_message.is_some(), + "Expected error_message to be Some" + ); + assert!( + instance.duration_ms.is_some(), + "Expected duration_ms to be Some" + ); } #[test] @@ -74,7 +110,11 @@ fn test_tool_result_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } #[test] diff --git a/runtime/rust/prompty/tests/model/core/file_not_found_error_test.rs b/runtime/rust/prompty/tests/model/core/file_not_found_error_test.rs index 0feaca97..ffac0c98 100644 --- a/runtime/rust/prompty/tests/model/core/file_not_found_error_test.rs +++ b/runtime/rust/prompty/tests/model/core/file_not_found_error_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::FileNotFoundError; use prompty::model::context::{LoadContext, SaveContext}; @@ -15,7 +22,11 @@ fn test_file_not_found_error_load_json() { "####; let ctx = LoadContext::default(); let result = FileNotFoundError::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.message, "Prompty file not found: ./chat.prompty"); assert_eq!(instance.path, "./chat.prompty"); @@ -30,7 +41,11 @@ path: ./chat.prompty "####; let ctx = LoadContext::default(); let result = FileNotFoundError::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.message, "Prompty file not found: ./chat.prompty"); assert_eq!(instance.path, "./chat.prompty"); @@ -50,5 +65,9 @@ fn test_file_not_found_error_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/core/invoker_error_test.rs b/runtime/rust/prompty/tests/model/core/invoker_error_test.rs index 3c77c610..e22ac916 100644 --- a/runtime/rust/prompty/tests/model/core/invoker_error_test.rs +++ b/runtime/rust/prompty/tests/model/core/invoker_error_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::InvokerError; use prompty::model::context::{LoadContext, SaveContext}; @@ -16,7 +23,11 @@ fn test_invoker_error_load_json() { "####; let ctx = LoadContext::default(); let result = InvokerError::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.message, "No renderer registered for key: jinja2"); assert_eq!(instance.component, "renderer"); @@ -33,7 +44,11 @@ key: jinja2 "####; let ctx = LoadContext::default(); let result = InvokerError::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.message, "No renderer registered for key: jinja2"); assert_eq!(instance.component, "renderer"); @@ -55,5 +70,9 @@ fn test_invoker_error_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/core/mod.rs b/runtime/rust/prompty/tests/model/core/mod.rs index 8bebb9b8..761b53c2 100644 --- a/runtime/rust/prompty/tests/model/core/mod.rs +++ b/runtime/rust/prompty/tests/model/core/mod.rs @@ -1,9 +1,16 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] -mod property_test; +mod file_not_found_error_test; mod invoker_error_test; +mod property_test; mod validation_error_test; -mod file_not_found_error_test; mod validation_result_test; diff --git a/runtime/rust/prompty/tests/model/core/property_test.rs b/runtime/rust/prompty/tests/model/core/property_test.rs index c7d50165..ff146898 100644 --- a/runtime/rust/prompty/tests/model/core/property_test.rs +++ b/runtime/rust/prompty/tests/model/core/property_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::Property; use prompty::model::context::{LoadContext, SaveContext}; @@ -24,7 +31,11 @@ fn test_property_load_json() { "####; let ctx = LoadContext::default(); let result = Property::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); } #[test] @@ -44,7 +55,11 @@ enumValues: "####; let ctx = LoadContext::default(); let result = Property::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); } #[test] diff --git a/runtime/rust/prompty/tests/model/core/validation_error_test.rs b/runtime/rust/prompty/tests/model/core/validation_error_test.rs index 453f5968..93d1cad3 100644 --- a/runtime/rust/prompty/tests/model/core/validation_error_test.rs +++ b/runtime/rust/prompty/tests/model/core/validation_error_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::ValidationError; use prompty::model::context::{LoadContext, SaveContext}; @@ -16,7 +23,11 @@ fn test_validation_error_load_json() { "####; let ctx = LoadContext::default(); let result = ValidationError::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.message, "Missing required input: firstName"); assert_eq!(instance.property, "firstName"); @@ -33,7 +44,11 @@ constraint: required "####; let ctx = LoadContext::default(); let result = ValidationError::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.message, "Missing required input: firstName"); assert_eq!(instance.property, "firstName"); @@ -55,5 +70,9 @@ fn test_validation_error_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/core/validation_result_test.rs b/runtime/rust/prompty/tests/model/core/validation_result_test.rs index bcb1444a..6d823775 100644 --- a/runtime/rust/prompty/tests/model/core/validation_result_test.rs +++ b/runtime/rust/prompty/tests/model/core/validation_result_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::ValidationResult; use prompty::model::context::{LoadContext, SaveContext}; @@ -15,7 +22,11 @@ fn test_validation_result_load_json() { "####; let ctx = LoadContext::default(); let result = ValidationResult::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.valid, true); } @@ -29,7 +40,11 @@ errors: [] "####; let ctx = LoadContext::default(); let result = ValidationResult::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.valid, true); } @@ -48,5 +63,9 @@ fn test_validation_result_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/checkpoint_test.rs b/runtime/rust/prompty/tests/model/events/checkpoint_test.rs index f372e2e2..8f191240 100644 --- a/runtime/rust/prompty/tests/model/events/checkpoint_test.rs +++ b/runtime/rust/prompty/tests/model/events/checkpoint_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::Checkpoint; use prompty::model::context::{LoadContext, SaveContext}; @@ -19,19 +26,35 @@ fn test_checkpoint_load_json() { "####; let ctx = LoadContext::default(); let result = Checkpoint::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert!(instance.id.is_some(), "Expected id to be Some"); assert_eq!(instance.id.as_ref().unwrap(), &"chk_abc123"); - assert!(instance.session_id.is_some(), "Expected session_id to be Some"); + assert!( + instance.session_id.is_some(), + "Expected session_id to be Some" + ); assert_eq!(instance.session_id.as_ref().unwrap(), &"sess_abc123"); assert!(instance.turn_id.is_some(), "Expected turn_id to be Some"); assert_eq!(instance.turn_id.as_ref().unwrap(), &"turn_001"); - assert!(instance.checkpoint_number.is_some(), "Expected checkpoint_number to be Some"); + assert!( + instance.checkpoint_number.is_some(), + "Expected checkpoint_number to be Some" + ); assert_eq!(instance.checkpoint_number.as_ref().unwrap(), &3); assert_eq!(instance.title, "Added harness contracts"); - assert!(instance.created_at.is_some(), "Expected created_at to be Some"); - assert_eq!(instance.created_at.as_ref().unwrap(), &"2026-06-09T20:00:00Z"); + assert!( + instance.created_at.is_some(), + "Expected created_at to be Some" + ); + assert_eq!( + instance.created_at.as_ref().unwrap(), + &"2026-06-09T20:00:00Z" + ); } #[test] @@ -47,14 +70,27 @@ createdAt: "2026-06-09T20:00:00Z" "####; let ctx = LoadContext::default(); let result = Checkpoint::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert!(instance.id.is_some(), "Expected id to be Some"); - assert!(instance.session_id.is_some(), "Expected session_id to be Some"); + assert!( + instance.session_id.is_some(), + "Expected session_id to be Some" + ); assert!(instance.turn_id.is_some(), "Expected turn_id to be Some"); - assert!(instance.checkpoint_number.is_some(), "Expected checkpoint_number to be Some"); + assert!( + instance.checkpoint_number.is_some(), + "Expected checkpoint_number to be Some" + ); assert_eq!(instance.title, "Added harness contracts"); - assert!(instance.created_at.is_some(), "Expected created_at to be Some"); + assert!( + instance.created_at.is_some(), + "Expected created_at to be Some" + ); } #[test] @@ -75,5 +111,9 @@ fn test_checkpoint_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/compaction_complete_payload_test.rs b/runtime/rust/prompty/tests/model/events/compaction_complete_payload_test.rs index 7ad67317..adcf4c54 100644 --- a/runtime/rust/prompty/tests/model/events/compaction_complete_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/compaction_complete_payload_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::CompactionCompletePayload; use prompty::model::context::{LoadContext, SaveContext}; @@ -16,11 +23,18 @@ fn test_compaction_complete_payload_load_json() { "####; let ctx = LoadContext::default(); let result = CompactionCompletePayload::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.removed, 5); assert_eq!(instance.remaining, 3); - assert!(instance.summary_length.is_some(), "Expected summary_length to be Some"); + assert!( + instance.summary_length.is_some(), + "Expected summary_length to be Some" + ); assert_eq!(instance.summary_length.as_ref().unwrap(), &1200); } @@ -34,11 +48,18 @@ summaryLength: 1200 "####; let ctx = LoadContext::default(); let result = CompactionCompletePayload::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.removed, 5); assert_eq!(instance.remaining, 3); - assert!(instance.summary_length.is_some(), "Expected summary_length to be Some"); + assert!( + instance.summary_length.is_some(), + "Expected summary_length to be Some" + ); } #[test] @@ -56,5 +77,9 @@ fn test_compaction_complete_payload_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/compaction_failed_payload_test.rs b/runtime/rust/prompty/tests/model/events/compaction_failed_payload_test.rs index 058cf2a5..141562e0 100644 --- a/runtime/rust/prompty/tests/model/events/compaction_failed_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/compaction_failed_payload_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::CompactionFailedPayload; use prompty::model::context::{LoadContext, SaveContext}; @@ -14,9 +21,16 @@ fn test_compaction_failed_payload_load_json() { "####; let ctx = LoadContext::default(); let result = CompactionFailedPayload::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); - assert_eq!(instance.message, "Summarization prompt exceeded context window"); + assert_eq!( + instance.message, + "Summarization prompt exceeded context window" + ); } #[test] @@ -27,9 +41,16 @@ message: Summarization prompt exceeded context window "####; let ctx = LoadContext::default(); let result = CompactionFailedPayload::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); - assert_eq!(instance.message, "Summarization prompt exceeded context window"); + assert_eq!( + instance.message, + "Summarization prompt exceeded context window" + ); } #[test] @@ -45,5 +66,9 @@ fn test_compaction_failed_payload_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/compaction_start_payload_test.rs b/runtime/rust/prompty/tests/model/events/compaction_start_payload_test.rs index 1bd83c40..2b46d1a1 100644 --- a/runtime/rust/prompty/tests/model/events/compaction_start_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/compaction_start_payload_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::CompactionStartPayload; use prompty::model::context::{LoadContext, SaveContext}; @@ -14,7 +21,11 @@ fn test_compaction_start_payload_load_json() { "####; let ctx = LoadContext::default(); let result = CompactionStartPayload::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.dropped_count, 5); } @@ -27,7 +38,11 @@ droppedCount: 5 "####; let ctx = LoadContext::default(); let result = CompactionStartPayload::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.dropped_count, 5); } @@ -45,5 +60,9 @@ fn test_compaction_start_payload_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/done_event_payload_test.rs b/runtime/rust/prompty/tests/model/events/done_event_payload_test.rs index 709546f2..7faa654d 100644 --- a/runtime/rust/prompty/tests/model/events/done_event_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/done_event_payload_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::DoneEventPayload; use prompty::model::context::{LoadContext, SaveContext}; diff --git a/runtime/rust/prompty/tests/model/events/error_event_payload_test.rs b/runtime/rust/prompty/tests/model/events/error_event_payload_test.rs index ad6c1a09..c48341be 100644 --- a/runtime/rust/prompty/tests/model/events/error_event_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/error_event_payload_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::ErrorEventPayload; use prompty::model::context::{LoadContext, SaveContext}; @@ -16,10 +23,17 @@ fn test_error_event_payload_load_json() { "####; let ctx = LoadContext::default(); let result = ErrorEventPayload::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.message, "Rate limit exceeded"); - assert!(instance.error_kind.is_some(), "Expected error_kind to be Some"); + assert!( + instance.error_kind.is_some(), + "Expected error_kind to be Some" + ); assert_eq!(instance.error_kind.as_ref().unwrap(), &"rate_limit"); assert!(instance.phase.is_some(), "Expected phase to be Some"); assert_eq!(instance.phase.as_ref().unwrap(), &"llm"); @@ -35,10 +49,17 @@ phase: llm "####; let ctx = LoadContext::default(); let result = ErrorEventPayload::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.message, "Rate limit exceeded"); - assert!(instance.error_kind.is_some(), "Expected error_kind to be Some"); + assert!( + instance.error_kind.is_some(), + "Expected error_kind to be Some" + ); assert!(instance.phase.is_some(), "Expected phase to be Some"); } @@ -57,5 +78,9 @@ fn test_error_event_payload_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/harness_context_test.rs b/runtime/rust/prompty/tests/model/events/harness_context_test.rs index 721019e5..fab7d7c0 100644 --- a/runtime/rust/prompty/tests/model/events/harness_context_test.rs +++ b/runtime/rust/prompty/tests/model/events/harness_context_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::HarnessContext; use prompty::model::context::{LoadContext, SaveContext}; @@ -15,7 +22,11 @@ fn test_harness_context_load_json() { "####; let ctx = LoadContext::default(); let result = HarnessContext::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert!(instance.cwd.is_some(), "Expected cwd to be Some"); assert_eq!(instance.cwd.as_ref().unwrap(), &"/workspace/project"); @@ -32,7 +43,11 @@ gitRoot: /workspace/project "####; let ctx = LoadContext::default(); let result = HarnessContext::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert!(instance.cwd.is_some(), "Expected cwd to be Some"); assert!(instance.git_root.is_some(), "Expected git_root to be Some"); @@ -52,5 +67,9 @@ fn test_harness_context_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/hook_end_payload_test.rs b/runtime/rust/prompty/tests/model/events/hook_end_payload_test.rs index 69c2823b..9aadb782 100644 --- a/runtime/rust/prompty/tests/model/events/hook_end_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/hook_end_payload_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::HookEndPayload; use prompty::model::HookEndScope; @@ -19,12 +26,19 @@ fn test_hook_end_payload_load_json() { "####; let ctx = LoadContext::default(); let result = HookEndPayload::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.hook_invocation_id, "hook_abc123"); assert_eq!(instance.hook_type, "preToolUse"); assert_eq!(instance.success, true); - assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); + assert!( + instance.duration_ms.is_some(), + "Expected duration_ms to be Some" + ); assert_eq!(instance.duration_ms.as_ref().unwrap(), &12.0); assert!(instance.error.is_some(), "Expected error to be Some"); assert_eq!(instance.error.as_ref().unwrap(), &"hook failed"); @@ -42,12 +56,19 @@ error: hook failed "####; let ctx = LoadContext::default(); let result = HookEndPayload::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.hook_invocation_id, "hook_abc123"); assert_eq!(instance.hook_type, "preToolUse"); assert_eq!(instance.success, true); - assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); + assert!( + instance.duration_ms.is_some(), + "Expected duration_ms to be Some" + ); assert!(instance.error.is_some(), "Expected error to be Some"); } @@ -68,5 +89,9 @@ fn test_hook_end_payload_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/hook_start_payload_test.rs b/runtime/rust/prompty/tests/model/events/hook_start_payload_test.rs index bb0d14c7..3a62a2ad 100644 --- a/runtime/rust/prompty/tests/model/events/hook_start_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/hook_start_payload_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::HookStartPayload; use prompty::model::HookStartScope; @@ -16,7 +23,11 @@ fn test_hook_start_payload_load_json() { "####; let ctx = LoadContext::default(); let result = HookStartPayload::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.hook_invocation_id, "hook_abc123"); assert_eq!(instance.hook_type, "preToolUse"); @@ -31,7 +42,11 @@ hookType: preToolUse "####; let ctx = LoadContext::default(); let result = HookStartPayload::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.hook_invocation_id, "hook_abc123"); assert_eq!(instance.hook_type, "preToolUse"); @@ -51,5 +66,9 @@ fn test_hook_start_payload_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/host_tool_request_test.rs b/runtime/rust/prompty/tests/model/events/host_tool_request_test.rs index 99caee25..b5803bff 100644 --- a/runtime/rust/prompty/tests/model/events/host_tool_request_test.rs +++ b/runtime/rust/prompty/tests/model/events/host_tool_request_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::HostToolRequest; use prompty::model::context::{LoadContext, SaveContext}; @@ -17,15 +24,31 @@ fn test_host_tool_request_load_json() { "####; let ctx = LoadContext::default(); let result = HostToolRequest::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); - assert!(instance.request_id.is_some(), "Expected request_id to be Some"); + assert!( + instance.request_id.is_some(), + "Expected request_id to be Some" + ); assert_eq!(instance.request_id.as_ref().unwrap(), &"exec_abc123"); - assert!(instance.tool_call_id.is_some(), "Expected tool_call_id to be Some"); + assert!( + instance.tool_call_id.is_some(), + "Expected tool_call_id to be Some" + ); assert_eq!(instance.tool_call_id.as_ref().unwrap(), &"call_abc123"); assert_eq!(instance.tool_name, "powershell"); - assert!(instance.working_directory.is_some(), "Expected working_directory to be Some"); - assert_eq!(instance.working_directory.as_ref().unwrap(), &"/workspace/project"); + assert!( + instance.working_directory.is_some(), + "Expected working_directory to be Some" + ); + assert_eq!( + instance.working_directory.as_ref().unwrap(), + &"/workspace/project" + ); } #[test] @@ -39,12 +62,25 @@ workingDirectory: /workspace/project "####; let ctx = LoadContext::default(); let result = HostToolRequest::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); - assert!(instance.request_id.is_some(), "Expected request_id to be Some"); - assert!(instance.tool_call_id.is_some(), "Expected tool_call_id to be Some"); + assert!( + instance.request_id.is_some(), + "Expected request_id to be Some" + ); + assert!( + instance.tool_call_id.is_some(), + "Expected tool_call_id to be Some" + ); assert_eq!(instance.tool_name, "powershell"); - assert!(instance.working_directory.is_some(), "Expected working_directory to be Some"); + assert!( + instance.working_directory.is_some(), + "Expected working_directory to be Some" + ); } #[test] @@ -63,5 +99,9 @@ fn test_host_tool_request_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/host_tool_result_test.rs b/runtime/rust/prompty/tests/model/events/host_tool_result_test.rs index 85988f25..5c9692da 100644 --- a/runtime/rust/prompty/tests/model/events/host_tool_result_test.rs +++ b/runtime/rust/prompty/tests/model/events/host_tool_result_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::HostToolResult; use prompty::model::context::{LoadContext, SaveContext}; @@ -20,19 +27,38 @@ fn test_host_tool_result_load_json() { "####; let ctx = LoadContext::default(); let result = HostToolResult::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); - assert!(instance.request_id.is_some(), "Expected request_id to be Some"); + assert!( + instance.request_id.is_some(), + "Expected request_id to be Some" + ); assert_eq!(instance.request_id.as_ref().unwrap(), &"exec_abc123"); - assert!(instance.tool_call_id.is_some(), "Expected tool_call_id to be Some"); + assert!( + instance.tool_call_id.is_some(), + "Expected tool_call_id to be Some" + ); assert_eq!(instance.tool_call_id.as_ref().unwrap(), &"call_abc123"); assert_eq!(instance.tool_name, "powershell"); assert_eq!(instance.success, true); - assert!(instance.exit_code.is_some(), "Expected exit_code to be Some"); + assert!( + instance.exit_code.is_some(), + "Expected exit_code to be Some" + ); assert_eq!(instance.exit_code.as_ref().unwrap(), &0); - assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); + assert!( + instance.duration_ms.is_some(), + "Expected duration_ms to be Some" + ); assert_eq!(instance.duration_ms.as_ref().unwrap(), &250.0); - assert!(instance.error_kind.is_some(), "Expected error_kind to be Some"); + assert!( + instance.error_kind.is_some(), + "Expected error_kind to be Some" + ); assert_eq!(instance.error_kind.as_ref().unwrap(), &"timeout"); } @@ -50,15 +76,34 @@ errorKind: timeout "####; let ctx = LoadContext::default(); let result = HostToolResult::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); - assert!(instance.request_id.is_some(), "Expected request_id to be Some"); - assert!(instance.tool_call_id.is_some(), "Expected tool_call_id to be Some"); + assert!( + instance.request_id.is_some(), + "Expected request_id to be Some" + ); + assert!( + instance.tool_call_id.is_some(), + "Expected tool_call_id to be Some" + ); assert_eq!(instance.tool_name, "powershell"); assert_eq!(instance.success, true); - assert!(instance.exit_code.is_some(), "Expected exit_code to be Some"); - assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); - assert!(instance.error_kind.is_some(), "Expected error_kind to be Some"); + assert!( + instance.exit_code.is_some(), + "Expected exit_code to be Some" + ); + assert!( + instance.duration_ms.is_some(), + "Expected duration_ms to be Some" + ); + assert!( + instance.error_kind.is_some(), + "Expected error_kind to be Some" + ); } #[test] @@ -80,5 +125,9 @@ fn test_host_tool_result_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/llm_complete_payload_test.rs b/runtime/rust/prompty/tests/model/events/llm_complete_payload_test.rs index 986a82f1..d8684275 100644 --- a/runtime/rust/prompty/tests/model/events/llm_complete_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/llm_complete_payload_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::LlmCompletePayload; use prompty::model::context::{LoadContext, SaveContext}; @@ -16,13 +23,26 @@ fn test_llm_complete_payload_load_json() { "####; let ctx = LoadContext::default(); let result = LlmCompletePayload::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); - assert!(instance.request_id.is_some(), "Expected request_id to be Some"); + assert!( + instance.request_id.is_some(), + "Expected request_id to be Some" + ); assert_eq!(instance.request_id.as_ref().unwrap(), &"req_abc123"); - assert!(instance.service_request_id.is_some(), "Expected service_request_id to be Some"); + assert!( + instance.service_request_id.is_some(), + "Expected service_request_id to be Some" + ); assert_eq!(instance.service_request_id.as_ref().unwrap(), &"srv_abc123"); - assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); + assert!( + instance.duration_ms.is_some(), + "Expected duration_ms to be Some" + ); assert_eq!(instance.duration_ms.as_ref().unwrap(), &820.0); } @@ -36,11 +56,24 @@ durationMs: 820 "####; let ctx = LoadContext::default(); let result = LlmCompletePayload::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); - assert!(instance.request_id.is_some(), "Expected request_id to be Some"); - assert!(instance.service_request_id.is_some(), "Expected service_request_id to be Some"); - assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); + assert!( + instance.request_id.is_some(), + "Expected request_id to be Some" + ); + assert!( + instance.service_request_id.is_some(), + "Expected service_request_id to be Some" + ); + assert!( + instance.duration_ms.is_some(), + "Expected duration_ms to be Some" + ); } #[test] @@ -58,5 +91,9 @@ fn test_llm_complete_payload_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/llm_start_payload_test.rs b/runtime/rust/prompty/tests/model/events/llm_start_payload_test.rs index 04668742..d4896bae 100644 --- a/runtime/rust/prompty/tests/model/events/llm_start_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/llm_start_payload_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::LlmStartPayload; use prompty::model::context::{LoadContext, SaveContext}; @@ -17,13 +24,20 @@ fn test_llm_start_payload_load_json() { "####; let ctx = LoadContext::default(); let result = LlmStartPayload::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert!(instance.provider.is_some(), "Expected provider to be Some"); assert_eq!(instance.provider.as_ref().unwrap(), &"openai"); assert!(instance.model_id.is_some(), "Expected model_id to be Some"); assert_eq!(instance.model_id.as_ref().unwrap(), &"gpt-4o-mini"); - assert!(instance.message_count.is_some(), "Expected message_count to be Some"); + assert!( + instance.message_count.is_some(), + "Expected message_count to be Some" + ); assert_eq!(instance.message_count.as_ref().unwrap(), &4); assert!(instance.attempt.is_some(), "Expected attempt to be Some"); assert_eq!(instance.attempt.as_ref().unwrap(), &0); @@ -40,11 +54,18 @@ attempt: 0 "####; let ctx = LoadContext::default(); let result = LlmStartPayload::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert!(instance.provider.is_some(), "Expected provider to be Some"); assert!(instance.model_id.is_some(), "Expected model_id to be Some"); - assert!(instance.message_count.is_some(), "Expected message_count to be Some"); + assert!( + instance.message_count.is_some(), + "Expected message_count to be Some" + ); assert!(instance.attempt.is_some(), "Expected attempt to be Some"); } @@ -64,5 +85,9 @@ fn test_llm_start_payload_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/messages_updated_payload_test.rs b/runtime/rust/prompty/tests/model/events/messages_updated_payload_test.rs index a8610e58..ff19fb47 100644 --- a/runtime/rust/prompty/tests/model/events/messages_updated_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/messages_updated_payload_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::MessagesUpdatedPayload; use prompty::model::context::{LoadContext, SaveContext}; @@ -15,7 +22,11 @@ fn test_messages_updated_payload_load_json() { "####; let ctx = LoadContext::default(); let result = MessagesUpdatedPayload::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert!(instance.reason.is_some(), "Expected reason to be Some"); assert_eq!(instance.reason.as_ref().unwrap(), &"tool_results"); @@ -32,7 +43,11 @@ removed: 2 "####; let ctx = LoadContext::default(); let result = MessagesUpdatedPayload::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert!(instance.reason.is_some(), "Expected reason to be Some"); assert!(instance.removed.is_some(), "Expected removed to be Some"); @@ -52,5 +67,9 @@ fn test_messages_updated_payload_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/mod.rs b/runtime/rust/prompty/tests/model/events/mod.rs index 229103f1..24bf6570 100644 --- a/runtime/rust/prompty/tests/model/events/mod.rs +++ b/runtime/rust/prompty/tests/model/events/mod.rs @@ -1,48 +1,55 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] -mod turn_event_test; -mod turn_start_payload_test; -mod turn_end_payload_test; -mod llm_start_payload_test; -mod llm_complete_payload_test; -mod retry_payload_test; -mod redacted_field_test; -mod redaction_metadata_test; -mod permission_requested_payload_test; -mod permission_completed_payload_test; -mod permission_request_test; -mod permission_decision_test; -mod token_event_payload_test; -mod thinking_event_payload_test; -mod tool_call_start_payload_test; -mod tool_call_complete_payload_test; -mod tool_execution_start_payload_test; -mod tool_execution_complete_payload_test; -mod host_tool_request_test; -mod host_tool_result_test; -mod hook_start_payload_test; -mod hook_end_payload_test; -mod tool_result_payload_test; -mod status_event_payload_test; -mod messages_updated_payload_test; -mod done_event_payload_test; -mod error_event_payload_test; -mod compaction_start_payload_test; +mod checkpoint_test; mod compaction_complete_payload_test; mod compaction_failed_payload_test; -mod turn_summary_test; -mod turn_trace_test; +mod compaction_start_payload_test; +mod done_event_payload_test; +mod error_event_payload_test; mod harness_context_test; -mod session_start_payload_test; +mod hook_end_payload_test; +mod hook_start_payload_test; +mod host_tool_request_test; +mod host_tool_result_test; +mod llm_complete_payload_test; +mod llm_start_payload_test; +mod messages_updated_payload_test; +mod permission_completed_payload_test; +mod permission_decision_test; +mod permission_request_test; +mod permission_requested_payload_test; +mod redacted_field_test; +mod redaction_metadata_test; +mod retry_payload_test; mod session_end_payload_test; -mod session_warning_payload_test; mod session_event_test; -mod checkpoint_test; -mod trajectory_event_test; mod session_file_ref_test; mod session_ref_test; +mod session_start_payload_test; mod session_summary_test; mod session_trace_test; +mod session_warning_payload_test; +mod status_event_payload_test; mod stream_chunk_test; +mod thinking_event_payload_test; +mod token_event_payload_test; +mod tool_call_complete_payload_test; +mod tool_call_start_payload_test; +mod tool_execution_complete_payload_test; +mod tool_execution_start_payload_test; +mod tool_result_payload_test; +mod trajectory_event_test; +mod turn_end_payload_test; +mod turn_event_test; +mod turn_start_payload_test; +mod turn_summary_test; +mod turn_trace_test; diff --git a/runtime/rust/prompty/tests/model/events/permission_completed_payload_test.rs b/runtime/rust/prompty/tests/model/events/permission_completed_payload_test.rs index 128ed55b..a60ffae4 100644 --- a/runtime/rust/prompty/tests/model/events/permission_completed_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/permission_completed_payload_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::PermissionCompletedPayload; use prompty::model::context::{LoadContext, SaveContext}; @@ -18,11 +25,21 @@ fn test_permission_completed_payload_load_json() { "####; let ctx = LoadContext::default(); let result = PermissionCompletedPayload::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); - assert!(instance.request_id.is_some(), "Expected request_id to be Some"); + assert!( + instance.request_id.is_some(), + "Expected request_id to be Some" + ); assert_eq!(instance.request_id.as_ref().unwrap(), &"perm_abc123"); - assert!(instance.tool_call_id.is_some(), "Expected tool_call_id to be Some"); + assert!( + instance.tool_call_id.is_some(), + "Expected tool_call_id to be Some" + ); assert_eq!(instance.tool_call_id.as_ref().unwrap(), &"call_abc123"); assert_eq!(instance.permission, "tool.execute"); assert_eq!(instance.approved, true); @@ -42,10 +59,20 @@ reason: user_approved "####; let ctx = LoadContext::default(); let result = PermissionCompletedPayload::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); - assert!(instance.request_id.is_some(), "Expected request_id to be Some"); - assert!(instance.tool_call_id.is_some(), "Expected tool_call_id to be Some"); + assert!( + instance.request_id.is_some(), + "Expected request_id to be Some" + ); + assert!( + instance.tool_call_id.is_some(), + "Expected tool_call_id to be Some" + ); assert_eq!(instance.permission, "tool.execute"); assert_eq!(instance.approved, true); assert!(instance.reason.is_some(), "Expected reason to be Some"); @@ -68,5 +95,9 @@ fn test_permission_completed_payload_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/permission_decision_test.rs b/runtime/rust/prompty/tests/model/events/permission_decision_test.rs index eaef93f4..2740a8c2 100644 --- a/runtime/rust/prompty/tests/model/events/permission_decision_test.rs +++ b/runtime/rust/prompty/tests/model/events/permission_decision_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::PermissionDecision; use prompty::model::context::{LoadContext, SaveContext}; @@ -18,11 +25,21 @@ fn test_permission_decision_load_json() { "####; let ctx = LoadContext::default(); let result = PermissionDecision::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); - assert!(instance.request_id.is_some(), "Expected request_id to be Some"); + assert!( + instance.request_id.is_some(), + "Expected request_id to be Some" + ); assert_eq!(instance.request_id.as_ref().unwrap(), &"perm_abc123"); - assert!(instance.tool_call_id.is_some(), "Expected tool_call_id to be Some"); + assert!( + instance.tool_call_id.is_some(), + "Expected tool_call_id to be Some" + ); assert_eq!(instance.tool_call_id.as_ref().unwrap(), &"call_abc123"); assert_eq!(instance.permission, "tool.execute"); assert_eq!(instance.approved, true); @@ -42,10 +59,20 @@ reason: user_approved "####; let ctx = LoadContext::default(); let result = PermissionDecision::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); - assert!(instance.request_id.is_some(), "Expected request_id to be Some"); - assert!(instance.tool_call_id.is_some(), "Expected tool_call_id to be Some"); + assert!( + instance.request_id.is_some(), + "Expected request_id to be Some" + ); + assert!( + instance.tool_call_id.is_some(), + "Expected tool_call_id to be Some" + ); assert_eq!(instance.permission, "tool.execute"); assert_eq!(instance.approved, true); assert!(instance.reason.is_some(), "Expected reason to be Some"); @@ -68,5 +95,9 @@ fn test_permission_decision_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/permission_request_test.rs b/runtime/rust/prompty/tests/model/events/permission_request_test.rs index efbd6ecd..4257ec2d 100644 --- a/runtime/rust/prompty/tests/model/events/permission_request_test.rs +++ b/runtime/rust/prompty/tests/model/events/permission_request_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::PermissionRequest; use prompty::model::context::{LoadContext, SaveContext}; @@ -18,17 +25,33 @@ fn test_permission_request_load_json() { "####; let ctx = LoadContext::default(); let result = PermissionRequest::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); - assert!(instance.request_id.is_some(), "Expected request_id to be Some"); + assert!( + instance.request_id.is_some(), + "Expected request_id to be Some" + ); assert_eq!(instance.request_id.as_ref().unwrap(), &"perm_abc123"); - assert!(instance.tool_call_id.is_some(), "Expected tool_call_id to be Some"); + assert!( + instance.tool_call_id.is_some(), + "Expected tool_call_id to be Some" + ); assert_eq!(instance.tool_call_id.as_ref().unwrap(), &"call_abc123"); assert_eq!(instance.permission, "tool.execute"); assert!(instance.target.is_some(), "Expected target to be Some"); assert_eq!(instance.target.as_ref().unwrap(), &"shell"); - assert!(instance.prompt_request.is_some(), "Expected prompt_request to be Some"); - assert_eq!(instance.prompt_request.as_ref().unwrap(), &"Allow shell to run tests?"); + assert!( + instance.prompt_request.is_some(), + "Expected prompt_request to be Some" + ); + assert_eq!( + instance.prompt_request.as_ref().unwrap(), + &"Allow shell to run tests?" + ); } #[test] @@ -43,13 +66,26 @@ promptRequest: Allow shell to run tests? "####; let ctx = LoadContext::default(); let result = PermissionRequest::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); - assert!(instance.request_id.is_some(), "Expected request_id to be Some"); - assert!(instance.tool_call_id.is_some(), "Expected tool_call_id to be Some"); + assert!( + instance.request_id.is_some(), + "Expected request_id to be Some" + ); + assert!( + instance.tool_call_id.is_some(), + "Expected tool_call_id to be Some" + ); assert_eq!(instance.permission, "tool.execute"); assert!(instance.target.is_some(), "Expected target to be Some"); - assert!(instance.prompt_request.is_some(), "Expected prompt_request to be Some"); + assert!( + instance.prompt_request.is_some(), + "Expected prompt_request to be Some" + ); } #[test] @@ -69,5 +105,9 @@ fn test_permission_request_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/permission_requested_payload_test.rs b/runtime/rust/prompty/tests/model/events/permission_requested_payload_test.rs index 683c86a9..4a77781d 100644 --- a/runtime/rust/prompty/tests/model/events/permission_requested_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/permission_requested_payload_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::PermissionRequestedPayload; use prompty::model::context::{LoadContext, SaveContext}; @@ -18,17 +25,33 @@ fn test_permission_requested_payload_load_json() { "####; let ctx = LoadContext::default(); let result = PermissionRequestedPayload::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); - assert!(instance.request_id.is_some(), "Expected request_id to be Some"); + assert!( + instance.request_id.is_some(), + "Expected request_id to be Some" + ); assert_eq!(instance.request_id.as_ref().unwrap(), &"perm_abc123"); - assert!(instance.tool_call_id.is_some(), "Expected tool_call_id to be Some"); + assert!( + instance.tool_call_id.is_some(), + "Expected tool_call_id to be Some" + ); assert_eq!(instance.tool_call_id.as_ref().unwrap(), &"call_abc123"); assert_eq!(instance.permission, "tool.execute"); assert!(instance.target.is_some(), "Expected target to be Some"); assert_eq!(instance.target.as_ref().unwrap(), &"shell"); - assert!(instance.prompt_request.is_some(), "Expected prompt_request to be Some"); - assert_eq!(instance.prompt_request.as_ref().unwrap(), &"Allow shell to run tests?"); + assert!( + instance.prompt_request.is_some(), + "Expected prompt_request to be Some" + ); + assert_eq!( + instance.prompt_request.as_ref().unwrap(), + &"Allow shell to run tests?" + ); } #[test] @@ -43,13 +66,26 @@ promptRequest: Allow shell to run tests? "####; let ctx = LoadContext::default(); let result = PermissionRequestedPayload::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); - assert!(instance.request_id.is_some(), "Expected request_id to be Some"); - assert!(instance.tool_call_id.is_some(), "Expected tool_call_id to be Some"); + assert!( + instance.request_id.is_some(), + "Expected request_id to be Some" + ); + assert!( + instance.tool_call_id.is_some(), + "Expected tool_call_id to be Some" + ); assert_eq!(instance.permission, "tool.execute"); assert!(instance.target.is_some(), "Expected target to be Some"); - assert!(instance.prompt_request.is_some(), "Expected prompt_request to be Some"); + assert!( + instance.prompt_request.is_some(), + "Expected prompt_request to be Some" + ); } #[test] @@ -69,5 +105,9 @@ fn test_permission_requested_payload_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/redacted_field_test.rs b/runtime/rust/prompty/tests/model/events/redacted_field_test.rs index 41b1149a..f375c758 100644 --- a/runtime/rust/prompty/tests/model/events/redacted_field_test.rs +++ b/runtime/rust/prompty/tests/model/events/redacted_field_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::RedactedField; use prompty::model::RedactionMode; @@ -17,7 +24,11 @@ fn test_redacted_field_load_json() { "####; let ctx = LoadContext::default(); let result = RedactedField::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.path, "$.arguments.apiKey"); assert_eq!(instance.mode, RedactionMode::Redacted); @@ -35,7 +46,11 @@ reason: secret "####; let ctx = LoadContext::default(); let result = RedactedField::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.path, "$.arguments.apiKey"); assert_eq!(instance.mode, RedactionMode::Redacted); @@ -57,5 +72,9 @@ fn test_redacted_field_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/redaction_metadata_test.rs b/runtime/rust/prompty/tests/model/events/redaction_metadata_test.rs index 1aefe7df..4ee0d184 100644 --- a/runtime/rust/prompty/tests/model/events/redaction_metadata_test.rs +++ b/runtime/rust/prompty/tests/model/events/redaction_metadata_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::RedactionMetadata; use prompty::model::context::{LoadContext, SaveContext}; @@ -15,9 +22,16 @@ fn test_redaction_metadata_load_json() { "####; let ctx = LoadContext::default(); let result = RedactionMetadata::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); - assert!(instance.sanitized.is_some(), "Expected sanitized to be Some"); + assert!( + instance.sanitized.is_some(), + "Expected sanitized to be Some" + ); assert_eq!(instance.sanitized.as_ref().unwrap(), &true); assert!(instance.policy.is_some(), "Expected policy to be Some"); assert_eq!(instance.policy.as_ref().unwrap(), &"default-v1"); @@ -32,9 +46,16 @@ policy: default-v1 "####; let ctx = LoadContext::default(); let result = RedactionMetadata::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); - assert!(instance.sanitized.is_some(), "Expected sanitized to be Some"); + assert!( + instance.sanitized.is_some(), + "Expected sanitized to be Some" + ); assert!(instance.policy.is_some(), "Expected policy to be Some"); } @@ -52,5 +73,9 @@ fn test_redaction_metadata_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/retry_payload_test.rs b/runtime/rust/prompty/tests/model/events/retry_payload_test.rs index bf34585b..e9ad82c7 100644 --- a/runtime/rust/prompty/tests/model/events/retry_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/retry_payload_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::RetryPayload; use prompty::model::context::{LoadContext, SaveContext}; @@ -18,11 +25,18 @@ fn test_retry_payload_load_json() { "####; let ctx = LoadContext::default(); let result = RetryPayload::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.operation, "llm"); assert_eq!(instance.attempt, 2); - assert!(instance.max_attempts.is_some(), "Expected max_attempts to be Some"); + assert!( + instance.max_attempts.is_some(), + "Expected max_attempts to be Some" + ); assert_eq!(instance.max_attempts.as_ref().unwrap(), &3); assert!(instance.delay_ms.is_some(), "Expected delay_ms to be Some"); assert_eq!(instance.delay_ms.as_ref().unwrap(), &1250.0); @@ -42,11 +56,18 @@ reason: rate_limit "####; let ctx = LoadContext::default(); let result = RetryPayload::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.operation, "llm"); assert_eq!(instance.attempt, 2); - assert!(instance.max_attempts.is_some(), "Expected max_attempts to be Some"); + assert!( + instance.max_attempts.is_some(), + "Expected max_attempts to be Some" + ); assert!(instance.delay_ms.is_some(), "Expected delay_ms to be Some"); assert!(instance.reason.is_some(), "Expected reason to be Some"); } @@ -68,5 +89,9 @@ fn test_retry_payload_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/session_end_payload_test.rs b/runtime/rust/prompty/tests/model/events/session_end_payload_test.rs index 5568ff32..e82565a5 100644 --- a/runtime/rust/prompty/tests/model/events/session_end_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/session_end_payload_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::SessionEndPayload; use prompty::model::SessionEndStatus; @@ -18,15 +25,28 @@ fn test_session_end_payload_load_json() { "####; let ctx = LoadContext::default(); let result = SessionEndPayload::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); - assert!(instance.session_id.is_some(), "Expected session_id to be Some"); + assert!( + instance.session_id.is_some(), + "Expected session_id to be Some" + ); assert_eq!(instance.session_id.as_ref().unwrap(), &"sess_abc123"); assert!(instance.status.is_some(), "Expected status to be Some"); - assert_eq!(instance.status.as_ref().unwrap(), &SessionEndStatus::Success); + assert_eq!( + instance.status.as_ref().unwrap(), + &SessionEndStatus::Success + ); assert!(instance.reason.is_some(), "Expected reason to be Some"); assert_eq!(instance.reason.as_ref().unwrap(), &"complete"); - assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); + assert!( + instance.duration_ms.is_some(), + "Expected duration_ms to be Some" + ); assert_eq!(instance.duration_ms.as_ref().unwrap(), &12500.0); } @@ -41,12 +61,22 @@ durationMs: 12500 "####; let ctx = LoadContext::default(); let result = SessionEndPayload::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); - assert!(instance.session_id.is_some(), "Expected session_id to be Some"); + assert!( + instance.session_id.is_some(), + "Expected session_id to be Some" + ); assert!(instance.status.is_some(), "Expected status to be Some"); assert!(instance.reason.is_some(), "Expected reason to be Some"); - assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); + assert!( + instance.duration_ms.is_some(), + "Expected duration_ms to be Some" + ); } #[test] @@ -65,5 +95,9 @@ fn test_session_end_payload_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/session_event_test.rs b/runtime/rust/prompty/tests/model/events/session_event_test.rs index 20310ae3..8287d025 100644 --- a/runtime/rust/prompty/tests/model/events/session_event_test.rs +++ b/runtime/rust/prompty/tests/model/events/session_event_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::SessionEvent; use prompty::model::SessionEventType; @@ -20,15 +27,25 @@ fn test_session_event_load_json() { "####; let ctx = LoadContext::default(); let result = SessionEvent::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.id, "evt_abc123"); assert_eq!(instance.timestamp, "2026-06-09T20:00:00Z"); - assert!(instance.session_id.is_some(), "Expected session_id to be Some"); + assert!( + instance.session_id.is_some(), + "Expected session_id to be Some" + ); assert_eq!(instance.session_id.as_ref().unwrap(), &"sess_abc123"); assert!(instance.turn_id.is_some(), "Expected turn_id to be Some"); assert_eq!(instance.turn_id.as_ref().unwrap(), &"turn_001"); - assert!(instance.parent_id.is_some(), "Expected parent_id to be Some"); + assert!( + instance.parent_id.is_some(), + "Expected parent_id to be Some" + ); assert_eq!(instance.parent_id.as_ref().unwrap(), &"evt_parent"); assert!(instance.span_id.is_some(), "Expected span_id to be Some"); assert_eq!(instance.span_id.as_ref().unwrap(), &"span_hook_001"); @@ -47,13 +64,23 @@ spanId: span_hook_001 "####; let ctx = LoadContext::default(); let result = SessionEvent::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.id, "evt_abc123"); assert_eq!(instance.timestamp, "2026-06-09T20:00:00Z"); - assert!(instance.session_id.is_some(), "Expected session_id to be Some"); + assert!( + instance.session_id.is_some(), + "Expected session_id to be Some" + ); assert!(instance.turn_id.is_some(), "Expected turn_id to be Some"); - assert!(instance.parent_id.is_some(), "Expected parent_id to be Some"); + assert!( + instance.parent_id.is_some(), + "Expected parent_id to be Some" + ); assert!(instance.span_id.is_some(), "Expected span_id to be Some"); } @@ -75,5 +102,9 @@ fn test_session_event_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/session_file_ref_test.rs b/runtime/rust/prompty/tests/model/events/session_file_ref_test.rs index f91f7069..06bad9f3 100644 --- a/runtime/rust/prompty/tests/model/events/session_file_ref_test.rs +++ b/runtime/rust/prompty/tests/model/events/session_file_ref_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::SessionFileRef; use prompty::model::context::{LoadContext, SaveContext}; @@ -18,17 +25,36 @@ fn test_session_file_ref_load_json() { "####; let ctx = LoadContext::default(); let result = SessionFileRef::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); - assert!(instance.session_id.is_some(), "Expected session_id to be Some"); + assert!( + instance.session_id.is_some(), + "Expected session_id to be Some" + ); assert_eq!(instance.session_id.as_ref().unwrap(), &"sess_abc123"); assert_eq!(instance.path, "src/index.ts"); - assert!(instance.tool_name.is_some(), "Expected tool_name to be Some"); + assert!( + instance.tool_name.is_some(), + "Expected tool_name to be Some" + ); assert_eq!(instance.tool_name.as_ref().unwrap(), &"view"); - assert!(instance.turn_index.is_some(), "Expected turn_index to be Some"); + assert!( + instance.turn_index.is_some(), + "Expected turn_index to be Some" + ); assert_eq!(instance.turn_index.as_ref().unwrap(), &2); - assert!(instance.first_seen_at.is_some(), "Expected first_seen_at to be Some"); - assert_eq!(instance.first_seen_at.as_ref().unwrap(), &"2026-06-09T20:00:00Z"); + assert!( + instance.first_seen_at.is_some(), + "Expected first_seen_at to be Some" + ); + assert_eq!( + instance.first_seen_at.as_ref().unwrap(), + &"2026-06-09T20:00:00Z" + ); } #[test] @@ -43,13 +69,29 @@ firstSeenAt: "2026-06-09T20:00:00Z" "####; let ctx = LoadContext::default(); let result = SessionFileRef::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); - assert!(instance.session_id.is_some(), "Expected session_id to be Some"); + assert!( + instance.session_id.is_some(), + "Expected session_id to be Some" + ); assert_eq!(instance.path, "src/index.ts"); - assert!(instance.tool_name.is_some(), "Expected tool_name to be Some"); - assert!(instance.turn_index.is_some(), "Expected turn_index to be Some"); - assert!(instance.first_seen_at.is_some(), "Expected first_seen_at to be Some"); + assert!( + instance.tool_name.is_some(), + "Expected tool_name to be Some" + ); + assert!( + instance.turn_index.is_some(), + "Expected turn_index to be Some" + ); + assert!( + instance.first_seen_at.is_some(), + "Expected first_seen_at to be Some" + ); } #[test] @@ -69,5 +111,9 @@ fn test_session_file_ref_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/session_ref_test.rs b/runtime/rust/prompty/tests/model/events/session_ref_test.rs index 01812cae..82fb4bb4 100644 --- a/runtime/rust/prompty/tests/model/events/session_ref_test.rs +++ b/runtime/rust/prompty/tests/model/events/session_ref_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::SessionRef; use prompty::model::context::{LoadContext, SaveContext}; @@ -18,16 +25,32 @@ fn test_session_ref_load_json() { "####; let ctx = LoadContext::default(); let result = SessionRef::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); - assert!(instance.session_id.is_some(), "Expected session_id to be Some"); + assert!( + instance.session_id.is_some(), + "Expected session_id to be Some" + ); assert_eq!(instance.session_id.as_ref().unwrap(), &"sess_abc123"); assert_eq!(instance.ref_type, "issue"); assert_eq!(instance.ref_value, "owner/repo#123"); - assert!(instance.turn_index.is_some(), "Expected turn_index to be Some"); + assert!( + instance.turn_index.is_some(), + "Expected turn_index to be Some" + ); assert_eq!(instance.turn_index.as_ref().unwrap(), &2); - assert!(instance.created_at.is_some(), "Expected created_at to be Some"); - assert_eq!(instance.created_at.as_ref().unwrap(), &"2026-06-09T20:00:00Z"); + assert!( + instance.created_at.is_some(), + "Expected created_at to be Some" + ); + assert_eq!( + instance.created_at.as_ref().unwrap(), + &"2026-06-09T20:00:00Z" + ); } #[test] @@ -42,13 +65,26 @@ createdAt: "2026-06-09T20:00:00Z" "####; let ctx = LoadContext::default(); let result = SessionRef::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); - assert!(instance.session_id.is_some(), "Expected session_id to be Some"); + assert!( + instance.session_id.is_some(), + "Expected session_id to be Some" + ); assert_eq!(instance.ref_type, "issue"); assert_eq!(instance.ref_value, "owner/repo#123"); - assert!(instance.turn_index.is_some(), "Expected turn_index to be Some"); - assert!(instance.created_at.is_some(), "Expected created_at to be Some"); + assert!( + instance.turn_index.is_some(), + "Expected turn_index to be Some" + ); + assert!( + instance.created_at.is_some(), + "Expected created_at to be Some" + ); } #[test] @@ -68,5 +104,9 @@ fn test_session_ref_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/session_start_payload_test.rs b/runtime/rust/prompty/tests/model/events/session_start_payload_test.rs index 497a1173..8440d9d6 100644 --- a/runtime/rust/prompty/tests/model/events/session_start_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/session_start_payload_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::SessionStartPayload; use prompty::model::context::{LoadContext, SaveContext}; @@ -21,22 +28,44 @@ fn test_session_start_payload_load_json() { "####; let ctx = LoadContext::default(); let result = SessionStartPayload::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.session_id, "sess_abc123"); - assert!(instance.schema_version.is_some(), "Expected schema_version to be Some"); + assert!( + instance.schema_version.is_some(), + "Expected schema_version to be Some" + ); assert_eq!(instance.schema_version.as_ref().unwrap(), &"1"); assert!(instance.producer.is_some(), "Expected producer to be Some"); assert_eq!(instance.producer.as_ref().unwrap(), &"prompty-agent"); assert!(instance.runtime.is_some(), "Expected runtime to be Some"); assert_eq!(instance.runtime.as_ref().unwrap(), &"typescript"); - assert!(instance.prompty_version.is_some(), "Expected prompty_version to be Some"); + assert!( + instance.prompty_version.is_some(), + "Expected prompty_version to be Some" + ); assert_eq!(instance.prompty_version.as_ref().unwrap(), &"2.0.0"); - assert!(instance.start_time.is_some(), "Expected start_time to be Some"); - assert_eq!(instance.start_time.as_ref().unwrap(), &"2026-06-09T20:00:00Z"); - assert!(instance.selected_model.is_some(), "Expected selected_model to be Some"); + assert!( + instance.start_time.is_some(), + "Expected start_time to be Some" + ); + assert_eq!( + instance.start_time.as_ref().unwrap(), + &"2026-06-09T20:00:00Z" + ); + assert!( + instance.selected_model.is_some(), + "Expected selected_model to be Some" + ); assert_eq!(instance.selected_model.as_ref().unwrap(), &"gpt-4o-mini"); - assert!(instance.reasoning_effort.is_some(), "Expected reasoning_effort to be Some"); + assert!( + instance.reasoning_effort.is_some(), + "Expected reasoning_effort to be Some" + ); assert_eq!(instance.reasoning_effort.as_ref().unwrap(), &"medium"); } @@ -55,16 +84,35 @@ reasoningEffort: medium "####; let ctx = LoadContext::default(); let result = SessionStartPayload::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.session_id, "sess_abc123"); - assert!(instance.schema_version.is_some(), "Expected schema_version to be Some"); + assert!( + instance.schema_version.is_some(), + "Expected schema_version to be Some" + ); assert!(instance.producer.is_some(), "Expected producer to be Some"); assert!(instance.runtime.is_some(), "Expected runtime to be Some"); - assert!(instance.prompty_version.is_some(), "Expected prompty_version to be Some"); - assert!(instance.start_time.is_some(), "Expected start_time to be Some"); - assert!(instance.selected_model.is_some(), "Expected selected_model to be Some"); - assert!(instance.reasoning_effort.is_some(), "Expected reasoning_effort to be Some"); + assert!( + instance.prompty_version.is_some(), + "Expected prompty_version to be Some" + ); + assert!( + instance.start_time.is_some(), + "Expected start_time to be Some" + ); + assert!( + instance.selected_model.is_some(), + "Expected selected_model to be Some" + ); + assert!( + instance.reasoning_effort.is_some(), + "Expected reasoning_effort to be Some" + ); } #[test] @@ -87,5 +135,9 @@ fn test_session_start_payload_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/session_summary_test.rs b/runtime/rust/prompty/tests/model/events/session_summary_test.rs index 681fc56e..5c89287b 100644 --- a/runtime/rust/prompty/tests/model/events/session_summary_test.rs +++ b/runtime/rust/prompty/tests/model/events/session_summary_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::SessionSummary; use prompty::model::SessionSummaryStatus; @@ -19,16 +26,29 @@ fn test_session_summary_load_json() { "####; let ctx = LoadContext::default(); let result = SessionSummary::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.session_id, "sess_abc123"); assert!(instance.status.is_some(), "Expected status to be Some"); - assert_eq!(instance.status.as_ref().unwrap(), &SessionSummaryStatus::Success); + assert_eq!( + instance.status.as_ref().unwrap(), + &SessionSummaryStatus::Success + ); assert!(instance.turns.is_some(), "Expected turns to be Some"); assert_eq!(instance.turns.as_ref().unwrap(), &5); - assert!(instance.checkpoints.is_some(), "Expected checkpoints to be Some"); + assert!( + instance.checkpoints.is_some(), + "Expected checkpoints to be Some" + ); assert_eq!(instance.checkpoints.as_ref().unwrap(), &2); - assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); + assert!( + instance.duration_ms.is_some(), + "Expected duration_ms to be Some" + ); assert_eq!(instance.duration_ms.as_ref().unwrap(), &12500.0); } @@ -44,13 +64,23 @@ durationMs: 12500 "####; let ctx = LoadContext::default(); let result = SessionSummary::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.session_id, "sess_abc123"); assert!(instance.status.is_some(), "Expected status to be Some"); assert!(instance.turns.is_some(), "Expected turns to be Some"); - assert!(instance.checkpoints.is_some(), "Expected checkpoints to be Some"); - assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); + assert!( + instance.checkpoints.is_some(), + "Expected checkpoints to be Some" + ); + assert!( + instance.duration_ms.is_some(), + "Expected duration_ms to be Some" + ); } #[test] @@ -70,5 +100,9 @@ fn test_session_summary_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/session_trace_test.rs b/runtime/rust/prompty/tests/model/events/session_trace_test.rs index 9afd8886..80d05c74 100644 --- a/runtime/rust/prompty/tests/model/events/session_trace_test.rs +++ b/runtime/rust/prompty/tests/model/events/session_trace_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::SessionTrace; use prompty::model::context::{LoadContext, SaveContext}; @@ -17,14 +24,24 @@ fn test_session_trace_load_json() { "####; let ctx = LoadContext::default(); let result = SessionTrace::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.version, "1"); assert!(instance.runtime.is_some(), "Expected runtime to be Some"); assert_eq!(instance.runtime.as_ref().unwrap(), &"typescript"); - assert!(instance.prompty_version.is_some(), "Expected prompty_version to be Some"); + assert!( + instance.prompty_version.is_some(), + "Expected prompty_version to be Some" + ); assert_eq!(instance.prompty_version.as_ref().unwrap(), &"2.0.0"); - assert!(instance.session_id.is_some(), "Expected session_id to be Some"); + assert!( + instance.session_id.is_some(), + "Expected session_id to be Some" + ); assert_eq!(instance.session_id.as_ref().unwrap(), &"sess_abc123"); } @@ -39,12 +56,22 @@ sessionId: sess_abc123 "####; let ctx = LoadContext::default(); let result = SessionTrace::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.version, "1"); assert!(instance.runtime.is_some(), "Expected runtime to be Some"); - assert!(instance.prompty_version.is_some(), "Expected prompty_version to be Some"); - assert!(instance.session_id.is_some(), "Expected session_id to be Some"); + assert!( + instance.prompty_version.is_some(), + "Expected prompty_version to be Some" + ); + assert!( + instance.session_id.is_some(), + "Expected session_id to be Some" + ); } #[test] @@ -63,5 +90,9 @@ fn test_session_trace_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/session_warning_payload_test.rs b/runtime/rust/prompty/tests/model/events/session_warning_payload_test.rs index 56b2a90a..e451f490 100644 --- a/runtime/rust/prompty/tests/model/events/session_warning_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/session_warning_payload_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::SessionWarningPayload; use prompty::model::context::{LoadContext, SaveContext}; @@ -15,7 +22,11 @@ fn test_session_warning_payload_load_json() { "####; let ctx = LoadContext::default(); let result = SessionWarningPayload::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.warning_type, "remote"); assert_eq!(instance.message, "Remote session disabled"); @@ -30,7 +41,11 @@ message: Remote session disabled "####; let ctx = LoadContext::default(); let result = SessionWarningPayload::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.warning_type, "remote"); assert_eq!(instance.message, "Remote session disabled"); @@ -50,5 +65,9 @@ fn test_session_warning_payload_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/status_event_payload_test.rs b/runtime/rust/prompty/tests/model/events/status_event_payload_test.rs index 1b320341..2fcb936c 100644 --- a/runtime/rust/prompty/tests/model/events/status_event_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/status_event_payload_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::StatusEventPayload; use prompty::model::context::{LoadContext, SaveContext}; @@ -14,7 +21,11 @@ fn test_status_event_payload_load_json() { "####; let ctx = LoadContext::default(); let result = StatusEventPayload::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.message, "Starting iteration 3"); } @@ -27,7 +38,11 @@ message: Starting iteration 3 "####; let ctx = LoadContext::default(); let result = StatusEventPayload::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.message, "Starting iteration 3"); } @@ -45,5 +60,9 @@ fn test_status_event_payload_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/stream_chunk_test.rs b/runtime/rust/prompty/tests/model/events/stream_chunk_test.rs index efbdd847..5e094934 100644 --- a/runtime/rust/prompty/tests/model/events/stream_chunk_test.rs +++ b/runtime/rust/prompty/tests/model/events/stream_chunk_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::StreamChunk; use prompty::model::context::{LoadContext, SaveContext}; diff --git a/runtime/rust/prompty/tests/model/events/thinking_event_payload_test.rs b/runtime/rust/prompty/tests/model/events/thinking_event_payload_test.rs index 9f257dbd..b5e11822 100644 --- a/runtime/rust/prompty/tests/model/events/thinking_event_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/thinking_event_payload_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::ThinkingEventPayload; use prompty::model::context::{LoadContext, SaveContext}; @@ -14,7 +21,11 @@ fn test_thinking_event_payload_load_json() { "####; let ctx = LoadContext::default(); let result = ThinkingEventPayload::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.token, "Let me consider..."); } @@ -27,7 +38,11 @@ token: Let me consider... "####; let ctx = LoadContext::default(); let result = ThinkingEventPayload::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.token, "Let me consider..."); } @@ -45,5 +60,9 @@ fn test_thinking_event_payload_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/token_event_payload_test.rs b/runtime/rust/prompty/tests/model/events/token_event_payload_test.rs index b9b18c7a..523ac67a 100644 --- a/runtime/rust/prompty/tests/model/events/token_event_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/token_event_payload_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::TokenEventPayload; use prompty::model::context::{LoadContext, SaveContext}; @@ -14,7 +21,11 @@ fn test_token_event_payload_load_json() { "####; let ctx = LoadContext::default(); let result = TokenEventPayload::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.token, "Hello"); } @@ -27,7 +38,11 @@ token: Hello "####; let ctx = LoadContext::default(); let result = TokenEventPayload::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.token, "Hello"); } @@ -45,5 +60,9 @@ fn test_token_event_payload_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/tool_call_complete_payload_test.rs b/runtime/rust/prompty/tests/model/events/tool_call_complete_payload_test.rs index a63161a6..f1b7f804 100644 --- a/runtime/rust/prompty/tests/model/events/tool_call_complete_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/tool_call_complete_payload_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::ToolCallCompletePayload; use prompty::model::context::{LoadContext, SaveContext}; @@ -18,15 +25,25 @@ fn test_tool_call_complete_payload_load_json() { "####; let ctx = LoadContext::default(); let result = ToolCallCompletePayload::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert!(instance.id.is_some(), "Expected id to be Some"); assert_eq!(instance.id.as_ref().unwrap(), &"call_abc123"); assert_eq!(instance.name, "get_weather"); assert_eq!(instance.success, true); - assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); + assert!( + instance.duration_ms.is_some(), + "Expected duration_ms to be Some" + ); assert_eq!(instance.duration_ms.as_ref().unwrap(), &42.0); - assert!(instance.error_kind.is_some(), "Expected error_kind to be Some"); + assert!( + instance.error_kind.is_some(), + "Expected error_kind to be Some" + ); assert_eq!(instance.error_kind.as_ref().unwrap(), &"timeout"); } @@ -42,13 +59,23 @@ errorKind: timeout "####; let ctx = LoadContext::default(); let result = ToolCallCompletePayload::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert!(instance.id.is_some(), "Expected id to be Some"); assert_eq!(instance.name, "get_weather"); assert_eq!(instance.success, true); - assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); - assert!(instance.error_kind.is_some(), "Expected error_kind to be Some"); + assert!( + instance.duration_ms.is_some(), + "Expected duration_ms to be Some" + ); + assert!( + instance.error_kind.is_some(), + "Expected error_kind to be Some" + ); } #[test] @@ -68,5 +95,9 @@ fn test_tool_call_complete_payload_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/tool_call_start_payload_test.rs b/runtime/rust/prompty/tests/model/events/tool_call_start_payload_test.rs index 0230af03..bbcd5e72 100644 --- a/runtime/rust/prompty/tests/model/events/tool_call_start_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/tool_call_start_payload_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::ToolCallStartPayload; use prompty::model::context::{LoadContext, SaveContext}; @@ -16,7 +23,11 @@ fn test_tool_call_start_payload_load_json() { "####; let ctx = LoadContext::default(); let result = ToolCallStartPayload::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert!(instance.id.is_some(), "Expected id to be Some"); assert_eq!(instance.id.as_ref().unwrap(), &"call_abc123"); @@ -34,7 +45,11 @@ arguments: "{\"city\": \"Paris\"}" "####; let ctx = LoadContext::default(); let result = ToolCallStartPayload::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert!(instance.id.is_some(), "Expected id to be Some"); assert_eq!(instance.name, "get_weather"); @@ -56,5 +71,9 @@ fn test_tool_call_start_payload_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/tool_execution_complete_payload_test.rs b/runtime/rust/prompty/tests/model/events/tool_execution_complete_payload_test.rs index 57a58fc7..21deacf0 100644 --- a/runtime/rust/prompty/tests/model/events/tool_execution_complete_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/tool_execution_complete_payload_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::ToolExecutionCompletePayload; use prompty::model::context::{LoadContext, SaveContext}; @@ -20,19 +27,38 @@ fn test_tool_execution_complete_payload_load_json() { "####; let ctx = LoadContext::default(); let result = ToolExecutionCompletePayload::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); - assert!(instance.request_id.is_some(), "Expected request_id to be Some"); + assert!( + instance.request_id.is_some(), + "Expected request_id to be Some" + ); assert_eq!(instance.request_id.as_ref().unwrap(), &"exec_abc123"); - assert!(instance.tool_call_id.is_some(), "Expected tool_call_id to be Some"); + assert!( + instance.tool_call_id.is_some(), + "Expected tool_call_id to be Some" + ); assert_eq!(instance.tool_call_id.as_ref().unwrap(), &"call_abc123"); assert_eq!(instance.tool_name, "powershell"); assert_eq!(instance.success, true); - assert!(instance.exit_code.is_some(), "Expected exit_code to be Some"); + assert!( + instance.exit_code.is_some(), + "Expected exit_code to be Some" + ); assert_eq!(instance.exit_code.as_ref().unwrap(), &0); - assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); + assert!( + instance.duration_ms.is_some(), + "Expected duration_ms to be Some" + ); assert_eq!(instance.duration_ms.as_ref().unwrap(), &250.0); - assert!(instance.error_kind.is_some(), "Expected error_kind to be Some"); + assert!( + instance.error_kind.is_some(), + "Expected error_kind to be Some" + ); assert_eq!(instance.error_kind.as_ref().unwrap(), &"timeout"); } @@ -50,15 +76,34 @@ errorKind: timeout "####; let ctx = LoadContext::default(); let result = ToolExecutionCompletePayload::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); - assert!(instance.request_id.is_some(), "Expected request_id to be Some"); - assert!(instance.tool_call_id.is_some(), "Expected tool_call_id to be Some"); + assert!( + instance.request_id.is_some(), + "Expected request_id to be Some" + ); + assert!( + instance.tool_call_id.is_some(), + "Expected tool_call_id to be Some" + ); assert_eq!(instance.tool_name, "powershell"); assert_eq!(instance.success, true); - assert!(instance.exit_code.is_some(), "Expected exit_code to be Some"); - assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); - assert!(instance.error_kind.is_some(), "Expected error_kind to be Some"); + assert!( + instance.exit_code.is_some(), + "Expected exit_code to be Some" + ); + assert!( + instance.duration_ms.is_some(), + "Expected duration_ms to be Some" + ); + assert!( + instance.error_kind.is_some(), + "Expected error_kind to be Some" + ); } #[test] @@ -80,5 +125,9 @@ fn test_tool_execution_complete_payload_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/tool_execution_start_payload_test.rs b/runtime/rust/prompty/tests/model/events/tool_execution_start_payload_test.rs index a81ac534..1c475e2d 100644 --- a/runtime/rust/prompty/tests/model/events/tool_execution_start_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/tool_execution_start_payload_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::ToolExecutionStartPayload; use prompty::model::context::{LoadContext, SaveContext}; @@ -17,15 +24,31 @@ fn test_tool_execution_start_payload_load_json() { "####; let ctx = LoadContext::default(); let result = ToolExecutionStartPayload::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); - assert!(instance.request_id.is_some(), "Expected request_id to be Some"); + assert!( + instance.request_id.is_some(), + "Expected request_id to be Some" + ); assert_eq!(instance.request_id.as_ref().unwrap(), &"exec_abc123"); - assert!(instance.tool_call_id.is_some(), "Expected tool_call_id to be Some"); + assert!( + instance.tool_call_id.is_some(), + "Expected tool_call_id to be Some" + ); assert_eq!(instance.tool_call_id.as_ref().unwrap(), &"call_abc123"); assert_eq!(instance.tool_name, "powershell"); - assert!(instance.working_directory.is_some(), "Expected working_directory to be Some"); - assert_eq!(instance.working_directory.as_ref().unwrap(), &"/workspace/project"); + assert!( + instance.working_directory.is_some(), + "Expected working_directory to be Some" + ); + assert_eq!( + instance.working_directory.as_ref().unwrap(), + &"/workspace/project" + ); } #[test] @@ -39,12 +62,25 @@ workingDirectory: /workspace/project "####; let ctx = LoadContext::default(); let result = ToolExecutionStartPayload::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); - assert!(instance.request_id.is_some(), "Expected request_id to be Some"); - assert!(instance.tool_call_id.is_some(), "Expected tool_call_id to be Some"); + assert!( + instance.request_id.is_some(), + "Expected request_id to be Some" + ); + assert!( + instance.tool_call_id.is_some(), + "Expected tool_call_id to be Some" + ); assert_eq!(instance.tool_name, "powershell"); - assert!(instance.working_directory.is_some(), "Expected working_directory to be Some"); + assert!( + instance.working_directory.is_some(), + "Expected working_directory to be Some" + ); } #[test] @@ -63,5 +99,9 @@ fn test_tool_execution_start_payload_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/tool_result_payload_test.rs b/runtime/rust/prompty/tests/model/events/tool_result_payload_test.rs index 41b23d24..b08f41a8 100644 --- a/runtime/rust/prompty/tests/model/events/tool_result_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/tool_result_payload_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::ToolResultPayload; use prompty::model::context::{LoadContext, SaveContext}; @@ -22,7 +29,11 @@ fn test_tool_result_payload_load_json() { "####; let ctx = LoadContext::default(); let result = ToolResultPayload::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.name, "get_weather"); } @@ -39,7 +50,11 @@ result: "####; let ctx = LoadContext::default(); let result = ToolResultPayload::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.name, "get_weather"); } @@ -65,5 +80,9 @@ fn test_tool_result_payload_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/trajectory_event_test.rs b/runtime/rust/prompty/tests/model/events/trajectory_event_test.rs index 1b481f34..7cae8051 100644 --- a/runtime/rust/prompty/tests/model/events/trajectory_event_test.rs +++ b/runtime/rust/prompty/tests/model/events/trajectory_event_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::TrajectoryEvent; use prompty::model::context::{LoadContext, SaveContext}; @@ -20,21 +27,40 @@ fn test_trajectory_event_load_json() { "####; let ctx = LoadContext::default(); let result = TrajectoryEvent::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert!(instance.id.is_some(), "Expected id to be Some"); assert_eq!(instance.id.as_ref().unwrap(), &"traj_abc123"); - assert!(instance.session_id.is_some(), "Expected session_id to be Some"); + assert!( + instance.session_id.is_some(), + "Expected session_id to be Some" + ); assert_eq!(instance.session_id.as_ref().unwrap(), &"sess_abc123"); assert!(instance.turn_id.is_some(), "Expected turn_id to be Some"); assert_eq!(instance.turn_id.as_ref().unwrap(), &"turn_001"); - assert!(instance.tool_call_id.is_some(), "Expected tool_call_id to be Some"); + assert!( + instance.tool_call_id.is_some(), + "Expected tool_call_id to be Some" + ); assert_eq!(instance.tool_call_id.as_ref().unwrap(), &"call_abc123"); - assert!(instance.turn_index.is_some(), "Expected turn_index to be Some"); + assert!( + instance.turn_index.is_some(), + "Expected turn_index to be Some" + ); assert_eq!(instance.turn_index.as_ref().unwrap(), &4); assert_eq!(instance.event_type, "command"); - assert!(instance.created_at.is_some(), "Expected created_at to be Some"); - assert_eq!(instance.created_at.as_ref().unwrap(), &"2026-06-09T20:00:00Z"); + assert!( + instance.created_at.is_some(), + "Expected created_at to be Some" + ); + assert_eq!( + instance.created_at.as_ref().unwrap(), + &"2026-06-09T20:00:00Z" + ); } #[test] @@ -51,15 +77,31 @@ createdAt: "2026-06-09T20:00:00Z" "####; let ctx = LoadContext::default(); let result = TrajectoryEvent::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert!(instance.id.is_some(), "Expected id to be Some"); - assert!(instance.session_id.is_some(), "Expected session_id to be Some"); + assert!( + instance.session_id.is_some(), + "Expected session_id to be Some" + ); assert!(instance.turn_id.is_some(), "Expected turn_id to be Some"); - assert!(instance.tool_call_id.is_some(), "Expected tool_call_id to be Some"); - assert!(instance.turn_index.is_some(), "Expected turn_index to be Some"); + assert!( + instance.tool_call_id.is_some(), + "Expected tool_call_id to be Some" + ); + assert!( + instance.turn_index.is_some(), + "Expected turn_index to be Some" + ); assert_eq!(instance.event_type, "command"); - assert!(instance.created_at.is_some(), "Expected created_at to be Some"); + assert!( + instance.created_at.is_some(), + "Expected created_at to be Some" + ); } #[test] @@ -81,5 +123,9 @@ fn test_trajectory_event_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/turn_end_payload_test.rs b/runtime/rust/prompty/tests/model/events/turn_end_payload_test.rs index 76c884b0..e7323a2d 100644 --- a/runtime/rust/prompty/tests/model/events/turn_end_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/turn_end_payload_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::TurnEndPayload; use prompty::model::TurnStatus; @@ -16,11 +23,21 @@ fn test_turn_end_payload_load_json() { "####; let ctx = LoadContext::default(); let result = TurnEndPayload::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); - assert!(instance.iterations.is_some(), "Expected iterations to be Some"); + assert!( + instance.iterations.is_some(), + "Expected iterations to be Some" + ); assert_eq!(instance.iterations.as_ref().unwrap(), &2); - assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); + assert!( + instance.duration_ms.is_some(), + "Expected duration_ms to be Some" + ); assert_eq!(instance.duration_ms.as_ref().unwrap(), &1500.0); } @@ -33,10 +50,20 @@ durationMs: 1500 "####; let ctx = LoadContext::default(); let result = TurnEndPayload::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); - assert!(instance.iterations.is_some(), "Expected iterations to be Some"); - assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); + assert!( + instance.iterations.is_some(), + "Expected iterations to be Some" + ); + assert!( + instance.duration_ms.is_some(), + "Expected duration_ms to be Some" + ); } #[test] @@ -53,5 +80,9 @@ fn test_turn_end_payload_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/turn_event_test.rs b/runtime/rust/prompty/tests/model/events/turn_event_test.rs index 723d99ac..127e9b0d 100644 --- a/runtime/rust/prompty/tests/model/events/turn_event_test.rs +++ b/runtime/rust/prompty/tests/model/events/turn_event_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::TurnEvent; use prompty::model::TurnEventType; @@ -20,15 +27,25 @@ fn test_turn_event_load_json() { "####; let ctx = LoadContext::default(); let result = TurnEvent::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.id, "evt_abc123"); assert_eq!(instance.timestamp, "2026-06-09T20:00:00Z"); assert!(instance.turn_id.is_some(), "Expected turn_id to be Some"); assert_eq!(instance.turn_id.as_ref().unwrap(), &"turn_001"); - assert!(instance.iteration.is_some(), "Expected iteration to be Some"); + assert!( + instance.iteration.is_some(), + "Expected iteration to be Some" + ); assert_eq!(instance.iteration.as_ref().unwrap(), &0); - assert!(instance.parent_id.is_some(), "Expected parent_id to be Some"); + assert!( + instance.parent_id.is_some(), + "Expected parent_id to be Some" + ); assert_eq!(instance.parent_id.as_ref().unwrap(), &"evt_parent"); assert!(instance.span_id.is_some(), "Expected span_id to be Some"); assert_eq!(instance.span_id.as_ref().unwrap(), &"span_tool_001"); @@ -47,13 +64,23 @@ spanId: span_tool_001 "####; let ctx = LoadContext::default(); let result = TurnEvent::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.id, "evt_abc123"); assert_eq!(instance.timestamp, "2026-06-09T20:00:00Z"); assert!(instance.turn_id.is_some(), "Expected turn_id to be Some"); - assert!(instance.iteration.is_some(), "Expected iteration to be Some"); - assert!(instance.parent_id.is_some(), "Expected parent_id to be Some"); + assert!( + instance.iteration.is_some(), + "Expected iteration to be Some" + ); + assert!( + instance.parent_id.is_some(), + "Expected parent_id to be Some" + ); assert!(instance.span_id.is_some(), "Expected span_id to be Some"); } @@ -75,5 +102,9 @@ fn test_turn_event_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/turn_start_payload_test.rs b/runtime/rust/prompty/tests/model/events/turn_start_payload_test.rs index 7b93d282..b7e9e816 100644 --- a/runtime/rust/prompty/tests/model/events/turn_start_payload_test.rs +++ b/runtime/rust/prompty/tests/model/events/turn_start_payload_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::TurnStartPayload; use prompty::model::context::{LoadContext, SaveContext}; @@ -15,11 +22,18 @@ fn test_turn_start_payload_load_json() { "####; let ctx = LoadContext::default(); let result = TurnStartPayload::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert!(instance.agent.is_some(), "Expected agent to be Some"); assert_eq!(instance.agent.as_ref().unwrap(), &"weather-agent"); - assert!(instance.max_iterations.is_some(), "Expected max_iterations to be Some"); + assert!( + instance.max_iterations.is_some(), + "Expected max_iterations to be Some" + ); assert_eq!(instance.max_iterations.as_ref().unwrap(), &10); } @@ -32,10 +46,17 @@ maxIterations: 10 "####; let ctx = LoadContext::default(); let result = TurnStartPayload::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert!(instance.agent.is_some(), "Expected agent to be Some"); - assert!(instance.max_iterations.is_some(), "Expected max_iterations to be Some"); + assert!( + instance.max_iterations.is_some(), + "Expected max_iterations to be Some" + ); } #[test] @@ -52,5 +73,9 @@ fn test_turn_start_payload_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/turn_summary_test.rs b/runtime/rust/prompty/tests/model/events/turn_summary_test.rs index d807b04a..a400787f 100644 --- a/runtime/rust/prompty/tests/model/events/turn_summary_test.rs +++ b/runtime/rust/prompty/tests/model/events/turn_summary_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::TurnSummary; use prompty::model::context::{LoadContext, SaveContext}; @@ -20,18 +27,31 @@ fn test_turn_summary_load_json() { "####; let ctx = LoadContext::default(); let result = TurnSummary::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.turn_id, "turn_001"); assert_eq!(instance.status, "success"); assert_eq!(instance.iterations, 2); - assert!(instance.llm_calls.is_some(), "Expected llm_calls to be Some"); + assert!( + instance.llm_calls.is_some(), + "Expected llm_calls to be Some" + ); assert_eq!(instance.llm_calls.as_ref().unwrap(), &3); - assert!(instance.tool_calls.is_some(), "Expected tool_calls to be Some"); + assert!( + instance.tool_calls.is_some(), + "Expected tool_calls to be Some" + ); assert_eq!(instance.tool_calls.as_ref().unwrap(), &2); assert!(instance.retries.is_some(), "Expected retries to be Some"); assert_eq!(instance.retries.as_ref().unwrap(), &1); - assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); + assert!( + instance.duration_ms.is_some(), + "Expected duration_ms to be Some" + ); assert_eq!(instance.duration_ms.as_ref().unwrap(), &2500.0); } @@ -49,15 +69,28 @@ durationMs: 2500 "####; let ctx = LoadContext::default(); let result = TurnSummary::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.turn_id, "turn_001"); assert_eq!(instance.status, "success"); assert_eq!(instance.iterations, 2); - assert!(instance.llm_calls.is_some(), "Expected llm_calls to be Some"); - assert!(instance.tool_calls.is_some(), "Expected tool_calls to be Some"); + assert!( + instance.llm_calls.is_some(), + "Expected llm_calls to be Some" + ); + assert!( + instance.tool_calls.is_some(), + "Expected tool_calls to be Some" + ); assert!(instance.retries.is_some(), "Expected retries to be Some"); - assert!(instance.duration_ms.is_some(), "Expected duration_ms to be Some"); + assert!( + instance.duration_ms.is_some(), + "Expected duration_ms to be Some" + ); } #[test] @@ -79,5 +112,9 @@ fn test_turn_summary_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/events/turn_trace_test.rs b/runtime/rust/prompty/tests/model/events/turn_trace_test.rs index 21bceeda..beab6efd 100644 --- a/runtime/rust/prompty/tests/model/events/turn_trace_test.rs +++ b/runtime/rust/prompty/tests/model/events/turn_trace_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::TurnTrace; use prompty::model::context::{LoadContext, SaveContext}; @@ -16,12 +23,19 @@ fn test_turn_trace_load_json() { "####; let ctx = LoadContext::default(); let result = TurnTrace::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.version, "1"); assert!(instance.runtime.is_some(), "Expected runtime to be Some"); assert_eq!(instance.runtime.as_ref().unwrap(), &"typescript"); - assert!(instance.prompty_version.is_some(), "Expected prompty_version to be Some"); + assert!( + instance.prompty_version.is_some(), + "Expected prompty_version to be Some" + ); assert_eq!(instance.prompty_version.as_ref().unwrap(), &"2.0.0"); } @@ -35,11 +49,18 @@ promptyVersion: 2.0.0 "####; let ctx = LoadContext::default(); let result = TurnTrace::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.version, "1"); assert!(instance.runtime.is_some(), "Expected runtime to be Some"); - assert!(instance.prompty_version.is_some(), "Expected prompty_version to be Some"); + assert!( + instance.prompty_version.is_some(), + "Expected prompty_version to be Some" + ); } #[test] @@ -57,5 +78,9 @@ fn test_turn_trace_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/main.rs b/runtime/rust/prompty/tests/model/main.rs index fb66f889..fc601819 100644 --- a/runtime/rust/prompty/tests/model/main.rs +++ b/runtime/rust/prompty/tests/model/main.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] mod agent; mod connection; diff --git a/runtime/rust/prompty/tests/model/model/mod.rs b/runtime/rust/prompty/tests/model/model/mod.rs index e677e15a..411ab4a1 100644 --- a/runtime/rust/prompty/tests/model/model/mod.rs +++ b/runtime/rust/prompty/tests/model/model/mod.rs @@ -1,8 +1,15 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] +mod model_info_test; mod model_options_test; mod model_test; mod token_usage_test; -mod model_info_test; diff --git a/runtime/rust/prompty/tests/model/model/model_info_test.rs b/runtime/rust/prompty/tests/model/model/model_info_test.rs index 411a8cca..9e451027 100644 --- a/runtime/rust/prompty/tests/model/model/model_info_test.rs +++ b/runtime/rust/prompty/tests/model/model/model_info_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::ModelInfo; use prompty::model::context::{LoadContext, SaveContext}; @@ -27,14 +34,24 @@ fn test_model_info_load_json() { "####; let ctx = LoadContext::default(); let result = ModelInfo::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.id, "gpt-4o"); - assert!(instance.display_name.is_some(), "Expected display_name to be Some"); + assert!( + instance.display_name.is_some(), + "Expected display_name to be Some" + ); assert_eq!(instance.display_name.as_ref().unwrap(), &"GPT-4o"); assert!(instance.owned_by.is_some(), "Expected owned_by to be Some"); assert_eq!(instance.owned_by.as_ref().unwrap(), &"openai"); - assert!(instance.context_window.is_some(), "Expected context_window to be Some"); + assert!( + instance.context_window.is_some(), + "Expected context_window to be Some" + ); assert_eq!(instance.context_window.as_ref().unwrap(), &128000); } @@ -56,12 +73,22 @@ additionalProperties: "####; let ctx = LoadContext::default(); let result = ModelInfo::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.id, "gpt-4o"); - assert!(instance.display_name.is_some(), "Expected display_name to be Some"); + assert!( + instance.display_name.is_some(), + "Expected display_name to be Some" + ); assert!(instance.owned_by.is_some(), "Expected owned_by to be Some"); - assert!(instance.context_window.is_some(), "Expected context_window to be Some"); + assert!( + instance.context_window.is_some(), + "Expected context_window to be Some" + ); } #[test] @@ -90,5 +117,9 @@ fn test_model_info_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/model/model_options_test.rs b/runtime/rust/prompty/tests/model/model/model_options_test.rs index 677ef96f..33fb8613 100644 --- a/runtime/rust/prompty/tests/model/model/model_options_test.rs +++ b/runtime/rust/prompty/tests/model/model/model_options_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::ModelOptions; use prompty::model::context::{LoadContext, SaveContext}; @@ -29,23 +36,42 @@ fn test_model_options_load_json() { "####; let ctx = LoadContext::default(); let result = ModelOptions::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); - assert!(instance.frequency_penalty.is_some(), "Expected frequency_penalty to be Some"); + assert!( + instance.frequency_penalty.is_some(), + "Expected frequency_penalty to be Some" + ); assert_eq!(instance.frequency_penalty.as_ref().unwrap(), &0.5); - assert!(instance.max_output_tokens.is_some(), "Expected max_output_tokens to be Some"); + assert!( + instance.max_output_tokens.is_some(), + "Expected max_output_tokens to be Some" + ); assert_eq!(instance.max_output_tokens.as_ref().unwrap(), &2048); - assert!(instance.presence_penalty.is_some(), "Expected presence_penalty to be Some"); + assert!( + instance.presence_penalty.is_some(), + "Expected presence_penalty to be Some" + ); assert_eq!(instance.presence_penalty.as_ref().unwrap(), &0.3); assert!(instance.seed.is_some(), "Expected seed to be Some"); assert_eq!(instance.seed.as_ref().unwrap(), &42); - assert!(instance.temperature.is_some(), "Expected temperature to be Some"); + assert!( + instance.temperature.is_some(), + "Expected temperature to be Some" + ); assert_eq!(instance.temperature.as_ref().unwrap(), &0.7); assert!(instance.top_k.is_some(), "Expected top_k to be Some"); assert_eq!(instance.top_k.as_ref().unwrap(), &40); assert!(instance.top_p.is_some(), "Expected top_p to be Some"); assert_eq!(instance.top_p.as_ref().unwrap(), &0.9); - assert!(instance.allow_multiple_tool_calls.is_some(), "Expected allow_multiple_tool_calls to be Some"); + assert!( + instance.allow_multiple_tool_calls.is_some(), + "Expected allow_multiple_tool_calls to be Some" + ); assert_eq!(instance.allow_multiple_tool_calls.as_ref().unwrap(), &true); } @@ -70,16 +96,35 @@ additionalProperties: "####; let ctx = LoadContext::default(); let result = ModelOptions::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); - assert!(instance.frequency_penalty.is_some(), "Expected frequency_penalty to be Some"); - assert!(instance.max_output_tokens.is_some(), "Expected max_output_tokens to be Some"); - assert!(instance.presence_penalty.is_some(), "Expected presence_penalty to be Some"); + assert!( + instance.frequency_penalty.is_some(), + "Expected frequency_penalty to be Some" + ); + assert!( + instance.max_output_tokens.is_some(), + "Expected max_output_tokens to be Some" + ); + assert!( + instance.presence_penalty.is_some(), + "Expected presence_penalty to be Some" + ); assert!(instance.seed.is_some(), "Expected seed to be Some"); - assert!(instance.temperature.is_some(), "Expected temperature to be Some"); + assert!( + instance.temperature.is_some(), + "Expected temperature to be Some" + ); assert!(instance.top_k.is_some(), "Expected top_k to be Some"); assert!(instance.top_p.is_some(), "Expected top_p to be Some"); - assert!(instance.allow_multiple_tool_calls.is_some(), "Expected allow_multiple_tool_calls to be Some"); + assert!( + instance.allow_multiple_tool_calls.is_some(), + "Expected allow_multiple_tool_calls to be Some" + ); } #[test] @@ -110,5 +155,9 @@ fn test_model_options_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/model/model_test.rs b/runtime/rust/prompty/tests/model/model/model_test.rs index 7c9d0722..1fe28628 100644 --- a/runtime/rust/prompty/tests/model/model/model_test.rs +++ b/runtime/rust/prompty/tests/model/model/model_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::Model; use prompty::model::apiType; @@ -27,7 +34,11 @@ fn test_model_load_json() { "####; let ctx = LoadContext::default(); let result = Model::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.id, "gpt-35-turbo"); assert!(instance.provider.is_some(), "Expected provider to be Some"); @@ -54,7 +65,11 @@ options: "####; let ctx = LoadContext::default(); let result = Model::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.id, "gpt-35-turbo"); assert!(instance.provider.is_some(), "Expected provider to be Some"); @@ -86,7 +101,11 @@ fn test_model_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } #[test] diff --git a/runtime/rust/prompty/tests/model/model/token_usage_test.rs b/runtime/rust/prompty/tests/model/model/token_usage_test.rs index 1829a2b2..2234fc66 100644 --- a/runtime/rust/prompty/tests/model/model/token_usage_test.rs +++ b/runtime/rust/prompty/tests/model/model/token_usage_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::TokenUsage; use prompty::model::context::{LoadContext, SaveContext}; @@ -16,13 +23,26 @@ fn test_token_usage_load_json() { "####; let ctx = LoadContext::default(); let result = TokenUsage::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); - assert!(instance.prompt_tokens.is_some(), "Expected prompt_tokens to be Some"); + assert!( + instance.prompt_tokens.is_some(), + "Expected prompt_tokens to be Some" + ); assert_eq!(instance.prompt_tokens.as_ref().unwrap(), &150); - assert!(instance.completion_tokens.is_some(), "Expected completion_tokens to be Some"); + assert!( + instance.completion_tokens.is_some(), + "Expected completion_tokens to be Some" + ); assert_eq!(instance.completion_tokens.as_ref().unwrap(), &42); - assert!(instance.total_tokens.is_some(), "Expected total_tokens to be Some"); + assert!( + instance.total_tokens.is_some(), + "Expected total_tokens to be Some" + ); assert_eq!(instance.total_tokens.as_ref().unwrap(), &192); } @@ -36,11 +56,24 @@ totalTokens: 192 "####; let ctx = LoadContext::default(); let result = TokenUsage::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); - assert!(instance.prompt_tokens.is_some(), "Expected prompt_tokens to be Some"); - assert!(instance.completion_tokens.is_some(), "Expected completion_tokens to be Some"); - assert!(instance.total_tokens.is_some(), "Expected total_tokens to be Some"); + assert!( + instance.prompt_tokens.is_some(), + "Expected prompt_tokens to be Some" + ); + assert!( + instance.completion_tokens.is_some(), + "Expected completion_tokens to be Some" + ); + assert!( + instance.total_tokens.is_some(), + "Expected total_tokens to be Some" + ); } #[test] @@ -58,5 +91,9 @@ fn test_token_usage_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/pipeline/compaction_config_test.rs b/runtime/rust/prompty/tests/model/pipeline/compaction_config_test.rs index 10edc28c..23907e28 100644 --- a/runtime/rust/prompty/tests/model/pipeline/compaction_config_test.rs +++ b/runtime/rust/prompty/tests/model/pipeline/compaction_config_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::CompactionConfig; use prompty::model::context::{LoadContext, SaveContext}; @@ -18,7 +25,11 @@ fn test_compaction_config_load_json() { "####; let ctx = LoadContext::default(); let result = CompactionConfig::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert!(instance.strategy.is_some(), "Expected strategy to be Some"); assert_eq!(instance.strategy.as_ref().unwrap(), &"summarize"); @@ -37,7 +48,11 @@ options: "####; let ctx = LoadContext::default(); let result = CompactionConfig::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert!(instance.strategy.is_some(), "Expected strategy to be Some"); assert!(instance.budget.is_some(), "Expected budget to be Some"); @@ -60,5 +75,9 @@ fn test_compaction_config_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/pipeline/mod.rs b/runtime/rust/prompty/tests/model/pipeline/mod.rs index 5a3a85f7..dbbcc9a6 100644 --- a/runtime/rust/prompty/tests/model/pipeline/mod.rs +++ b/runtime/rust/prompty/tests/model/pipeline/mod.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] mod compaction_config_test; mod turn_options_test; diff --git a/runtime/rust/prompty/tests/model/pipeline/turn_options_test.rs b/runtime/rust/prompty/tests/model/pipeline/turn_options_test.rs index b2b2383e..791cad6c 100644 --- a/runtime/rust/prompty/tests/model/pipeline/turn_options_test.rs +++ b/runtime/rust/prompty/tests/model/pipeline/turn_options_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::TurnOptions; use prompty::model::context::{LoadContext, SaveContext}; @@ -22,15 +29,31 @@ fn test_turn_options_load_json() { "####; let ctx = LoadContext::default(); let result = TurnOptions::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); - assert!(instance.max_iterations.is_some(), "Expected max_iterations to be Some"); + assert!( + instance.max_iterations.is_some(), + "Expected max_iterations to be Some" + ); assert_eq!(instance.max_iterations.as_ref().unwrap(), &10); - assert!(instance.max_llm_retries.is_some(), "Expected max_llm_retries to be Some"); + assert!( + instance.max_llm_retries.is_some(), + "Expected max_llm_retries to be Some" + ); assert_eq!(instance.max_llm_retries.as_ref().unwrap(), &3); - assert!(instance.context_budget.is_some(), "Expected context_budget to be Some"); + assert!( + instance.context_budget.is_some(), + "Expected context_budget to be Some" + ); assert_eq!(instance.context_budget.as_ref().unwrap(), &100000); - assert!(instance.parallel_tool_calls.is_some(), "Expected parallel_tool_calls to be Some"); + assert!( + instance.parallel_tool_calls.is_some(), + "Expected parallel_tool_calls to be Some" + ); assert_eq!(instance.parallel_tool_calls.as_ref().unwrap(), &true); assert!(instance.raw.is_some(), "Expected raw to be Some"); assert_eq!(instance.raw.as_ref().unwrap(), &false); @@ -53,12 +76,28 @@ compaction: "####; let ctx = LoadContext::default(); let result = TurnOptions::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); - assert!(instance.max_iterations.is_some(), "Expected max_iterations to be Some"); - assert!(instance.max_llm_retries.is_some(), "Expected max_llm_retries to be Some"); - assert!(instance.context_budget.is_some(), "Expected context_budget to be Some"); - assert!(instance.parallel_tool_calls.is_some(), "Expected parallel_tool_calls to be Some"); + assert!( + instance.max_iterations.is_some(), + "Expected max_iterations to be Some" + ); + assert!( + instance.max_llm_retries.is_some(), + "Expected max_llm_retries to be Some" + ); + assert!( + instance.context_budget.is_some(), + "Expected context_budget to be Some" + ); + assert!( + instance.parallel_tool_calls.is_some(), + "Expected parallel_tool_calls to be Some" + ); assert!(instance.raw.is_some(), "Expected raw to be Some"); assert!(instance.turn.is_some(), "Expected turn to be Some"); } @@ -84,5 +123,9 @@ fn test_turn_options_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/streaming/mod.rs b/runtime/rust/prompty/tests/model/streaming/mod.rs index e1d58e14..9d4cc27b 100644 --- a/runtime/rust/prompty/tests/model/streaming/mod.rs +++ b/runtime/rust/prompty/tests/model/streaming/mod.rs @@ -1,5 +1,12 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] mod stream_options_test; diff --git a/runtime/rust/prompty/tests/model/streaming/stream_options_test.rs b/runtime/rust/prompty/tests/model/streaming/stream_options_test.rs index f5ff9962..ffa2241a 100644 --- a/runtime/rust/prompty/tests/model/streaming/stream_options_test.rs +++ b/runtime/rust/prompty/tests/model/streaming/stream_options_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::StreamOptions; use prompty::model::context::{LoadContext, SaveContext}; @@ -14,9 +21,16 @@ fn test_stream_options_load_json() { "####; let ctx = LoadContext::default(); let result = StreamOptions::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); - assert!(instance.include_usage.is_some(), "Expected include_usage to be Some"); + assert!( + instance.include_usage.is_some(), + "Expected include_usage to be Some" + ); assert_eq!(instance.include_usage.as_ref().unwrap(), &true); } @@ -28,9 +42,16 @@ includeUsage: true "####; let ctx = LoadContext::default(); let result = StreamOptions::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); - assert!(instance.include_usage.is_some(), "Expected include_usage to be Some"); + assert!( + instance.include_usage.is_some(), + "Expected include_usage to be Some" + ); } #[test] @@ -46,5 +67,9 @@ fn test_stream_options_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/template/format_config_test.rs b/runtime/rust/prompty/tests/model/template/format_config_test.rs index dcad8d7e..34a89108 100644 --- a/runtime/rust/prompty/tests/model/template/format_config_test.rs +++ b/runtime/rust/prompty/tests/model/template/format_config_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::FormatConfig; use prompty::model::context::{LoadContext, SaveContext}; @@ -18,7 +25,11 @@ fn test_format_config_load_json() { "####; let ctx = LoadContext::default(); let result = FormatConfig::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); } #[test] @@ -32,7 +43,11 @@ options: "####; let ctx = LoadContext::default(); let result = FormatConfig::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); } #[test] diff --git a/runtime/rust/prompty/tests/model/template/mod.rs b/runtime/rust/prompty/tests/model/template/mod.rs index e6e3c445..3e98998d 100644 --- a/runtime/rust/prompty/tests/model/template/mod.rs +++ b/runtime/rust/prompty/tests/model/template/mod.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] mod format_config_test; mod parser_config_test; diff --git a/runtime/rust/prompty/tests/model/template/parser_config_test.rs b/runtime/rust/prompty/tests/model/template/parser_config_test.rs index a5b96df1..1785b6ce 100644 --- a/runtime/rust/prompty/tests/model/template/parser_config_test.rs +++ b/runtime/rust/prompty/tests/model/template/parser_config_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::ParserConfig; use prompty::model::context::{LoadContext, SaveContext}; @@ -17,7 +24,11 @@ fn test_parser_config_load_json() { "####; let ctx = LoadContext::default(); let result = ParserConfig::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); } #[test] @@ -30,7 +41,11 @@ options: "####; let ctx = LoadContext::default(); let result = ParserConfig::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); } #[test] diff --git a/runtime/rust/prompty/tests/model/template/template_test.rs b/runtime/rust/prompty/tests/model/template/template_test.rs index 1da47b59..bc34bfc8 100644 --- a/runtime/rust/prompty/tests/model/template/template_test.rs +++ b/runtime/rust/prompty/tests/model/template/template_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::Template; use prompty::model::context::{LoadContext, SaveContext}; @@ -19,7 +26,11 @@ fn test_template_load_json() { "####; let ctx = LoadContext::default(); let result = Template::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); let _ = instance; // load succeeded, no scalar properties to validate } @@ -35,7 +46,11 @@ parser: "####; let ctx = LoadContext::default(); let result = Template::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); let _ = instance; // load succeeded, no scalar properties to validate } @@ -58,5 +73,9 @@ fn test_template_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/tools/binding_test.rs b/runtime/rust/prompty/tests/model/tools/binding_test.rs index 038b988d..d8f71fb1 100644 --- a/runtime/rust/prompty/tests/model/tools/binding_test.rs +++ b/runtime/rust/prompty/tests/model/tools/binding_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::Binding; use prompty::model::context::{LoadContext, SaveContext}; @@ -15,7 +22,11 @@ fn test_binding_load_json() { "####; let ctx = LoadContext::default(); let result = Binding::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.name, "my-tool"); assert_eq!(instance.input, "input-variable"); @@ -30,7 +41,11 @@ input: input-variable "####; let ctx = LoadContext::default(); let result = Binding::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.name, "my-tool"); assert_eq!(instance.input, "input-variable"); @@ -50,7 +65,11 @@ fn test_binding_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } #[test] diff --git a/runtime/rust/prompty/tests/model/tools/mcp_approval_mode_test.rs b/runtime/rust/prompty/tests/model/tools/mcp_approval_mode_test.rs index 68a98a9a..b20de138 100644 --- a/runtime/rust/prompty/tests/model/tools/mcp_approval_mode_test.rs +++ b/runtime/rust/prompty/tests/model/tools/mcp_approval_mode_test.rs @@ -1,10 +1,17 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::McpApprovalMode; -use prompty::model::mcpApprovalModeKind; use prompty::model::context::{LoadContext, SaveContext}; +use prompty::model::mcpApprovalModeKind; #[test] fn test_mcp_approval_mode_load_json() { @@ -21,7 +28,11 @@ fn test_mcp_approval_mode_load_json() { "####; let ctx = LoadContext::default(); let result = McpApprovalMode::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.kind, mcpApprovalModeKind::Never); } @@ -38,7 +49,11 @@ neverRequireApprovalTools: "####; let ctx = LoadContext::default(); let result = McpApprovalMode::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.kind, mcpApprovalModeKind::Never); } @@ -62,7 +77,11 @@ fn test_mcp_approval_mode_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } #[test] diff --git a/runtime/rust/prompty/tests/model/tools/mod.rs b/runtime/rust/prompty/tests/model/tools/mod.rs index fe5c4d63..469bdc71 100644 --- a/runtime/rust/prompty/tests/model/tools/mod.rs +++ b/runtime/rust/prompty/tests/model/tools/mod.rs @@ -1,9 +1,16 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] mod binding_test; -mod tool_test; mod mcp_approval_mode_test; mod tool_context_test; mod tool_dispatch_result_test; +mod tool_test; diff --git a/runtime/rust/prompty/tests/model/tools/tool_context_test.rs b/runtime/rust/prompty/tests/model/tools/tool_context_test.rs index 5945bb6f..80ebd6a0 100644 --- a/runtime/rust/prompty/tests/model/tools/tool_context_test.rs +++ b/runtime/rust/prompty/tests/model/tools/tool_context_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::ToolContext; use prompty::model::context::{LoadContext, SaveContext}; @@ -16,7 +23,11 @@ fn test_tool_context_load_json() { "####; let ctx = LoadContext::default(); let result = ToolContext::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); let _ = instance; // load succeeded, no scalar properties to validate } @@ -30,7 +41,11 @@ metadata: "####; let ctx = LoadContext::default(); let result = ToolContext::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); let _ = instance; // load succeeded, no scalar properties to validate } @@ -50,5 +65,9 @@ fn test_tool_context_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/tools/tool_dispatch_result_test.rs b/runtime/rust/prompty/tests/model/tools/tool_dispatch_result_test.rs index afe14769..c3b7e792 100644 --- a/runtime/rust/prompty/tests/model/tools/tool_dispatch_result_test.rs +++ b/runtime/rust/prompty/tests/model/tools/tool_dispatch_result_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::ToolDispatchResult; use prompty::model::context::{LoadContext, SaveContext}; @@ -23,7 +30,11 @@ fn test_tool_dispatch_result_load_json() { "####; let ctx = LoadContext::default(); let result = ToolDispatchResult::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.tool_call_id, "call_abc123"); assert_eq!(instance.name, "get_weather"); @@ -42,7 +53,11 @@ result: "####; let ctx = LoadContext::default(); let result = ToolDispatchResult::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.tool_call_id, "call_abc123"); assert_eq!(instance.name, "get_weather"); @@ -70,5 +85,9 @@ fn test_tool_dispatch_result_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/tools/tool_test.rs b/runtime/rust/prompty/tests/model/tools/tool_test.rs index 89aee4d4..1eb1648d 100644 --- a/runtime/rust/prompty/tests/model/tools/tool_test.rs +++ b/runtime/rust/prompty/tests/model/tools/tool_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::Tool; use prompty::model::context::{LoadContext, SaveContext}; @@ -19,7 +26,11 @@ fn test_tool_load_json() { "####; let ctx = LoadContext::default(); let result = Tool::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); } #[test] @@ -34,7 +45,11 @@ bindings: "####; let ctx = LoadContext::default(); let result = Tool::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); } #[test] diff --git a/runtime/rust/prompty/tests/model/tracing/mod.rs b/runtime/rust/prompty/tests/model/tracing/mod.rs index 449c1ad4..42c9ce80 100644 --- a/runtime/rust/prompty/tests/model/tracing/mod.rs +++ b/runtime/rust/prompty/tests/model/tracing/mod.rs @@ -1,7 +1,14 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] -mod trace_time_test; -mod trace_span_test; mod trace_file_test; +mod trace_span_test; +mod trace_time_test; diff --git a/runtime/rust/prompty/tests/model/tracing/trace_file_test.rs b/runtime/rust/prompty/tests/model/tracing/trace_file_test.rs index 390b2ed6..d4e3905f 100644 --- a/runtime/rust/prompty/tests/model/tracing/trace_file_test.rs +++ b/runtime/rust/prompty/tests/model/tracing/trace_file_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::TraceFile; use prompty::model::context::{LoadContext, SaveContext}; @@ -15,7 +22,11 @@ fn test_trace_file_load_json() { "####; let ctx = LoadContext::default(); let result = TraceFile::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.runtime, "python"); assert_eq!(instance.version, "2.0.0"); @@ -30,7 +41,11 @@ version: 2.0.0 "####; let ctx = LoadContext::default(); let result = TraceFile::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.runtime, "python"); assert_eq!(instance.version, "2.0.0"); @@ -50,5 +65,9 @@ fn test_trace_file_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/tracing/trace_span_test.rs b/runtime/rust/prompty/tests/model/tracing/trace_span_test.rs index 2f9448b8..a6f04c1e 100644 --- a/runtime/rust/prompty/tests/model/tracing/trace_span_test.rs +++ b/runtime/rust/prompty/tests/model/tracing/trace_span_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::TraceSpan; use prompty::model::context::{LoadContext, SaveContext}; @@ -16,11 +23,21 @@ fn test_trace_span_load_json() { "####; let ctx = LoadContext::default(); let result = TraceSpan::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.name, "prompty.core.pipeline.run"); - assert!(instance.signature.is_some(), "Expected signature to be Some"); - assert_eq!(instance.signature.as_ref().unwrap(), &"prompty.core.pipeline.run"); + assert!( + instance.signature.is_some(), + "Expected signature to be Some" + ); + assert_eq!( + instance.signature.as_ref().unwrap(), + &"prompty.core.pipeline.run" + ); assert!(instance.error.is_some(), "Expected error to be Some"); assert_eq!(instance.error.as_ref().unwrap(), &"Connection refused"); } @@ -35,10 +52,17 @@ error: Connection refused "####; let ctx = LoadContext::default(); let result = TraceSpan::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.name, "prompty.core.pipeline.run"); - assert!(instance.signature.is_some(), "Expected signature to be Some"); + assert!( + instance.signature.is_some(), + "Expected signature to be Some" + ); assert!(instance.error.is_some(), "Expected error to be Some"); } @@ -57,5 +81,9 @@ fn test_trace_span_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/tracing/trace_time_test.rs b/runtime/rust/prompty/tests/model/tracing/trace_time_test.rs index fcee85be..2b03e1b0 100644 --- a/runtime/rust/prompty/tests/model/tracing/trace_time_test.rs +++ b/runtime/rust/prompty/tests/model/tracing/trace_time_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::TraceTime; use prompty::model::context::{LoadContext, SaveContext}; @@ -16,7 +23,11 @@ fn test_trace_time_load_json() { "####; let ctx = LoadContext::default(); let result = TraceTime::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.start, "2026-04-04T12:00:00Z"); assert_eq!(instance.end, "2026-04-04T12:00:01Z"); @@ -33,7 +44,11 @@ duration: 1000 "####; let ctx = LoadContext::default(); let result = TraceTime::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.start, "2026-04-04T12:00:00Z"); assert_eq!(instance.end, "2026-04-04T12:00:01Z"); @@ -55,5 +70,9 @@ fn test_trace_time_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/wire/anthropic_image_block_test.rs b/runtime/rust/prompty/tests/model/wire/anthropic_image_block_test.rs index 95e5e90c..565836db 100644 --- a/runtime/rust/prompty/tests/model/wire/anthropic_image_block_test.rs +++ b/runtime/rust/prompty/tests/model/wire/anthropic_image_block_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::AnthropicImageBlock; use prompty::model::context::{LoadContext, SaveContext}; diff --git a/runtime/rust/prompty/tests/model/wire/anthropic_image_source_test.rs b/runtime/rust/prompty/tests/model/wire/anthropic_image_source_test.rs index 0bbf018c..089aa702 100644 --- a/runtime/rust/prompty/tests/model/wire/anthropic_image_source_test.rs +++ b/runtime/rust/prompty/tests/model/wire/anthropic_image_source_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::AnthropicImageSource; use prompty::model::context::{LoadContext, SaveContext}; @@ -15,7 +22,11 @@ fn test_anthropic_image_source_load_json() { "####; let ctx = LoadContext::default(); let result = AnthropicImageSource::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.media_type, "image/png"); assert_eq!(instance.data, "iVBORw0KGgo..."); @@ -30,7 +41,11 @@ data: iVBORw0KGgo... "####; let ctx = LoadContext::default(); let result = AnthropicImageSource::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.media_type, "image/png"); assert_eq!(instance.data, "iVBORw0KGgo..."); @@ -50,5 +65,9 @@ fn test_anthropic_image_source_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/wire/anthropic_messages_request_test.rs b/runtime/rust/prompty/tests/model/wire/anthropic_messages_request_test.rs index 99b35f90..e18311e7 100644 --- a/runtime/rust/prompty/tests/model/wire/anthropic_messages_request_test.rs +++ b/runtime/rust/prompty/tests/model/wire/anthropic_messages_request_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::AnthropicMessagesRequest; use prompty::model::context::{LoadContext, SaveContext}; @@ -22,13 +29,23 @@ fn test_anthropic_messages_request_load_json() { "####; let ctx = LoadContext::default(); let result = AnthropicMessagesRequest::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.model, "claude-sonnet-4-20250514"); assert_eq!(instance.max_tokens, 4096); assert!(instance.system.is_some(), "Expected system to be Some"); - assert_eq!(instance.system.as_ref().unwrap(), &"You are a helpful assistant."); - assert!(instance.temperature.is_some(), "Expected temperature to be Some"); + assert_eq!( + instance.system.as_ref().unwrap(), + &"You are a helpful assistant." + ); + assert!( + instance.temperature.is_some(), + "Expected temperature to be Some" + ); assert_eq!(instance.temperature.as_ref().unwrap(), &0.7); assert!(instance.top_p.is_some(), "Expected top_p to be Some"); assert_eq!(instance.top_p.as_ref().unwrap(), &0.9); @@ -51,12 +68,19 @@ stop_sequences: "####; let ctx = LoadContext::default(); let result = AnthropicMessagesRequest::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.model, "claude-sonnet-4-20250514"); assert_eq!(instance.max_tokens, 4096); assert!(instance.system.is_some(), "Expected system to be Some"); - assert!(instance.temperature.is_some(), "Expected temperature to be Some"); + assert!( + instance.temperature.is_some(), + "Expected temperature to be Some" + ); assert!(instance.top_p.is_some(), "Expected top_p to be Some"); assert!(instance.top_k.is_some(), "Expected top_k to be Some"); } @@ -82,5 +106,9 @@ fn test_anthropic_messages_request_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/wire/anthropic_messages_response_test.rs b/runtime/rust/prompty/tests/model/wire/anthropic_messages_response_test.rs index e5e3b93e..7d5ef69e 100644 --- a/runtime/rust/prompty/tests/model/wire/anthropic_messages_response_test.rs +++ b/runtime/rust/prompty/tests/model/wire/anthropic_messages_response_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::AnthropicMessagesResponse; use prompty::model::context::{LoadContext, SaveContext}; @@ -16,7 +23,11 @@ fn test_anthropic_messages_response_load_json() { "####; let ctx = LoadContext::default(); let result = AnthropicMessagesResponse::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.id, "msg_01XFDUDYJgAACzvnptvVoYEL"); assert_eq!(instance.model, "claude-sonnet-4-20250514"); @@ -33,7 +44,11 @@ stop_reason: end_turn "####; let ctx = LoadContext::default(); let result = AnthropicMessagesResponse::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.id, "msg_01XFDUDYJgAACzvnptvVoYEL"); assert_eq!(instance.model, "claude-sonnet-4-20250514"); @@ -55,5 +70,9 @@ fn test_anthropic_messages_response_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/wire/anthropic_text_block_test.rs b/runtime/rust/prompty/tests/model/wire/anthropic_text_block_test.rs index 5b2ce62a..0f5bd4bc 100644 --- a/runtime/rust/prompty/tests/model/wire/anthropic_text_block_test.rs +++ b/runtime/rust/prompty/tests/model/wire/anthropic_text_block_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::AnthropicTextBlock; use prompty::model::context::{LoadContext, SaveContext}; @@ -14,7 +21,11 @@ fn test_anthropic_text_block_load_json() { "####; let ctx = LoadContext::default(); let result = AnthropicTextBlock::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.text, "Hello, how can I help?"); } @@ -27,7 +38,11 @@ text: Hello, how can I help? "####; let ctx = LoadContext::default(); let result = AnthropicTextBlock::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.text, "Hello, how can I help?"); } @@ -45,5 +60,9 @@ fn test_anthropic_text_block_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/wire/anthropic_tool_definition_test.rs b/runtime/rust/prompty/tests/model/wire/anthropic_tool_definition_test.rs index 054c297f..02c999b9 100644 --- a/runtime/rust/prompty/tests/model/wire/anthropic_tool_definition_test.rs +++ b/runtime/rust/prompty/tests/model/wire/anthropic_tool_definition_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::AnthropicToolDefinition; use prompty::model::context::{LoadContext, SaveContext}; @@ -15,11 +22,21 @@ fn test_anthropic_tool_definition_load_json() { "####; let ctx = LoadContext::default(); let result = AnthropicToolDefinition::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.name, "get_weather"); - assert!(instance.description.is_some(), "Expected description to be Some"); - assert_eq!(instance.description.as_ref().unwrap(), &"Get the current weather for a city"); + assert!( + instance.description.is_some(), + "Expected description to be Some" + ); + assert_eq!( + instance.description.as_ref().unwrap(), + &"Get the current weather for a city" + ); } #[test] @@ -31,10 +48,17 @@ description: Get the current weather for a city "####; let ctx = LoadContext::default(); let result = AnthropicToolDefinition::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.name, "get_weather"); - assert!(instance.description.is_some(), "Expected description to be Some"); + assert!( + instance.description.is_some(), + "Expected description to be Some" + ); } #[test] @@ -51,5 +75,9 @@ fn test_anthropic_tool_definition_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/wire/anthropic_tool_result_block_test.rs b/runtime/rust/prompty/tests/model/wire/anthropic_tool_result_block_test.rs index 7f8a9bc3..b1b951a7 100644 --- a/runtime/rust/prompty/tests/model/wire/anthropic_tool_result_block_test.rs +++ b/runtime/rust/prompty/tests/model/wire/anthropic_tool_result_block_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::AnthropicToolResultBlock; use prompty::model::context::{LoadContext, SaveContext}; @@ -15,7 +22,11 @@ fn test_anthropic_tool_result_block_load_json() { "####; let ctx = LoadContext::default(); let result = AnthropicToolResultBlock::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.tool_use_id, "toolu_01A09q90qw90lq917835lq9"); assert_eq!(instance.content, "72°F and sunny in Paris"); @@ -30,7 +41,11 @@ content: 72°F and sunny in Paris "####; let ctx = LoadContext::default(); let result = AnthropicToolResultBlock::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.tool_use_id, "toolu_01A09q90qw90lq917835lq9"); assert_eq!(instance.content, "72°F and sunny in Paris"); @@ -50,5 +65,9 @@ fn test_anthropic_tool_result_block_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/wire/anthropic_tool_use_block_test.rs b/runtime/rust/prompty/tests/model/wire/anthropic_tool_use_block_test.rs index eec49a7c..0b969e84 100644 --- a/runtime/rust/prompty/tests/model/wire/anthropic_tool_use_block_test.rs +++ b/runtime/rust/prompty/tests/model/wire/anthropic_tool_use_block_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::AnthropicToolUseBlock; use prompty::model::context::{LoadContext, SaveContext}; @@ -18,7 +25,11 @@ fn test_anthropic_tool_use_block_load_json() { "####; let ctx = LoadContext::default(); let result = AnthropicToolUseBlock::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.id, "toolu_01A09q90qw90lq917835lq9"); assert_eq!(instance.name, "get_weather"); @@ -35,7 +46,11 @@ input: "####; let ctx = LoadContext::default(); let result = AnthropicToolUseBlock::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.id, "toolu_01A09q90qw90lq917835lq9"); assert_eq!(instance.name, "get_weather"); @@ -58,5 +73,9 @@ fn test_anthropic_tool_use_block_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/wire/anthropic_usage_test.rs b/runtime/rust/prompty/tests/model/wire/anthropic_usage_test.rs index a1e32542..a52e6af4 100644 --- a/runtime/rust/prompty/tests/model/wire/anthropic_usage_test.rs +++ b/runtime/rust/prompty/tests/model/wire/anthropic_usage_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::AnthropicUsage; use prompty::model::context::{LoadContext, SaveContext}; @@ -15,7 +22,11 @@ fn test_anthropic_usage_load_json() { "####; let ctx = LoadContext::default(); let result = AnthropicUsage::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.input_tokens, 150); assert_eq!(instance.output_tokens, 42); @@ -30,7 +41,11 @@ output_tokens: 42 "####; let ctx = LoadContext::default(); let result = AnthropicUsage::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.input_tokens, 150); assert_eq!(instance.output_tokens, 42); @@ -50,5 +65,9 @@ fn test_anthropic_usage_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/wire/anthropic_wire_message_test.rs b/runtime/rust/prompty/tests/model/wire/anthropic_wire_message_test.rs index e081b1a0..a54277bb 100644 --- a/runtime/rust/prompty/tests/model/wire/anthropic_wire_message_test.rs +++ b/runtime/rust/prompty/tests/model/wire/anthropic_wire_message_test.rs @@ -1,6 +1,13 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] use prompty::model::AnthropicWireMessage; use prompty::model::context::{LoadContext, SaveContext}; @@ -14,7 +21,11 @@ fn test_anthropic_wire_message_load_json() { "####; let ctx = LoadContext::default(); let result = AnthropicWireMessage::from_json(json, &ctx); - assert!(result.is_ok(), "Failed to load from JSON: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from JSON: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.role, "user"); } @@ -27,7 +38,11 @@ role: user "####; let ctx = LoadContext::default(); let result = AnthropicWireMessage::from_yaml(yaml, &ctx); - assert!(result.is_ok(), "Failed to load from YAML: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to load from YAML: {:?}", + result.err() + ); let instance = result.unwrap(); assert_eq!(instance.role, "user"); } @@ -45,5 +60,9 @@ fn test_anthropic_wire_message_roundtrip() { let instance = result.unwrap(); let save_ctx = SaveContext::default(); let json_output = instance.to_json(&save_ctx); - assert!(json_output.is_ok(), "Failed to serialize to JSON: {:?}", json_output.err()); + assert!( + json_output.is_ok(), + "Failed to serialize to JSON: {:?}", + json_output.err() + ); } diff --git a/runtime/rust/prompty/tests/model/wire/mod.rs b/runtime/rust/prompty/tests/model/wire/mod.rs index 0c6ed6dd..fbacc623 100644 --- a/runtime/rust/prompty/tests/model/wire/mod.rs +++ b/runtime/rust/prompty/tests/model/wire/mod.rs @@ -1,14 +1,21 @@ -// Code generated by Prompty emitter; DO NOT EDIT. +// +// Code generated by Typra emitter; DO NOT EDIT. -#![allow(unused_imports, dead_code, non_camel_case_types, unused_variables, clippy::all)] +#![allow( + unused_imports, + dead_code, + non_camel_case_types, + unused_variables, + clippy::all +)] -mod anthropic_text_block_test; -mod anthropic_image_source_test; mod anthropic_image_block_test; -mod anthropic_tool_use_block_test; -mod anthropic_tool_result_block_test; -mod anthropic_wire_message_test; -mod anthropic_tool_definition_test; +mod anthropic_image_source_test; mod anthropic_messages_request_test; -mod anthropic_usage_test; mod anthropic_messages_response_test; +mod anthropic_text_block_test; +mod anthropic_tool_definition_test; +mod anthropic_tool_result_block_test; +mod anthropic_tool_use_block_test; +mod anthropic_usage_test; +mod anthropic_wire_message_test; diff --git a/runtime/typescript/packages/core/src/model/agent/guardrail-result.ts b/runtime/typescript/packages/core/src/model/agent/guardrail-result.ts index be9c392e..7e43c7db 100644 --- a/runtime/typescript/packages/core/src/model/agent/guardrail-result.ts +++ b/runtime/typescript/packages/core/src/model/agent/guardrail-result.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/agent/index.ts b/runtime/typescript/packages/core/src/model/agent/index.ts index ffb7c225..3da1c268 100644 --- a/runtime/typescript/packages/core/src/model/agent/index.ts +++ b/runtime/typescript/packages/core/src/model/agent/index.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/agent/prompty.ts b/runtime/typescript/packages/core/src/model/agent/prompty.ts index f6de1772..cb750a68 100644 --- a/runtime/typescript/packages/core/src/model/agent/prompty.ts +++ b/runtime/typescript/packages/core/src/model/agent/prompty.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/connection/connection.ts b/runtime/typescript/packages/core/src/model/connection/connection.ts index 79085fb9..cbe015cf 100644 --- a/runtime/typescript/packages/core/src/model/connection/connection.ts +++ b/runtime/typescript/packages/core/src/model/connection/connection.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/connection/index.ts b/runtime/typescript/packages/core/src/model/connection/index.ts index 500f748a..2c312a1a 100644 --- a/runtime/typescript/packages/core/src/model/connection/index.ts +++ b/runtime/typescript/packages/core/src/model/connection/index.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/context.ts b/runtime/typescript/packages/core/src/model/context.ts index 639bb708..8307e52b 100644 --- a/runtime/typescript/packages/core/src/model/context.ts +++ b/runtime/typescript/packages/core/src/model/context.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/conversation/content-part.ts b/runtime/typescript/packages/core/src/model/conversation/content-part.ts index 4d448638..273eeada 100644 --- a/runtime/typescript/packages/core/src/model/conversation/content-part.ts +++ b/runtime/typescript/packages/core/src/model/conversation/content-part.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/conversation/index.ts b/runtime/typescript/packages/core/src/model/conversation/index.ts index 9443ad17..98832d99 100644 --- a/runtime/typescript/packages/core/src/model/conversation/index.ts +++ b/runtime/typescript/packages/core/src/model/conversation/index.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/conversation/message.ts b/runtime/typescript/packages/core/src/model/conversation/message.ts index 30ae67de..fc62988a 100644 --- a/runtime/typescript/packages/core/src/model/conversation/message.ts +++ b/runtime/typescript/packages/core/src/model/conversation/message.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/conversation/thread-marker.ts b/runtime/typescript/packages/core/src/model/conversation/thread-marker.ts index d52164b0..47d739d6 100644 --- a/runtime/typescript/packages/core/src/model/conversation/thread-marker.ts +++ b/runtime/typescript/packages/core/src/model/conversation/thread-marker.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/conversation/tool-call.ts b/runtime/typescript/packages/core/src/model/conversation/tool-call.ts index 385e85d3..c792f5a5 100644 --- a/runtime/typescript/packages/core/src/model/conversation/tool-call.ts +++ b/runtime/typescript/packages/core/src/model/conversation/tool-call.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/conversation/tool-result.ts b/runtime/typescript/packages/core/src/model/conversation/tool-result.ts index 0bf3e59c..6d6bc63b 100644 --- a/runtime/typescript/packages/core/src/model/conversation/tool-result.ts +++ b/runtime/typescript/packages/core/src/model/conversation/tool-result.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/core/file-not-found-error.ts b/runtime/typescript/packages/core/src/model/core/file-not-found-error.ts index 87efa82e..b2e91f10 100644 --- a/runtime/typescript/packages/core/src/model/core/file-not-found-error.ts +++ b/runtime/typescript/packages/core/src/model/core/file-not-found-error.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/core/index.ts b/runtime/typescript/packages/core/src/model/core/index.ts index 59175c21..e88baa26 100644 --- a/runtime/typescript/packages/core/src/model/core/index.ts +++ b/runtime/typescript/packages/core/src/model/core/index.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/core/invoker-error.ts b/runtime/typescript/packages/core/src/model/core/invoker-error.ts index 31680119..b4880b8b 100644 --- a/runtime/typescript/packages/core/src/model/core/invoker-error.ts +++ b/runtime/typescript/packages/core/src/model/core/invoker-error.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/core/property.ts b/runtime/typescript/packages/core/src/model/core/property.ts index 911893b0..e8a26334 100644 --- a/runtime/typescript/packages/core/src/model/core/property.ts +++ b/runtime/typescript/packages/core/src/model/core/property.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/core/validation-error.ts b/runtime/typescript/packages/core/src/model/core/validation-error.ts index 87f5ea6c..6717a801 100644 --- a/runtime/typescript/packages/core/src/model/core/validation-error.ts +++ b/runtime/typescript/packages/core/src/model/core/validation-error.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/core/validation-result.ts b/runtime/typescript/packages/core/src/model/core/validation-result.ts index a9f64878..757c4d86 100644 --- a/runtime/typescript/packages/core/src/model/core/validation-result.ts +++ b/runtime/typescript/packages/core/src/model/core/validation-result.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/checkpoint.ts b/runtime/typescript/packages/core/src/model/events/checkpoint.ts index 11ba6d45..fbf80375 100644 --- a/runtime/typescript/packages/core/src/model/events/checkpoint.ts +++ b/runtime/typescript/packages/core/src/model/events/checkpoint.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/compaction-complete-payload.ts b/runtime/typescript/packages/core/src/model/events/compaction-complete-payload.ts index 53ef6cca..0eca9fa3 100644 --- a/runtime/typescript/packages/core/src/model/events/compaction-complete-payload.ts +++ b/runtime/typescript/packages/core/src/model/events/compaction-complete-payload.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/compaction-failed-payload.ts b/runtime/typescript/packages/core/src/model/events/compaction-failed-payload.ts index 5baa16ec..fa6091ec 100644 --- a/runtime/typescript/packages/core/src/model/events/compaction-failed-payload.ts +++ b/runtime/typescript/packages/core/src/model/events/compaction-failed-payload.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/compaction-start-payload.ts b/runtime/typescript/packages/core/src/model/events/compaction-start-payload.ts index aab36724..136dfbeb 100644 --- a/runtime/typescript/packages/core/src/model/events/compaction-start-payload.ts +++ b/runtime/typescript/packages/core/src/model/events/compaction-start-payload.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/done-event-payload.ts b/runtime/typescript/packages/core/src/model/events/done-event-payload.ts index 2e42b467..4e3f3dec 100644 --- a/runtime/typescript/packages/core/src/model/events/done-event-payload.ts +++ b/runtime/typescript/packages/core/src/model/events/done-event-payload.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/error-event-payload.ts b/runtime/typescript/packages/core/src/model/events/error-event-payload.ts index 048c70dc..65b73039 100644 --- a/runtime/typescript/packages/core/src/model/events/error-event-payload.ts +++ b/runtime/typescript/packages/core/src/model/events/error-event-payload.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/harness-context.ts b/runtime/typescript/packages/core/src/model/events/harness-context.ts index 5592f324..6bb6cb98 100644 --- a/runtime/typescript/packages/core/src/model/events/harness-context.ts +++ b/runtime/typescript/packages/core/src/model/events/harness-context.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/hook-end-payload.ts b/runtime/typescript/packages/core/src/model/events/hook-end-payload.ts index 57245d45..5091b533 100644 --- a/runtime/typescript/packages/core/src/model/events/hook-end-payload.ts +++ b/runtime/typescript/packages/core/src/model/events/hook-end-payload.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/hook-start-payload.ts b/runtime/typescript/packages/core/src/model/events/hook-start-payload.ts index f1710483..e5cc1118 100644 --- a/runtime/typescript/packages/core/src/model/events/hook-start-payload.ts +++ b/runtime/typescript/packages/core/src/model/events/hook-start-payload.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/host-tool-request.ts b/runtime/typescript/packages/core/src/model/events/host-tool-request.ts index 734fc5bc..16edbef2 100644 --- a/runtime/typescript/packages/core/src/model/events/host-tool-request.ts +++ b/runtime/typescript/packages/core/src/model/events/host-tool-request.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/host-tool-result.ts b/runtime/typescript/packages/core/src/model/events/host-tool-result.ts index 4265b17b..1a5628e4 100644 --- a/runtime/typescript/packages/core/src/model/events/host-tool-result.ts +++ b/runtime/typescript/packages/core/src/model/events/host-tool-result.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/index.ts b/runtime/typescript/packages/core/src/model/events/index.ts index 76bff945..476c1d71 100644 --- a/runtime/typescript/packages/core/src/model/events/index.ts +++ b/runtime/typescript/packages/core/src/model/events/index.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/llm-complete-payload.ts b/runtime/typescript/packages/core/src/model/events/llm-complete-payload.ts index b3496839..9aa1d6b3 100644 --- a/runtime/typescript/packages/core/src/model/events/llm-complete-payload.ts +++ b/runtime/typescript/packages/core/src/model/events/llm-complete-payload.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/llm-start-payload.ts b/runtime/typescript/packages/core/src/model/events/llm-start-payload.ts index a98702fb..5262733f 100644 --- a/runtime/typescript/packages/core/src/model/events/llm-start-payload.ts +++ b/runtime/typescript/packages/core/src/model/events/llm-start-payload.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/messages-updated-payload.ts b/runtime/typescript/packages/core/src/model/events/messages-updated-payload.ts index 191507eb..b014fb0e 100644 --- a/runtime/typescript/packages/core/src/model/events/messages-updated-payload.ts +++ b/runtime/typescript/packages/core/src/model/events/messages-updated-payload.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/permission-completed-payload.ts b/runtime/typescript/packages/core/src/model/events/permission-completed-payload.ts index d71fa080..63a3dde1 100644 --- a/runtime/typescript/packages/core/src/model/events/permission-completed-payload.ts +++ b/runtime/typescript/packages/core/src/model/events/permission-completed-payload.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/permission-decision.ts b/runtime/typescript/packages/core/src/model/events/permission-decision.ts index 1eaee0a4..d818a600 100644 --- a/runtime/typescript/packages/core/src/model/events/permission-decision.ts +++ b/runtime/typescript/packages/core/src/model/events/permission-decision.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/permission-request.ts b/runtime/typescript/packages/core/src/model/events/permission-request.ts index e39c58e4..e3e25e7c 100644 --- a/runtime/typescript/packages/core/src/model/events/permission-request.ts +++ b/runtime/typescript/packages/core/src/model/events/permission-request.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/permission-requested-payload.ts b/runtime/typescript/packages/core/src/model/events/permission-requested-payload.ts index 5beaa5ab..5d4d3b8f 100644 --- a/runtime/typescript/packages/core/src/model/events/permission-requested-payload.ts +++ b/runtime/typescript/packages/core/src/model/events/permission-requested-payload.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/redacted-field.ts b/runtime/typescript/packages/core/src/model/events/redacted-field.ts index ce94680c..d9636cba 100644 --- a/runtime/typescript/packages/core/src/model/events/redacted-field.ts +++ b/runtime/typescript/packages/core/src/model/events/redacted-field.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/redaction-metadata.ts b/runtime/typescript/packages/core/src/model/events/redaction-metadata.ts index 643434ae..c08fbb88 100644 --- a/runtime/typescript/packages/core/src/model/events/redaction-metadata.ts +++ b/runtime/typescript/packages/core/src/model/events/redaction-metadata.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/retry-payload.ts b/runtime/typescript/packages/core/src/model/events/retry-payload.ts index 100a48e2..46470311 100644 --- a/runtime/typescript/packages/core/src/model/events/retry-payload.ts +++ b/runtime/typescript/packages/core/src/model/events/retry-payload.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/session-end-payload.ts b/runtime/typescript/packages/core/src/model/events/session-end-payload.ts index 977382f3..16a29212 100644 --- a/runtime/typescript/packages/core/src/model/events/session-end-payload.ts +++ b/runtime/typescript/packages/core/src/model/events/session-end-payload.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/session-event.ts b/runtime/typescript/packages/core/src/model/events/session-event.ts index 602fc186..bec2b5fb 100644 --- a/runtime/typescript/packages/core/src/model/events/session-event.ts +++ b/runtime/typescript/packages/core/src/model/events/session-event.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/session-file-ref.ts b/runtime/typescript/packages/core/src/model/events/session-file-ref.ts index ba09a16a..558e3507 100644 --- a/runtime/typescript/packages/core/src/model/events/session-file-ref.ts +++ b/runtime/typescript/packages/core/src/model/events/session-file-ref.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/session-ref.ts b/runtime/typescript/packages/core/src/model/events/session-ref.ts index 566ae841..5c30c5c5 100644 --- a/runtime/typescript/packages/core/src/model/events/session-ref.ts +++ b/runtime/typescript/packages/core/src/model/events/session-ref.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/session-start-payload.ts b/runtime/typescript/packages/core/src/model/events/session-start-payload.ts index 732aace2..dbba60b7 100644 --- a/runtime/typescript/packages/core/src/model/events/session-start-payload.ts +++ b/runtime/typescript/packages/core/src/model/events/session-start-payload.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/session-summary.ts b/runtime/typescript/packages/core/src/model/events/session-summary.ts index f882c83e..539050b4 100644 --- a/runtime/typescript/packages/core/src/model/events/session-summary.ts +++ b/runtime/typescript/packages/core/src/model/events/session-summary.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/session-trace.ts b/runtime/typescript/packages/core/src/model/events/session-trace.ts index d5fc7963..f2067a86 100644 --- a/runtime/typescript/packages/core/src/model/events/session-trace.ts +++ b/runtime/typescript/packages/core/src/model/events/session-trace.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/session-warning-payload.ts b/runtime/typescript/packages/core/src/model/events/session-warning-payload.ts index 255c0a89..5521086d 100644 --- a/runtime/typescript/packages/core/src/model/events/session-warning-payload.ts +++ b/runtime/typescript/packages/core/src/model/events/session-warning-payload.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/status-event-payload.ts b/runtime/typescript/packages/core/src/model/events/status-event-payload.ts index 6d6cb367..8752ecdf 100644 --- a/runtime/typescript/packages/core/src/model/events/status-event-payload.ts +++ b/runtime/typescript/packages/core/src/model/events/status-event-payload.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/stream-chunk.ts b/runtime/typescript/packages/core/src/model/events/stream-chunk.ts index 444bbc1b..0b82aca3 100644 --- a/runtime/typescript/packages/core/src/model/events/stream-chunk.ts +++ b/runtime/typescript/packages/core/src/model/events/stream-chunk.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/thinking-event-payload.ts b/runtime/typescript/packages/core/src/model/events/thinking-event-payload.ts index 5bfa3d88..4e77e6f0 100644 --- a/runtime/typescript/packages/core/src/model/events/thinking-event-payload.ts +++ b/runtime/typescript/packages/core/src/model/events/thinking-event-payload.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/token-event-payload.ts b/runtime/typescript/packages/core/src/model/events/token-event-payload.ts index 740a04bd..b334e702 100644 --- a/runtime/typescript/packages/core/src/model/events/token-event-payload.ts +++ b/runtime/typescript/packages/core/src/model/events/token-event-payload.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/tool-call-complete-payload.ts b/runtime/typescript/packages/core/src/model/events/tool-call-complete-payload.ts index 8245af79..18e2a870 100644 --- a/runtime/typescript/packages/core/src/model/events/tool-call-complete-payload.ts +++ b/runtime/typescript/packages/core/src/model/events/tool-call-complete-payload.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/tool-call-start-payload.ts b/runtime/typescript/packages/core/src/model/events/tool-call-start-payload.ts index 66c35f20..23ae073e 100644 --- a/runtime/typescript/packages/core/src/model/events/tool-call-start-payload.ts +++ b/runtime/typescript/packages/core/src/model/events/tool-call-start-payload.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/tool-execution-complete-payload.ts b/runtime/typescript/packages/core/src/model/events/tool-execution-complete-payload.ts index 124dd1f8..07e6edca 100644 --- a/runtime/typescript/packages/core/src/model/events/tool-execution-complete-payload.ts +++ b/runtime/typescript/packages/core/src/model/events/tool-execution-complete-payload.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/tool-execution-start-payload.ts b/runtime/typescript/packages/core/src/model/events/tool-execution-start-payload.ts index 14a7b7df..a3641573 100644 --- a/runtime/typescript/packages/core/src/model/events/tool-execution-start-payload.ts +++ b/runtime/typescript/packages/core/src/model/events/tool-execution-start-payload.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/tool-result-payload.ts b/runtime/typescript/packages/core/src/model/events/tool-result-payload.ts index 9c06e9b8..450d8894 100644 --- a/runtime/typescript/packages/core/src/model/events/tool-result-payload.ts +++ b/runtime/typescript/packages/core/src/model/events/tool-result-payload.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/trajectory-event.ts b/runtime/typescript/packages/core/src/model/events/trajectory-event.ts index ab15d277..f32a2a29 100644 --- a/runtime/typescript/packages/core/src/model/events/trajectory-event.ts +++ b/runtime/typescript/packages/core/src/model/events/trajectory-event.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/turn-end-payload.ts b/runtime/typescript/packages/core/src/model/events/turn-end-payload.ts index f95d5043..2d3266c0 100644 --- a/runtime/typescript/packages/core/src/model/events/turn-end-payload.ts +++ b/runtime/typescript/packages/core/src/model/events/turn-end-payload.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/turn-event.ts b/runtime/typescript/packages/core/src/model/events/turn-event.ts index b30d1ce2..8a68d6d5 100644 --- a/runtime/typescript/packages/core/src/model/events/turn-event.ts +++ b/runtime/typescript/packages/core/src/model/events/turn-event.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/turn-start-payload.ts b/runtime/typescript/packages/core/src/model/events/turn-start-payload.ts index d4f2bc81..f2094217 100644 --- a/runtime/typescript/packages/core/src/model/events/turn-start-payload.ts +++ b/runtime/typescript/packages/core/src/model/events/turn-start-payload.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/turn-summary.ts b/runtime/typescript/packages/core/src/model/events/turn-summary.ts index a7ebc91b..1dce7ee2 100644 --- a/runtime/typescript/packages/core/src/model/events/turn-summary.ts +++ b/runtime/typescript/packages/core/src/model/events/turn-summary.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/events/turn-trace.ts b/runtime/typescript/packages/core/src/model/events/turn-trace.ts index 97c48ac9..786f954c 100644 --- a/runtime/typescript/packages/core/src/model/events/turn-trace.ts +++ b/runtime/typescript/packages/core/src/model/events/turn-trace.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/index.ts b/runtime/typescript/packages/core/src/model/index.ts index b1ffe1d3..3f5d90f5 100644 --- a/runtime/typescript/packages/core/src/model/index.ts +++ b/runtime/typescript/packages/core/src/model/index.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/model/index.ts b/runtime/typescript/packages/core/src/model/model/index.ts index 535885a5..c93fa0e6 100644 --- a/runtime/typescript/packages/core/src/model/model/index.ts +++ b/runtime/typescript/packages/core/src/model/model/index.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/model/model-info.ts b/runtime/typescript/packages/core/src/model/model/model-info.ts index 60c9d6a5..e5d58117 100644 --- a/runtime/typescript/packages/core/src/model/model/model-info.ts +++ b/runtime/typescript/packages/core/src/model/model/model-info.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/model/model-options.ts b/runtime/typescript/packages/core/src/model/model/model-options.ts index 65868065..806ed03a 100644 --- a/runtime/typescript/packages/core/src/model/model/model-options.ts +++ b/runtime/typescript/packages/core/src/model/model/model-options.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/model/model.ts b/runtime/typescript/packages/core/src/model/model/model.ts index 60d05444..4d9bed76 100644 --- a/runtime/typescript/packages/core/src/model/model/model.ts +++ b/runtime/typescript/packages/core/src/model/model/model.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/model/token-usage.ts b/runtime/typescript/packages/core/src/model/model/token-usage.ts index 6965a646..c3ced855 100644 --- a/runtime/typescript/packages/core/src/model/model/token-usage.ts +++ b/runtime/typescript/packages/core/src/model/model/token-usage.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/pipeline/checkpoint-store.ts b/runtime/typescript/packages/core/src/model/pipeline/checkpoint-store.ts index f05ee30d..474fcec3 100644 --- a/runtime/typescript/packages/core/src/model/pipeline/checkpoint-store.ts +++ b/runtime/typescript/packages/core/src/model/pipeline/checkpoint-store.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/pipeline/compaction-config.ts b/runtime/typescript/packages/core/src/model/pipeline/compaction-config.ts index a94e4c2c..61bae55d 100644 --- a/runtime/typescript/packages/core/src/model/pipeline/compaction-config.ts +++ b/runtime/typescript/packages/core/src/model/pipeline/compaction-config.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/pipeline/event-journal-writer.ts b/runtime/typescript/packages/core/src/model/pipeline/event-journal-writer.ts index 7d9a6723..9c2d3787 100644 --- a/runtime/typescript/packages/core/src/model/pipeline/event-journal-writer.ts +++ b/runtime/typescript/packages/core/src/model/pipeline/event-journal-writer.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/pipeline/event-sink.ts b/runtime/typescript/packages/core/src/model/pipeline/event-sink.ts index 9666d03a..6f2ff06d 100644 --- a/runtime/typescript/packages/core/src/model/pipeline/event-sink.ts +++ b/runtime/typescript/packages/core/src/model/pipeline/event-sink.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/pipeline/executor.ts b/runtime/typescript/packages/core/src/model/pipeline/executor.ts index 548078fb..a288c30c 100644 --- a/runtime/typescript/packages/core/src/model/pipeline/executor.ts +++ b/runtime/typescript/packages/core/src/model/pipeline/executor.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/pipeline/host-tool-executor.ts b/runtime/typescript/packages/core/src/model/pipeline/host-tool-executor.ts index e2456f33..a6f8a06f 100644 --- a/runtime/typescript/packages/core/src/model/pipeline/host-tool-executor.ts +++ b/runtime/typescript/packages/core/src/model/pipeline/host-tool-executor.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/pipeline/index.ts b/runtime/typescript/packages/core/src/model/pipeline/index.ts index 8d01b4ea..1e102fb7 100644 --- a/runtime/typescript/packages/core/src/model/pipeline/index.ts +++ b/runtime/typescript/packages/core/src/model/pipeline/index.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/pipeline/parser.ts b/runtime/typescript/packages/core/src/model/pipeline/parser.ts index eb43685a..2649cf44 100644 --- a/runtime/typescript/packages/core/src/model/pipeline/parser.ts +++ b/runtime/typescript/packages/core/src/model/pipeline/parser.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/pipeline/permission-resolver.ts b/runtime/typescript/packages/core/src/model/pipeline/permission-resolver.ts index 1e32c3a0..4062162e 100644 --- a/runtime/typescript/packages/core/src/model/pipeline/permission-resolver.ts +++ b/runtime/typescript/packages/core/src/model/pipeline/permission-resolver.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/pipeline/processor.ts b/runtime/typescript/packages/core/src/model/pipeline/processor.ts index a5c22796..4dec64a0 100644 --- a/runtime/typescript/packages/core/src/model/pipeline/processor.ts +++ b/runtime/typescript/packages/core/src/model/pipeline/processor.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/pipeline/renderer.ts b/runtime/typescript/packages/core/src/model/pipeline/renderer.ts index 70e1a89f..2a71a63c 100644 --- a/runtime/typescript/packages/core/src/model/pipeline/renderer.ts +++ b/runtime/typescript/packages/core/src/model/pipeline/renderer.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/pipeline/turn-options.ts b/runtime/typescript/packages/core/src/model/pipeline/turn-options.ts index 5628f610..e6ef5b45 100644 --- a/runtime/typescript/packages/core/src/model/pipeline/turn-options.ts +++ b/runtime/typescript/packages/core/src/model/pipeline/turn-options.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/streaming/index.ts b/runtime/typescript/packages/core/src/model/streaming/index.ts index 931f8a82..382b53fc 100644 --- a/runtime/typescript/packages/core/src/model/streaming/index.ts +++ b/runtime/typescript/packages/core/src/model/streaming/index.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/streaming/stream-options.ts b/runtime/typescript/packages/core/src/model/streaming/stream-options.ts index f5f78005..e1763b43 100644 --- a/runtime/typescript/packages/core/src/model/streaming/stream-options.ts +++ b/runtime/typescript/packages/core/src/model/streaming/stream-options.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/template/format-config.ts b/runtime/typescript/packages/core/src/model/template/format-config.ts index 69741caa..3a8050bb 100644 --- a/runtime/typescript/packages/core/src/model/template/format-config.ts +++ b/runtime/typescript/packages/core/src/model/template/format-config.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/template/index.ts b/runtime/typescript/packages/core/src/model/template/index.ts index ba6ed5f4..fc96d87d 100644 --- a/runtime/typescript/packages/core/src/model/template/index.ts +++ b/runtime/typescript/packages/core/src/model/template/index.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/template/parser-config.ts b/runtime/typescript/packages/core/src/model/template/parser-config.ts index 9d2012dd..b676e890 100644 --- a/runtime/typescript/packages/core/src/model/template/parser-config.ts +++ b/runtime/typescript/packages/core/src/model/template/parser-config.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/template/template.ts b/runtime/typescript/packages/core/src/model/template/template.ts index d619c31f..e54d16be 100644 --- a/runtime/typescript/packages/core/src/model/template/template.ts +++ b/runtime/typescript/packages/core/src/model/template/template.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/tools/binding.ts b/runtime/typescript/packages/core/src/model/tools/binding.ts index 4dff4650..378f5b94 100644 --- a/runtime/typescript/packages/core/src/model/tools/binding.ts +++ b/runtime/typescript/packages/core/src/model/tools/binding.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/tools/index.ts b/runtime/typescript/packages/core/src/model/tools/index.ts index 6ee2a844..49dd0ac3 100644 --- a/runtime/typescript/packages/core/src/model/tools/index.ts +++ b/runtime/typescript/packages/core/src/model/tools/index.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/tools/mcp-approval-mode.ts b/runtime/typescript/packages/core/src/model/tools/mcp-approval-mode.ts index 33ac01a8..54169e0e 100644 --- a/runtime/typescript/packages/core/src/model/tools/mcp-approval-mode.ts +++ b/runtime/typescript/packages/core/src/model/tools/mcp-approval-mode.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/tools/tool-context.ts b/runtime/typescript/packages/core/src/model/tools/tool-context.ts index a893b47c..a8b63fe1 100644 --- a/runtime/typescript/packages/core/src/model/tools/tool-context.ts +++ b/runtime/typescript/packages/core/src/model/tools/tool-context.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/tools/tool-dispatch-result.ts b/runtime/typescript/packages/core/src/model/tools/tool-dispatch-result.ts index 9fdb93b9..3250bcdf 100644 --- a/runtime/typescript/packages/core/src/model/tools/tool-dispatch-result.ts +++ b/runtime/typescript/packages/core/src/model/tools/tool-dispatch-result.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/tools/tool.ts b/runtime/typescript/packages/core/src/model/tools/tool.ts index 26f180ba..87ddffc3 100644 --- a/runtime/typescript/packages/core/src/model/tools/tool.ts +++ b/runtime/typescript/packages/core/src/model/tools/tool.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/tracing/index.ts b/runtime/typescript/packages/core/src/model/tracing/index.ts index 2135ee97..e535f8fc 100644 --- a/runtime/typescript/packages/core/src/model/tracing/index.ts +++ b/runtime/typescript/packages/core/src/model/tracing/index.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/tracing/trace-file.ts b/runtime/typescript/packages/core/src/model/tracing/trace-file.ts index 082468ec..eabf02a1 100644 --- a/runtime/typescript/packages/core/src/model/tracing/trace-file.ts +++ b/runtime/typescript/packages/core/src/model/tracing/trace-file.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/tracing/trace-span.ts b/runtime/typescript/packages/core/src/model/tracing/trace-span.ts index 15891a30..5fd017be 100644 --- a/runtime/typescript/packages/core/src/model/tracing/trace-span.ts +++ b/runtime/typescript/packages/core/src/model/tracing/trace-span.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/tracing/trace-time.ts b/runtime/typescript/packages/core/src/model/tracing/trace-time.ts index 552d00f4..be24b71e 100644 --- a/runtime/typescript/packages/core/src/model/tracing/trace-time.ts +++ b/runtime/typescript/packages/core/src/model/tracing/trace-time.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/wire/anthropic-image-block.ts b/runtime/typescript/packages/core/src/model/wire/anthropic-image-block.ts index 8a2ab857..ec2df219 100644 --- a/runtime/typescript/packages/core/src/model/wire/anthropic-image-block.ts +++ b/runtime/typescript/packages/core/src/model/wire/anthropic-image-block.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/wire/anthropic-image-source.ts b/runtime/typescript/packages/core/src/model/wire/anthropic-image-source.ts index 0580d2ca..319c38c9 100644 --- a/runtime/typescript/packages/core/src/model/wire/anthropic-image-source.ts +++ b/runtime/typescript/packages/core/src/model/wire/anthropic-image-source.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/wire/anthropic-messages-request.ts b/runtime/typescript/packages/core/src/model/wire/anthropic-messages-request.ts index f40b274b..8dde01a6 100644 --- a/runtime/typescript/packages/core/src/model/wire/anthropic-messages-request.ts +++ b/runtime/typescript/packages/core/src/model/wire/anthropic-messages-request.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/wire/anthropic-messages-response.ts b/runtime/typescript/packages/core/src/model/wire/anthropic-messages-response.ts index cd688326..50fd78b8 100644 --- a/runtime/typescript/packages/core/src/model/wire/anthropic-messages-response.ts +++ b/runtime/typescript/packages/core/src/model/wire/anthropic-messages-response.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/wire/anthropic-text-block.ts b/runtime/typescript/packages/core/src/model/wire/anthropic-text-block.ts index b0010085..e441b5c0 100644 --- a/runtime/typescript/packages/core/src/model/wire/anthropic-text-block.ts +++ b/runtime/typescript/packages/core/src/model/wire/anthropic-text-block.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/wire/anthropic-tool-definition.ts b/runtime/typescript/packages/core/src/model/wire/anthropic-tool-definition.ts index 1c7c518f..07f9017d 100644 --- a/runtime/typescript/packages/core/src/model/wire/anthropic-tool-definition.ts +++ b/runtime/typescript/packages/core/src/model/wire/anthropic-tool-definition.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/wire/anthropic-tool-result-block.ts b/runtime/typescript/packages/core/src/model/wire/anthropic-tool-result-block.ts index ccaee3e4..b51ccced 100644 --- a/runtime/typescript/packages/core/src/model/wire/anthropic-tool-result-block.ts +++ b/runtime/typescript/packages/core/src/model/wire/anthropic-tool-result-block.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/wire/anthropic-tool-use-block.ts b/runtime/typescript/packages/core/src/model/wire/anthropic-tool-use-block.ts index d2d1e7b2..1a21976a 100644 --- a/runtime/typescript/packages/core/src/model/wire/anthropic-tool-use-block.ts +++ b/runtime/typescript/packages/core/src/model/wire/anthropic-tool-use-block.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/wire/anthropic-usage.ts b/runtime/typescript/packages/core/src/model/wire/anthropic-usage.ts index da25a95b..532de4a8 100644 --- a/runtime/typescript/packages/core/src/model/wire/anthropic-usage.ts +++ b/runtime/typescript/packages/core/src/model/wire/anthropic-usage.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/wire/anthropic-wire-message.ts b/runtime/typescript/packages/core/src/model/wire/anthropic-wire-message.ts index 4e83619d..6415c2cf 100644 --- a/runtime/typescript/packages/core/src/model/wire/anthropic-wire-message.ts +++ b/runtime/typescript/packages/core/src/model/wire/anthropic-wire-message.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/src/model/wire/index.ts b/runtime/typescript/packages/core/src/model/wire/index.ts index 8fdcc319..a4f800c2 100644 --- a/runtime/typescript/packages/core/src/model/wire/index.ts +++ b/runtime/typescript/packages/core/src/model/wire/index.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/agent/guardrail-result.test.ts b/runtime/typescript/packages/core/tests/model/agent/guardrail-result.test.ts index feb766b9..8c7de005 100644 --- a/runtime/typescript/packages/core/tests/model/agent/guardrail-result.test.ts +++ b/runtime/typescript/packages/core/tests/model/agent/guardrail-result.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/agent/prompty.test.ts b/runtime/typescript/packages/core/tests/model/agent/prompty.test.ts index 8adf4d85..401cb72e 100644 --- a/runtime/typescript/packages/core/tests/model/agent/prompty.test.ts +++ b/runtime/typescript/packages/core/tests/model/agent/prompty.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/connection/anonymous-connection.test.ts b/runtime/typescript/packages/core/tests/model/connection/anonymous-connection.test.ts index 3459285d..57c5bcda 100644 --- a/runtime/typescript/packages/core/tests/model/connection/anonymous-connection.test.ts +++ b/runtime/typescript/packages/core/tests/model/connection/anonymous-connection.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/connection/api-key-connection.test.ts b/runtime/typescript/packages/core/tests/model/connection/api-key-connection.test.ts index 1fd78c51..b72270a7 100644 --- a/runtime/typescript/packages/core/tests/model/connection/api-key-connection.test.ts +++ b/runtime/typescript/packages/core/tests/model/connection/api-key-connection.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/connection/connection.test.ts b/runtime/typescript/packages/core/tests/model/connection/connection.test.ts index 50c60abf..193aa0bd 100644 --- a/runtime/typescript/packages/core/tests/model/connection/connection.test.ts +++ b/runtime/typescript/packages/core/tests/model/connection/connection.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/connection/foundry-connection.test.ts b/runtime/typescript/packages/core/tests/model/connection/foundry-connection.test.ts index e3fac545..b691b3fe 100644 --- a/runtime/typescript/packages/core/tests/model/connection/foundry-connection.test.ts +++ b/runtime/typescript/packages/core/tests/model/connection/foundry-connection.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/connection/o-auth-connection.test.ts b/runtime/typescript/packages/core/tests/model/connection/o-auth-connection.test.ts index 6cc08cd9..6119454b 100644 --- a/runtime/typescript/packages/core/tests/model/connection/o-auth-connection.test.ts +++ b/runtime/typescript/packages/core/tests/model/connection/o-auth-connection.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/connection/reference-connection.test.ts b/runtime/typescript/packages/core/tests/model/connection/reference-connection.test.ts index 999ca922..4b46d0f5 100644 --- a/runtime/typescript/packages/core/tests/model/connection/reference-connection.test.ts +++ b/runtime/typescript/packages/core/tests/model/connection/reference-connection.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/connection/remote-connection.test.ts b/runtime/typescript/packages/core/tests/model/connection/remote-connection.test.ts index 5c876360..bbc29a6c 100644 --- a/runtime/typescript/packages/core/tests/model/connection/remote-connection.test.ts +++ b/runtime/typescript/packages/core/tests/model/connection/remote-connection.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/conversation/audio-part.test.ts b/runtime/typescript/packages/core/tests/model/conversation/audio-part.test.ts index 4f3bd5b0..348fc839 100644 --- a/runtime/typescript/packages/core/tests/model/conversation/audio-part.test.ts +++ b/runtime/typescript/packages/core/tests/model/conversation/audio-part.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/conversation/content-part.test.ts b/runtime/typescript/packages/core/tests/model/conversation/content-part.test.ts index 3a6e3b4d..ecd3cece 100644 --- a/runtime/typescript/packages/core/tests/model/conversation/content-part.test.ts +++ b/runtime/typescript/packages/core/tests/model/conversation/content-part.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/conversation/file-part.test.ts b/runtime/typescript/packages/core/tests/model/conversation/file-part.test.ts index 29893087..c83c5ee5 100644 --- a/runtime/typescript/packages/core/tests/model/conversation/file-part.test.ts +++ b/runtime/typescript/packages/core/tests/model/conversation/file-part.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/conversation/image-part.test.ts b/runtime/typescript/packages/core/tests/model/conversation/image-part.test.ts index 4fa02ad4..827cbe23 100644 --- a/runtime/typescript/packages/core/tests/model/conversation/image-part.test.ts +++ b/runtime/typescript/packages/core/tests/model/conversation/image-part.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/conversation/message.test.ts b/runtime/typescript/packages/core/tests/model/conversation/message.test.ts index badb3277..3816ada6 100644 --- a/runtime/typescript/packages/core/tests/model/conversation/message.test.ts +++ b/runtime/typescript/packages/core/tests/model/conversation/message.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/conversation/text-part.test.ts b/runtime/typescript/packages/core/tests/model/conversation/text-part.test.ts index 366212d4..1c80f3e0 100644 --- a/runtime/typescript/packages/core/tests/model/conversation/text-part.test.ts +++ b/runtime/typescript/packages/core/tests/model/conversation/text-part.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/conversation/thread-marker.test.ts b/runtime/typescript/packages/core/tests/model/conversation/thread-marker.test.ts index a478cb0c..2f57c898 100644 --- a/runtime/typescript/packages/core/tests/model/conversation/thread-marker.test.ts +++ b/runtime/typescript/packages/core/tests/model/conversation/thread-marker.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/conversation/tool-call.test.ts b/runtime/typescript/packages/core/tests/model/conversation/tool-call.test.ts index b0141892..eac12b40 100644 --- a/runtime/typescript/packages/core/tests/model/conversation/tool-call.test.ts +++ b/runtime/typescript/packages/core/tests/model/conversation/tool-call.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/conversation/tool-result.test.ts b/runtime/typescript/packages/core/tests/model/conversation/tool-result.test.ts index e16970c0..8f74c02e 100644 --- a/runtime/typescript/packages/core/tests/model/conversation/tool-result.test.ts +++ b/runtime/typescript/packages/core/tests/model/conversation/tool-result.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/core/array-property.test.ts b/runtime/typescript/packages/core/tests/model/core/array-property.test.ts index d83e43f7..08e11b9b 100644 --- a/runtime/typescript/packages/core/tests/model/core/array-property.test.ts +++ b/runtime/typescript/packages/core/tests/model/core/array-property.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/core/file-not-found-error.test.ts b/runtime/typescript/packages/core/tests/model/core/file-not-found-error.test.ts index 8e811b81..e4e5036f 100644 --- a/runtime/typescript/packages/core/tests/model/core/file-not-found-error.test.ts +++ b/runtime/typescript/packages/core/tests/model/core/file-not-found-error.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/core/invoker-error.test.ts b/runtime/typescript/packages/core/tests/model/core/invoker-error.test.ts index 3699b903..248de8ad 100644 --- a/runtime/typescript/packages/core/tests/model/core/invoker-error.test.ts +++ b/runtime/typescript/packages/core/tests/model/core/invoker-error.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/core/object-property.test.ts b/runtime/typescript/packages/core/tests/model/core/object-property.test.ts index 51702532..09d9567a 100644 --- a/runtime/typescript/packages/core/tests/model/core/object-property.test.ts +++ b/runtime/typescript/packages/core/tests/model/core/object-property.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/core/property.test.ts b/runtime/typescript/packages/core/tests/model/core/property.test.ts index c94e9337..2925a486 100644 --- a/runtime/typescript/packages/core/tests/model/core/property.test.ts +++ b/runtime/typescript/packages/core/tests/model/core/property.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/core/validation-error.test.ts b/runtime/typescript/packages/core/tests/model/core/validation-error.test.ts index 0ac7ef99..fde328f0 100644 --- a/runtime/typescript/packages/core/tests/model/core/validation-error.test.ts +++ b/runtime/typescript/packages/core/tests/model/core/validation-error.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/core/validation-result.test.ts b/runtime/typescript/packages/core/tests/model/core/validation-result.test.ts index 539cb2dd..41ea55c0 100644 --- a/runtime/typescript/packages/core/tests/model/core/validation-result.test.ts +++ b/runtime/typescript/packages/core/tests/model/core/validation-result.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/checkpoint.test.ts b/runtime/typescript/packages/core/tests/model/events/checkpoint.test.ts index 2eb4115b..26c11255 100644 --- a/runtime/typescript/packages/core/tests/model/events/checkpoint.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/checkpoint.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/compaction-complete-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/compaction-complete-payload.test.ts index 77b00a2c..f8f56d98 100644 --- a/runtime/typescript/packages/core/tests/model/events/compaction-complete-payload.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/compaction-complete-payload.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/compaction-failed-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/compaction-failed-payload.test.ts index 1f0ac0a5..211dad76 100644 --- a/runtime/typescript/packages/core/tests/model/events/compaction-failed-payload.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/compaction-failed-payload.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/compaction-start-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/compaction-start-payload.test.ts index 80d53a23..d4b87fb2 100644 --- a/runtime/typescript/packages/core/tests/model/events/compaction-start-payload.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/compaction-start-payload.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/done-event-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/done-event-payload.test.ts index 5719e2d1..6ff23372 100644 --- a/runtime/typescript/packages/core/tests/model/events/done-event-payload.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/done-event-payload.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/error-chunk.test.ts b/runtime/typescript/packages/core/tests/model/events/error-chunk.test.ts index 33526f5b..b0980c7f 100644 --- a/runtime/typescript/packages/core/tests/model/events/error-chunk.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/error-chunk.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/error-event-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/error-event-payload.test.ts index 89197a27..2dee9181 100644 --- a/runtime/typescript/packages/core/tests/model/events/error-event-payload.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/error-event-payload.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/harness-context.test.ts b/runtime/typescript/packages/core/tests/model/events/harness-context.test.ts index 0f0359c2..da18d798 100644 --- a/runtime/typescript/packages/core/tests/model/events/harness-context.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/harness-context.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/hook-end-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/hook-end-payload.test.ts index de9bb3b8..645d8b0e 100644 --- a/runtime/typescript/packages/core/tests/model/events/hook-end-payload.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/hook-end-payload.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/hook-start-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/hook-start-payload.test.ts index 772b0099..77b0ac3c 100644 --- a/runtime/typescript/packages/core/tests/model/events/hook-start-payload.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/hook-start-payload.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/host-tool-request.test.ts b/runtime/typescript/packages/core/tests/model/events/host-tool-request.test.ts index 76c03450..74acbfa4 100644 --- a/runtime/typescript/packages/core/tests/model/events/host-tool-request.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/host-tool-request.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/host-tool-result.test.ts b/runtime/typescript/packages/core/tests/model/events/host-tool-result.test.ts index e6e200f1..95c431cd 100644 --- a/runtime/typescript/packages/core/tests/model/events/host-tool-result.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/host-tool-result.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/llm-complete-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/llm-complete-payload.test.ts index 65b989ab..23953899 100644 --- a/runtime/typescript/packages/core/tests/model/events/llm-complete-payload.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/llm-complete-payload.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/llm-start-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/llm-start-payload.test.ts index fe8003b7..bb7a0c6b 100644 --- a/runtime/typescript/packages/core/tests/model/events/llm-start-payload.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/llm-start-payload.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/messages-updated-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/messages-updated-payload.test.ts index 7e5dafb6..08df2b50 100644 --- a/runtime/typescript/packages/core/tests/model/events/messages-updated-payload.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/messages-updated-payload.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/permission-completed-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/permission-completed-payload.test.ts index 20f1c55a..84e2b7ff 100644 --- a/runtime/typescript/packages/core/tests/model/events/permission-completed-payload.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/permission-completed-payload.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/permission-decision.test.ts b/runtime/typescript/packages/core/tests/model/events/permission-decision.test.ts index 7d14694c..2644d421 100644 --- a/runtime/typescript/packages/core/tests/model/events/permission-decision.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/permission-decision.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/permission-request.test.ts b/runtime/typescript/packages/core/tests/model/events/permission-request.test.ts index 598184c3..aea9ef96 100644 --- a/runtime/typescript/packages/core/tests/model/events/permission-request.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/permission-request.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/permission-requested-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/permission-requested-payload.test.ts index 9e9a71d6..540865ee 100644 --- a/runtime/typescript/packages/core/tests/model/events/permission-requested-payload.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/permission-requested-payload.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/redacted-field.test.ts b/runtime/typescript/packages/core/tests/model/events/redacted-field.test.ts index 950d8492..72c58484 100644 --- a/runtime/typescript/packages/core/tests/model/events/redacted-field.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/redacted-field.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/redaction-metadata.test.ts b/runtime/typescript/packages/core/tests/model/events/redaction-metadata.test.ts index e0fc58d1..aaa2d75b 100644 --- a/runtime/typescript/packages/core/tests/model/events/redaction-metadata.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/redaction-metadata.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/retry-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/retry-payload.test.ts index 453c687a..ef954f14 100644 --- a/runtime/typescript/packages/core/tests/model/events/retry-payload.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/retry-payload.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/session-end-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/session-end-payload.test.ts index ca0bd132..f0386c15 100644 --- a/runtime/typescript/packages/core/tests/model/events/session-end-payload.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/session-end-payload.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/session-event.test.ts b/runtime/typescript/packages/core/tests/model/events/session-event.test.ts index 09fd07ab..2d619091 100644 --- a/runtime/typescript/packages/core/tests/model/events/session-event.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/session-event.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/session-file-ref.test.ts b/runtime/typescript/packages/core/tests/model/events/session-file-ref.test.ts index 26ebb767..e215ea18 100644 --- a/runtime/typescript/packages/core/tests/model/events/session-file-ref.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/session-file-ref.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/session-ref.test.ts b/runtime/typescript/packages/core/tests/model/events/session-ref.test.ts index 14950fbd..0d3ac52d 100644 --- a/runtime/typescript/packages/core/tests/model/events/session-ref.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/session-ref.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/session-start-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/session-start-payload.test.ts index eb551c2e..bc804b7e 100644 --- a/runtime/typescript/packages/core/tests/model/events/session-start-payload.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/session-start-payload.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/session-summary.test.ts b/runtime/typescript/packages/core/tests/model/events/session-summary.test.ts index 140c686a..5d74c979 100644 --- a/runtime/typescript/packages/core/tests/model/events/session-summary.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/session-summary.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/session-trace.test.ts b/runtime/typescript/packages/core/tests/model/events/session-trace.test.ts index 5fbc7867..1284e1ae 100644 --- a/runtime/typescript/packages/core/tests/model/events/session-trace.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/session-trace.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/session-warning-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/session-warning-payload.test.ts index 4f206b18..1b2ab319 100644 --- a/runtime/typescript/packages/core/tests/model/events/session-warning-payload.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/session-warning-payload.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/status-event-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/status-event-payload.test.ts index bf4f7059..fee9fb58 100644 --- a/runtime/typescript/packages/core/tests/model/events/status-event-payload.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/status-event-payload.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/stream-chunk.test.ts b/runtime/typescript/packages/core/tests/model/events/stream-chunk.test.ts index 347fbbae..186574a2 100644 --- a/runtime/typescript/packages/core/tests/model/events/stream-chunk.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/stream-chunk.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/text-chunk.test.ts b/runtime/typescript/packages/core/tests/model/events/text-chunk.test.ts index 54732d5a..7e7f5690 100644 --- a/runtime/typescript/packages/core/tests/model/events/text-chunk.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/text-chunk.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/thinking-chunk.test.ts b/runtime/typescript/packages/core/tests/model/events/thinking-chunk.test.ts index 3d18ceb1..49bfcf71 100644 --- a/runtime/typescript/packages/core/tests/model/events/thinking-chunk.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/thinking-chunk.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/thinking-event-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/thinking-event-payload.test.ts index 0a79e6aa..b9f32d05 100644 --- a/runtime/typescript/packages/core/tests/model/events/thinking-event-payload.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/thinking-event-payload.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/token-event-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/token-event-payload.test.ts index 596ed9b7..218d8e4c 100644 --- a/runtime/typescript/packages/core/tests/model/events/token-event-payload.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/token-event-payload.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/tool-call-complete-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/tool-call-complete-payload.test.ts index f5491a3d..596b349e 100644 --- a/runtime/typescript/packages/core/tests/model/events/tool-call-complete-payload.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/tool-call-complete-payload.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/tool-call-start-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/tool-call-start-payload.test.ts index 0e2fb23f..0c4f7fc2 100644 --- a/runtime/typescript/packages/core/tests/model/events/tool-call-start-payload.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/tool-call-start-payload.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/tool-chunk.test.ts b/runtime/typescript/packages/core/tests/model/events/tool-chunk.test.ts index c64c49b2..ec933714 100644 --- a/runtime/typescript/packages/core/tests/model/events/tool-chunk.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/tool-chunk.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/tool-execution-complete-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/tool-execution-complete-payload.test.ts index a76db616..80e198ff 100644 --- a/runtime/typescript/packages/core/tests/model/events/tool-execution-complete-payload.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/tool-execution-complete-payload.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/tool-execution-start-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/tool-execution-start-payload.test.ts index e14add42..fdee2615 100644 --- a/runtime/typescript/packages/core/tests/model/events/tool-execution-start-payload.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/tool-execution-start-payload.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/tool-result-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/tool-result-payload.test.ts index 647804c7..e61f8778 100644 --- a/runtime/typescript/packages/core/tests/model/events/tool-result-payload.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/tool-result-payload.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/trajectory-event.test.ts b/runtime/typescript/packages/core/tests/model/events/trajectory-event.test.ts index e17f52e0..e53ae938 100644 --- a/runtime/typescript/packages/core/tests/model/events/trajectory-event.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/trajectory-event.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/turn-end-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/turn-end-payload.test.ts index 783f75d1..4a7b8252 100644 --- a/runtime/typescript/packages/core/tests/model/events/turn-end-payload.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/turn-end-payload.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/turn-event.test.ts b/runtime/typescript/packages/core/tests/model/events/turn-event.test.ts index fe8939a7..f432a24c 100644 --- a/runtime/typescript/packages/core/tests/model/events/turn-event.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/turn-event.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/turn-start-payload.test.ts b/runtime/typescript/packages/core/tests/model/events/turn-start-payload.test.ts index fc16c852..588712d8 100644 --- a/runtime/typescript/packages/core/tests/model/events/turn-start-payload.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/turn-start-payload.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/turn-summary.test.ts b/runtime/typescript/packages/core/tests/model/events/turn-summary.test.ts index ea7e3ad5..43c4969c 100644 --- a/runtime/typescript/packages/core/tests/model/events/turn-summary.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/turn-summary.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/events/turn-trace.test.ts b/runtime/typescript/packages/core/tests/model/events/turn-trace.test.ts index af0f92fb..34a79a4e 100644 --- a/runtime/typescript/packages/core/tests/model/events/turn-trace.test.ts +++ b/runtime/typescript/packages/core/tests/model/events/turn-trace.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/model/model-info.test.ts b/runtime/typescript/packages/core/tests/model/model/model-info.test.ts index 553d7ac4..e8a11a04 100644 --- a/runtime/typescript/packages/core/tests/model/model/model-info.test.ts +++ b/runtime/typescript/packages/core/tests/model/model/model-info.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/model/model-options.test.ts b/runtime/typescript/packages/core/tests/model/model/model-options.test.ts index 6eadda6c..a96b7959 100644 --- a/runtime/typescript/packages/core/tests/model/model/model-options.test.ts +++ b/runtime/typescript/packages/core/tests/model/model/model-options.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/model/model.test.ts b/runtime/typescript/packages/core/tests/model/model/model.test.ts index 6cae2cff..0d71d05b 100644 --- a/runtime/typescript/packages/core/tests/model/model/model.test.ts +++ b/runtime/typescript/packages/core/tests/model/model/model.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/model/token-usage.test.ts b/runtime/typescript/packages/core/tests/model/model/token-usage.test.ts index a4ea1ba6..1da6e77c 100644 --- a/runtime/typescript/packages/core/tests/model/model/token-usage.test.ts +++ b/runtime/typescript/packages/core/tests/model/model/token-usage.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/pipeline/compaction-config.test.ts b/runtime/typescript/packages/core/tests/model/pipeline/compaction-config.test.ts index d97b4f05..c055d5cd 100644 --- a/runtime/typescript/packages/core/tests/model/pipeline/compaction-config.test.ts +++ b/runtime/typescript/packages/core/tests/model/pipeline/compaction-config.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/pipeline/turn-options.test.ts b/runtime/typescript/packages/core/tests/model/pipeline/turn-options.test.ts index 7efdc80d..6248d328 100644 --- a/runtime/typescript/packages/core/tests/model/pipeline/turn-options.test.ts +++ b/runtime/typescript/packages/core/tests/model/pipeline/turn-options.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/streaming/stream-options.test.ts b/runtime/typescript/packages/core/tests/model/streaming/stream-options.test.ts index ba97ce57..8bd71335 100644 --- a/runtime/typescript/packages/core/tests/model/streaming/stream-options.test.ts +++ b/runtime/typescript/packages/core/tests/model/streaming/stream-options.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/template/format-config.test.ts b/runtime/typescript/packages/core/tests/model/template/format-config.test.ts index e27c452c..8d211d25 100644 --- a/runtime/typescript/packages/core/tests/model/template/format-config.test.ts +++ b/runtime/typescript/packages/core/tests/model/template/format-config.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/template/parser-config.test.ts b/runtime/typescript/packages/core/tests/model/template/parser-config.test.ts index 4de1997f..bf783689 100644 --- a/runtime/typescript/packages/core/tests/model/template/parser-config.test.ts +++ b/runtime/typescript/packages/core/tests/model/template/parser-config.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/template/template.test.ts b/runtime/typescript/packages/core/tests/model/template/template.test.ts index d04bd9d0..c82a0c52 100644 --- a/runtime/typescript/packages/core/tests/model/template/template.test.ts +++ b/runtime/typescript/packages/core/tests/model/template/template.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/tools/binding.test.ts b/runtime/typescript/packages/core/tests/model/tools/binding.test.ts index dc7c6705..86fb579c 100644 --- a/runtime/typescript/packages/core/tests/model/tools/binding.test.ts +++ b/runtime/typescript/packages/core/tests/model/tools/binding.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/tools/custom-tool.test.ts b/runtime/typescript/packages/core/tests/model/tools/custom-tool.test.ts index f0c7708d..950c3ba4 100644 --- a/runtime/typescript/packages/core/tests/model/tools/custom-tool.test.ts +++ b/runtime/typescript/packages/core/tests/model/tools/custom-tool.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/tools/function-tool.test.ts b/runtime/typescript/packages/core/tests/model/tools/function-tool.test.ts index f43403d7..a9096d0a 100644 --- a/runtime/typescript/packages/core/tests/model/tools/function-tool.test.ts +++ b/runtime/typescript/packages/core/tests/model/tools/function-tool.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/tools/mcp-approval-mode.test.ts b/runtime/typescript/packages/core/tests/model/tools/mcp-approval-mode.test.ts index 3e0d14d3..60d50872 100644 --- a/runtime/typescript/packages/core/tests/model/tools/mcp-approval-mode.test.ts +++ b/runtime/typescript/packages/core/tests/model/tools/mcp-approval-mode.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/tools/mcp-tool.test.ts b/runtime/typescript/packages/core/tests/model/tools/mcp-tool.test.ts index eed2007e..53c93f41 100644 --- a/runtime/typescript/packages/core/tests/model/tools/mcp-tool.test.ts +++ b/runtime/typescript/packages/core/tests/model/tools/mcp-tool.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/tools/open-api-tool.test.ts b/runtime/typescript/packages/core/tests/model/tools/open-api-tool.test.ts index 2f568db8..a2f10210 100644 --- a/runtime/typescript/packages/core/tests/model/tools/open-api-tool.test.ts +++ b/runtime/typescript/packages/core/tests/model/tools/open-api-tool.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/tools/prompty-tool.test.ts b/runtime/typescript/packages/core/tests/model/tools/prompty-tool.test.ts index 3f61b608..d1f58846 100644 --- a/runtime/typescript/packages/core/tests/model/tools/prompty-tool.test.ts +++ b/runtime/typescript/packages/core/tests/model/tools/prompty-tool.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/tools/tool-context.test.ts b/runtime/typescript/packages/core/tests/model/tools/tool-context.test.ts index 7d91c671..81c822f1 100644 --- a/runtime/typescript/packages/core/tests/model/tools/tool-context.test.ts +++ b/runtime/typescript/packages/core/tests/model/tools/tool-context.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/tools/tool-dispatch-result.test.ts b/runtime/typescript/packages/core/tests/model/tools/tool-dispatch-result.test.ts index aef9bfe3..543f7dd6 100644 --- a/runtime/typescript/packages/core/tests/model/tools/tool-dispatch-result.test.ts +++ b/runtime/typescript/packages/core/tests/model/tools/tool-dispatch-result.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/tools/tool.test.ts b/runtime/typescript/packages/core/tests/model/tools/tool.test.ts index 87db7245..683dfcd5 100644 --- a/runtime/typescript/packages/core/tests/model/tools/tool.test.ts +++ b/runtime/typescript/packages/core/tests/model/tools/tool.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/tracing/trace-file.test.ts b/runtime/typescript/packages/core/tests/model/tracing/trace-file.test.ts index 9aaa2d26..ac1fa22c 100644 --- a/runtime/typescript/packages/core/tests/model/tracing/trace-file.test.ts +++ b/runtime/typescript/packages/core/tests/model/tracing/trace-file.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/tracing/trace-span.test.ts b/runtime/typescript/packages/core/tests/model/tracing/trace-span.test.ts index 0a5c0fdb..572a778d 100644 --- a/runtime/typescript/packages/core/tests/model/tracing/trace-span.test.ts +++ b/runtime/typescript/packages/core/tests/model/tracing/trace-span.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/tracing/trace-time.test.ts b/runtime/typescript/packages/core/tests/model/tracing/trace-time.test.ts index 2ba66ff9..12b14fd8 100644 --- a/runtime/typescript/packages/core/tests/model/tracing/trace-time.test.ts +++ b/runtime/typescript/packages/core/tests/model/tracing/trace-time.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/wire/anthropic-image-block.test.ts b/runtime/typescript/packages/core/tests/model/wire/anthropic-image-block.test.ts index 22c37f56..55ae9668 100644 --- a/runtime/typescript/packages/core/tests/model/wire/anthropic-image-block.test.ts +++ b/runtime/typescript/packages/core/tests/model/wire/anthropic-image-block.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/wire/anthropic-image-source.test.ts b/runtime/typescript/packages/core/tests/model/wire/anthropic-image-source.test.ts index c1a3f877..1e66ebdf 100644 --- a/runtime/typescript/packages/core/tests/model/wire/anthropic-image-source.test.ts +++ b/runtime/typescript/packages/core/tests/model/wire/anthropic-image-source.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/wire/anthropic-messages-request.test.ts b/runtime/typescript/packages/core/tests/model/wire/anthropic-messages-request.test.ts index 1bd34776..79e8cf8e 100644 --- a/runtime/typescript/packages/core/tests/model/wire/anthropic-messages-request.test.ts +++ b/runtime/typescript/packages/core/tests/model/wire/anthropic-messages-request.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/wire/anthropic-messages-response.test.ts b/runtime/typescript/packages/core/tests/model/wire/anthropic-messages-response.test.ts index 4a5522cd..dad0b6df 100644 --- a/runtime/typescript/packages/core/tests/model/wire/anthropic-messages-response.test.ts +++ b/runtime/typescript/packages/core/tests/model/wire/anthropic-messages-response.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/wire/anthropic-text-block.test.ts b/runtime/typescript/packages/core/tests/model/wire/anthropic-text-block.test.ts index f15860ef..3f391cbc 100644 --- a/runtime/typescript/packages/core/tests/model/wire/anthropic-text-block.test.ts +++ b/runtime/typescript/packages/core/tests/model/wire/anthropic-text-block.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/wire/anthropic-tool-definition.test.ts b/runtime/typescript/packages/core/tests/model/wire/anthropic-tool-definition.test.ts index b118e7c5..6b9de077 100644 --- a/runtime/typescript/packages/core/tests/model/wire/anthropic-tool-definition.test.ts +++ b/runtime/typescript/packages/core/tests/model/wire/anthropic-tool-definition.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/wire/anthropic-tool-result-block.test.ts b/runtime/typescript/packages/core/tests/model/wire/anthropic-tool-result-block.test.ts index 9d3f0019..cd1c0100 100644 --- a/runtime/typescript/packages/core/tests/model/wire/anthropic-tool-result-block.test.ts +++ b/runtime/typescript/packages/core/tests/model/wire/anthropic-tool-result-block.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/wire/anthropic-tool-use-block.test.ts b/runtime/typescript/packages/core/tests/model/wire/anthropic-tool-use-block.test.ts index c1afe495..cfc33b47 100644 --- a/runtime/typescript/packages/core/tests/model/wire/anthropic-tool-use-block.test.ts +++ b/runtime/typescript/packages/core/tests/model/wire/anthropic-tool-use-block.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/wire/anthropic-usage.test.ts b/runtime/typescript/packages/core/tests/model/wire/anthropic-usage.test.ts index 1f66ac2f..139b7c41 100644 --- a/runtime/typescript/packages/core/tests/model/wire/anthropic-usage.test.ts +++ b/runtime/typescript/packages/core/tests/model/wire/anthropic-usage.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/runtime/typescript/packages/core/tests/model/wire/anthropic-wire-message.test.ts b/runtime/typescript/packages/core/tests/model/wire/anthropic-wire-message.test.ts index 8b6afac9..41cf7807 100644 --- a/runtime/typescript/packages/core/tests/model/wire/anthropic-wire-message.test.ts +++ b/runtime/typescript/packages/core/tests/model/wire/anthropic-wire-message.test.ts @@ -1,3 +1,4 @@ +// // Copyright (c) Microsoft. All rights reserved. // WARNING: This is an auto-generated file. DO NOT EDIT THIS FILE DIRECTLY. diff --git a/schema/model/agent/agent.tsp b/schema/model/agent/agent.tsp index 4c226a97..0a7094e1 100644 --- a/schema/model/agent/agent.tsp +++ b/schema/model/agent/agent.tsp @@ -1,4 +1,4 @@ -import "prompty-emitter"; +import "@typra/emitter"; import "@typespec/json-schema"; import "../core/core.tsp"; import "../model/model.tsp"; diff --git a/schema/model/agent/guardrails.tsp b/schema/model/agent/guardrails.tsp index 650f34a0..e8a6c577 100644 --- a/schema/model/agent/guardrails.tsp +++ b/schema/model/agent/guardrails.tsp @@ -1,4 +1,4 @@ -import "prompty-emitter"; +import "@typra/emitter"; namespace Prompty; diff --git a/schema/model/connection/connection.tsp b/schema/model/connection/connection.tsp index 9358721e..e7489808 100644 --- a/schema/model/connection/connection.tsp +++ b/schema/model/connection/connection.tsp @@ -1,4 +1,4 @@ -import "prompty-emitter"; +import "@typra/emitter"; import "../core/core.tsp"; namespace Prompty; diff --git a/schema/model/connection/foundry.tsp b/schema/model/connection/foundry.tsp index 43b8fcba..f05c8800 100644 --- a/schema/model/connection/foundry.tsp +++ b/schema/model/connection/foundry.tsp @@ -1,4 +1,4 @@ -import "prompty-emitter"; +import "@typra/emitter"; import "./connection.tsp"; namespace Prompty; diff --git a/schema/model/connection/oauth.tsp b/schema/model/connection/oauth.tsp index 366381f4..5551eac2 100644 --- a/schema/model/connection/oauth.tsp +++ b/schema/model/connection/oauth.tsp @@ -1,4 +1,4 @@ -import "prompty-emitter"; +import "@typra/emitter"; import "./connection.tsp"; namespace Prompty; diff --git a/schema/model/conversation/content.tsp b/schema/model/conversation/content.tsp index c339efcb..fd0cb6d3 100644 --- a/schema/model/conversation/content.tsp +++ b/schema/model/conversation/content.tsp @@ -1,4 +1,4 @@ -import "prompty-emitter"; +import "@typra/emitter"; namespace Prompty; diff --git a/schema/model/conversation/message.tsp b/schema/model/conversation/message.tsp index 99cca2af..ae8fdf08 100644 --- a/schema/model/conversation/message.tsp +++ b/schema/model/conversation/message.tsp @@ -1,4 +1,4 @@ -import "prompty-emitter"; +import "@typra/emitter"; import "./content.tsp"; namespace Prompty; diff --git a/schema/model/conversation/thread.tsp b/schema/model/conversation/thread.tsp index 53b8bc67..f9f536e9 100644 --- a/schema/model/conversation/thread.tsp +++ b/schema/model/conversation/thread.tsp @@ -1,4 +1,4 @@ -import "prompty-emitter"; +import "@typra/emitter"; namespace Prompty; diff --git a/schema/model/conversation/tool-invocation.tsp b/schema/model/conversation/tool-invocation.tsp index 7e78c6ff..b8cad53d 100644 --- a/schema/model/conversation/tool-invocation.tsp +++ b/schema/model/conversation/tool-invocation.tsp @@ -1,4 +1,4 @@ -import "prompty-emitter"; +import "@typra/emitter"; import "./content.tsp"; namespace Prompty; diff --git a/schema/model/core/core.tsp b/schema/model/core/core.tsp index e52bf1ec..a595ec16 100644 --- a/schema/model/core/core.tsp +++ b/schema/model/core/core.tsp @@ -1,4 +1,4 @@ -import "prompty-emitter"; +import "@typra/emitter"; namespace Prompty; diff --git a/schema/model/core/errors.tsp b/schema/model/core/errors.tsp index 9d8a552a..ef9bbbd3 100644 --- a/schema/model/core/errors.tsp +++ b/schema/model/core/errors.tsp @@ -1,4 +1,4 @@ -import "prompty-emitter"; +import "@typra/emitter"; namespace Prompty; diff --git a/schema/model/core/properties.tsp b/schema/model/core/properties.tsp index f15f084b..01664da3 100644 --- a/schema/model/core/properties.tsp +++ b/schema/model/core/properties.tsp @@ -1,4 +1,4 @@ -import "prompty-emitter"; +import "@typra/emitter"; import "./core.tsp"; namespace Prompty; diff --git a/schema/model/core/validation.tsp b/schema/model/core/validation.tsp index 1339bb30..8d89ee37 100644 --- a/schema/model/core/validation.tsp +++ b/schema/model/core/validation.tsp @@ -1,4 +1,4 @@ -import "prompty-emitter"; +import "@typra/emitter"; import "./errors.tsp"; namespace Prompty; diff --git a/schema/model/events/payloads.tsp b/schema/model/events/payloads.tsp index ae6d5859..ef113549 100644 --- a/schema/model/events/payloads.tsp +++ b/schema/model/events/payloads.tsp @@ -1,4 +1,4 @@ -import "prompty-emitter"; +import "@typra/emitter"; import "../conversation/message.tsp"; import "../conversation/tool-invocation.tsp"; import "../model/usage.tsp"; diff --git a/schema/model/events/session.tsp b/schema/model/events/session.tsp index 21d032a6..c502d968 100644 --- a/schema/model/events/session.tsp +++ b/schema/model/events/session.tsp @@ -1,4 +1,4 @@ -import "prompty-emitter"; +import "@typra/emitter"; import "../model/usage.tsp"; import "./payloads.tsp"; diff --git a/schema/model/events/stream-chunks.tsp b/schema/model/events/stream-chunks.tsp index df018094..ab88b29c 100644 --- a/schema/model/events/stream-chunks.tsp +++ b/schema/model/events/stream-chunks.tsp @@ -1,4 +1,4 @@ -import "prompty-emitter"; +import "@typra/emitter"; import "../conversation/tool-invocation.tsp"; namespace Prompty; diff --git a/schema/model/model/discovery.tsp b/schema/model/model/discovery.tsp index e3533401..8fb623f5 100644 --- a/schema/model/model/discovery.tsp +++ b/schema/model/model/discovery.tsp @@ -1,4 +1,4 @@ -import "prompty-emitter"; +import "@typra/emitter"; namespace Prompty; diff --git a/schema/model/model/usage.tsp b/schema/model/model/usage.tsp index 80b73a8f..69d5eefa 100644 --- a/schema/model/model/usage.tsp +++ b/schema/model/model/usage.tsp @@ -1,4 +1,4 @@ -import "prompty-emitter"; +import "@typra/emitter"; namespace Prompty; diff --git a/schema/model/pipeline/executor.tsp b/schema/model/pipeline/executor.tsp index 555fb865..357a09cb 100644 --- a/schema/model/pipeline/executor.tsp +++ b/schema/model/pipeline/executor.tsp @@ -1,4 +1,4 @@ -import "prompty-emitter"; +import "@typra/emitter"; import "../agent/agent.tsp"; import "../conversation/message.tsp"; import "../conversation/tool-invocation.tsp"; diff --git a/schema/model/pipeline/harness.tsp b/schema/model/pipeline/harness.tsp index 7bcc4681..6d9066ad 100644 --- a/schema/model/pipeline/harness.tsp +++ b/schema/model/pipeline/harness.tsp @@ -1,4 +1,4 @@ -import "prompty-emitter"; +import "@typra/emitter"; import "../events/payloads.tsp"; import "../events/session.tsp"; diff --git a/schema/model/pipeline/parser.tsp b/schema/model/pipeline/parser.tsp index 566d03ce..ab9caed7 100644 --- a/schema/model/pipeline/parser.tsp +++ b/schema/model/pipeline/parser.tsp @@ -1,4 +1,4 @@ -import "prompty-emitter"; +import "@typra/emitter"; import "../agent/agent.tsp"; import "../conversation/message.tsp"; diff --git a/schema/model/pipeline/processor.tsp b/schema/model/pipeline/processor.tsp index 5ddc4d07..6a04b0fa 100644 --- a/schema/model/pipeline/processor.tsp +++ b/schema/model/pipeline/processor.tsp @@ -1,4 +1,4 @@ -import "prompty-emitter"; +import "@typra/emitter"; import "../agent/agent.tsp"; namespace Prompty; diff --git a/schema/model/pipeline/renderer.tsp b/schema/model/pipeline/renderer.tsp index 1b67bc86..2fbec10b 100644 --- a/schema/model/pipeline/renderer.tsp +++ b/schema/model/pipeline/renderer.tsp @@ -1,4 +1,4 @@ -import "prompty-emitter"; +import "@typra/emitter"; import "../agent/agent.tsp"; namespace Prompty; diff --git a/schema/model/pipeline/turn.tsp b/schema/model/pipeline/turn.tsp index 3eecbcf4..c262a128 100644 --- a/schema/model/pipeline/turn.tsp +++ b/schema/model/pipeline/turn.tsp @@ -1,4 +1,4 @@ -import "prompty-emitter"; +import "@typra/emitter"; namespace Prompty; diff --git a/schema/model/streaming/stream.tsp b/schema/model/streaming/stream.tsp index 7e1222a1..aac8d264 100644 --- a/schema/model/streaming/stream.tsp +++ b/schema/model/streaming/stream.tsp @@ -1,4 +1,4 @@ -import "prompty-emitter"; +import "@typra/emitter"; namespace Prompty; diff --git a/schema/model/template/template.tsp b/schema/model/template/template.tsp index 0d6cf7c8..a5f4bf62 100644 --- a/schema/model/template/template.tsp +++ b/schema/model/template/template.tsp @@ -1,4 +1,4 @@ -import "prompty-emitter"; +import "@typra/emitter"; import "../core/core.tsp"; namespace Prompty; diff --git a/schema/model/tools/dispatch.tsp b/schema/model/tools/dispatch.tsp index e9b6a604..59135160 100644 --- a/schema/model/tools/dispatch.tsp +++ b/schema/model/tools/dispatch.tsp @@ -1,4 +1,4 @@ -import "prompty-emitter"; +import "@typra/emitter"; import "../conversation/message.tsp"; import "../conversation/tool-invocation.tsp"; diff --git a/schema/model/tools/tool.tsp b/schema/model/tools/tool.tsp index 018d9f12..5b324882 100644 --- a/schema/model/tools/tool.tsp +++ b/schema/model/tools/tool.tsp @@ -1,4 +1,4 @@ -import "prompty-emitter"; +import "@typra/emitter"; import "../core/core.tsp"; import "../core/properties.tsp"; import "../connection/connection.tsp"; diff --git a/schema/model/tracing/tracer.tsp b/schema/model/tracing/tracer.tsp index a1599592..dcd5fe93 100644 --- a/schema/model/tracing/tracer.tsp +++ b/schema/model/tracing/tracer.tsp @@ -1,4 +1,4 @@ -import "prompty-emitter"; +import "@typra/emitter"; import "../model/usage.tsp"; namespace Prompty; diff --git a/schema/model/wire/anthropic-types.tsp b/schema/model/wire/anthropic-types.tsp index 43f09c96..f497d331 100644 --- a/schema/model/wire/anthropic-types.tsp +++ b/schema/model/wire/anthropic-types.tsp @@ -1,4 +1,4 @@ -import "prompty-emitter"; +import "@typra/emitter"; namespace Prompty; diff --git a/schema/model/wire/anthropic.tsp b/schema/model/wire/anthropic.tsp index 60e020aa..973354d7 100644 --- a/schema/model/wire/anthropic.tsp +++ b/schema/model/wire/anthropic.tsp @@ -1,4 +1,4 @@ -import "prompty-emitter"; +import "@typra/emitter"; import "../model/model.tsp"; import "../model/usage.tsp"; diff --git a/schema/model/wire/openai.tsp b/schema/model/wire/openai.tsp index a36679ed..9046c6e1 100644 --- a/schema/model/wire/openai.tsp +++ b/schema/model/wire/openai.tsp @@ -1,4 +1,4 @@ -import "prompty-emitter"; +import "@typra/emitter"; import "../model/model.tsp"; import "../model/usage.tsp"; diff --git a/schema/package-lock.json b/schema/package-lock.json index 40e7f52d..6e6fac86 100644 --- a/schema/package-lock.json +++ b/schema/package-lock.json @@ -8,41 +8,11 @@ "dependencies": { "@typespec/compiler": "latest", "@typespec/json-schema": "latest", - "prompty-emitter": "file:./emitter" - } - }, - "emitter": { - "name": "prompty-emitter", - "version": "0.2.0", - "license": "MIT", - "dependencies": { - "xml-formatter": "^3.6.7", - "yaml": "^2.8.1" - }, - "bin": { - "prompty-generate": "dist/src/cli.js" - }, - "devDependencies": { - "@types/node": "^24.7.0", - "@typescript-eslint/eslint-plugin": "^8.15.0", - "@typescript-eslint/parser": "^8.15.0", - "@typespec/compiler": "latest", - "@typespec/json-schema": "^1.8.0", - "eslint": "^9.15.0", - "markdownlint-cli": "^0.48.0", - "prettier": "^3.3.3", - "typescript": "^5.3.3", - "typescript-eslint": "^8.54.0" - }, - "peerDependencies": { - "@typespec/compiler": "latest", - "@typespec/json-schema": "latest" + "@typra/emitter": "0.2.4" } }, "node_modules/@babel/code-frame": { "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", - "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", @@ -55,314 +25,33 @@ }, "node_modules/@babel/helper-validator-identifier": { "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", - "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", - "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/config-array": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", - "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/object-schema": "^2.1.7", - "debug": "^4.3.1", - "minimatch": "^3.1.5" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/config-array/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", - "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/config-array/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@eslint/config-helpers": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", - "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.17.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/core": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", - "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", - "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.14.0", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.1", - "minimatch": "^3.1.5", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@eslint/eslintrc/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", - "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/eslintrc/node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@eslint/js": { - "version": "9.39.4", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", - "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - } - }, - "node_modules/@eslint/object-schema": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", - "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/plugin-kit": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", - "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.17.0", - "levn": "^0.4.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@humanfs/core": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node": { - "version": "0.16.7", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", - "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/core": "^0.19.1", - "@humanwhocodes/retry": "^0.4.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/retry": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", - "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, "node_modules/@inquirer/ansi": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-2.0.4.tgz", - "integrity": "sha512-DpcZrQObd7S0R/U3bFdkcT5ebRwbTTC4D3tCc1vsJizmgPLxNJBo+AAFmrZwe8zk30P2QzgzGWZ3Q9uJwWuhIg==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-2.0.7.tgz", + "integrity": "sha512-3eTuUO1vH2cZm2ZKHeQxnOqlTi9EfZDGgIe3BL3I4u+rJHocr9Fz86M4fjYABPvFnQG/gGK551HqDiIcETwU6Q==", "license": "MIT", "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" } }, "node_modules/@inquirer/checkbox": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-5.1.2.tgz", - "integrity": "sha512-PubpMPO2nJgMufkoB3P2wwxNXEMUXnBIKi/ACzDUYfaoPuM7gSTmuxJeMscoLVEsR4qqrCMf5p0SiYGWnVJ8kw==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-5.2.1.tgz", + "integrity": "sha512-b6xmA/VlTe0ZgDQHDui+Nav470u7u49nRd8/iuhOcQPO9Ch7lGuogydhi2VOmNlZ+zXcM8IcPuNSwQcdJaF/kw==", "license": "MIT", "dependencies": { - "@inquirer/ansi": "^2.0.4", - "@inquirer/core": "^11.1.7", - "@inquirer/figures": "^2.0.4", - "@inquirer/type": "^4.0.4" + "@inquirer/ansi": "^2.0.7", + "@inquirer/core": "^11.2.1", + "@inquirer/figures": "^2.0.7", + "@inquirer/type": "^4.0.7" }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" }, "peerDependencies": { "@types/node": ">=18" @@ -374,16 +63,16 @@ } }, "node_modules/@inquirer/confirm": { - "version": "6.0.10", - "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-6.0.10.tgz", - "integrity": "sha512-tiNyA73pgpQ0FQ7axqtoLUe4GDYjNCDcVsbgcA5anvwg2z6i+suEngLKKJrWKJolT//GFPZHwN30binDIHgSgQ==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-6.1.1.tgz", + "integrity": "sha512-eb8DBZcz/2qHWQda4rk2JiQk5h9QV/cVHi1yjt0f69WFZMRFn0sJTye3EAP8icut8UDMjQPsaH5KbcOogefrFQ==", "license": "MIT", "dependencies": { - "@inquirer/core": "^11.1.7", - "@inquirer/type": "^4.0.4" + "@inquirer/core": "^11.2.1", + "@inquirer/type": "^4.0.7" }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" }, "peerDependencies": { "@types/node": ">=18" @@ -395,21 +84,21 @@ } }, "node_modules/@inquirer/core": { - "version": "11.1.7", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-11.1.7.tgz", - "integrity": "sha512-1BiBNDk9btIwYIzNZpkikIHXWeNzNncJePPqwDyVMhXhD1ebqbpn1mKGctpoqAbzywZfdG0O4tvmsGIcOevAPQ==", + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-11.2.1.tgz", + "integrity": "sha512-Qd6GJT1yVyrZZCfN8W2qKF5ApmqryXRhRKCuip8h01x2w/esJQ2XIYc6f9abMIHgKQdBfFTSOdbHRLAhuM09UA==", "license": "MIT", "dependencies": { - "@inquirer/ansi": "^2.0.4", - "@inquirer/figures": "^2.0.4", - "@inquirer/type": "^4.0.4", + "@inquirer/ansi": "^2.0.7", + "@inquirer/figures": "^2.0.7", + "@inquirer/type": "^4.0.7", "cli-width": "^4.1.0", "fast-wrap-ansi": "^0.2.0", "mute-stream": "^3.0.0", "signal-exit": "^4.1.0" }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" }, "peerDependencies": { "@types/node": ">=18" @@ -421,17 +110,17 @@ } }, "node_modules/@inquirer/editor": { - "version": "5.0.10", - "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-5.0.10.tgz", - "integrity": "sha512-VJx4XyaKea7t8hEApTw5dxeIyMtWXre2OiyJcICCRZI4hkoHsMoCnl/KbUnJJExLbH9csLLHMVR144ZhFE1CwA==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-5.2.2.tgz", + "integrity": "sha512-ZRVd/oD+sYsUd5zVm0NflqEzlqfYCyHNsqkHl2oWXEUHs12tCbcSFi+wVFEvD8+LGRaMUsVrE7qeo6lSG/S1Vg==", "license": "MIT", "dependencies": { - "@inquirer/core": "^11.1.7", - "@inquirer/external-editor": "^2.0.4", - "@inquirer/type": "^4.0.4" + "@inquirer/core": "^11.2.1", + "@inquirer/external-editor": "^3.0.3", + "@inquirer/type": "^4.0.7" }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" }, "peerDependencies": { "@types/node": ">=18" @@ -443,16 +132,16 @@ } }, "node_modules/@inquirer/expand": { - "version": "5.0.10", - "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-5.0.10.tgz", - "integrity": "sha512-fC0UHJPXsTRvY2fObiwuQYaAnHrp3aDqfwKUJSdfpgv18QUG054ezGbaRNStk/BKD5IPijeMKWej8VV8O5Q/eQ==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-5.1.1.tgz", + "integrity": "sha512-YmQpenjbFSHAK3sOd44puHh3V1KXXr+JiNpUztoSQ4drLh2rTVzTap/YtlAVu/5xavifIlBfNEzJ/neZJ1a/1g==", "license": "MIT", "dependencies": { - "@inquirer/core": "^11.1.7", - "@inquirer/type": "^4.0.4" + "@inquirer/core": "^11.2.1", + "@inquirer/type": "^4.0.7" }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" }, "peerDependencies": { "@types/node": ">=18" @@ -464,16 +153,16 @@ } }, "node_modules/@inquirer/external-editor": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-2.0.4.tgz", - "integrity": "sha512-Prenuv9C1PHj2Itx0BcAOVBTonz02Hc2Nd2DbU67PdGUaqn0nPCnV34oDyyoaZHnmfRxkpuhh/u51ThkrO+RdA==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-3.0.3.tgz", + "integrity": "sha512-6thf5I8q7lZwzGLAxPaaGEREEkZ3nyePPDQ1oyobblxmEE8mqTLguScP7pDjUTAibiyb4hfXl+qjUEJ+di/aNA==", "license": "MIT", "dependencies": { "chardet": "^2.1.1", "iconv-lite": "^0.7.2" }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" }, "peerDependencies": { "@types/node": ">=18" @@ -485,25 +174,25 @@ } }, "node_modules/@inquirer/figures": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-2.0.4.tgz", - "integrity": "sha512-eLBsjlS7rPS3WEhmOmh1znQ5IsQrxWzxWDxO51e4urv+iVrSnIHbq4zqJIOiyNdYLa+BVjwOtdetcQx1lWPpiQ==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-2.0.7.tgz", + "integrity": "sha512-aJ8TBPOGB6f/2qziPfElISTCEd5XOYTFckA2SGjhNmiKzfK/u4ot3v0DUzGVdUnKjN10EqnnEPck36BkyfLnJw==", "license": "MIT", "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" } }, "node_modules/@inquirer/input": { - "version": "5.0.10", - "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-5.0.10.tgz", - "integrity": "sha512-nvZ6qEVeX/zVtZ1dY2hTGDQpVGD3R7MYPLODPgKO8Y+RAqxkrP3i/3NwF3fZpLdaMiNuK0z2NaYIx9tPwiSegQ==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-5.1.2.tgz", + "integrity": "sha512-9K/DDBSQpOyZSkt6sOVP9Vo0TR7atX2kuILsUu0x3wVcVbe97lJwIJKMLdMw25tDYuXl/qp6erT0Xs1rfmcfZg==", "license": "MIT", "dependencies": { - "@inquirer/core": "^11.1.7", - "@inquirer/type": "^4.0.4" + "@inquirer/core": "^11.2.1", + "@inquirer/type": "^4.0.7" }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" }, "peerDependencies": { "@types/node": ">=18" @@ -515,16 +204,16 @@ } }, "node_modules/@inquirer/number": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-4.0.10.tgz", - "integrity": "sha512-Ht8OQstxiS3APMGjHV0aYAjRAysidWdwurWEo2i8yI5xbhOBWqizT0+MU1S2GCcuhIBg+3SgWVjEoXgfhY+XaA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-4.1.1.tgz", + "integrity": "sha512-XF4IXAbPnGPgw0wsbC/i2tPcyfdZgDpUlhsqU0SfT4IRIGWha6Xm9VRgN5yYxJq+jnyXlfXI/nQ3ulfk0iEICA==", "license": "MIT", "dependencies": { - "@inquirer/core": "^11.1.7", - "@inquirer/type": "^4.0.4" + "@inquirer/core": "^11.2.1", + "@inquirer/type": "^4.0.7" }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" }, "peerDependencies": { "@types/node": ">=18" @@ -536,17 +225,17 @@ } }, "node_modules/@inquirer/password": { - "version": "5.0.10", - "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-5.0.10.tgz", - "integrity": "sha512-QbNyvIE8q2GTqKLYSsA8ATG+eETo+m31DSR0+AU7x3d2FhaTWzqQek80dj3JGTo743kQc6mhBR0erMjYw5jQ0A==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-5.1.1.tgz", + "integrity": "sha512-3XBfF7DAsp5qeDsvN5Rd1HmbNokVvEQoUM0QLrRcybC9nX96w3Pbmu7qUsb3IT3J3jBvs2+mTXaKHOUsgHMLzg==", "license": "MIT", "dependencies": { - "@inquirer/ansi": "^2.0.4", - "@inquirer/core": "^11.1.7", - "@inquirer/type": "^4.0.4" + "@inquirer/ansi": "^2.0.7", + "@inquirer/core": "^11.2.1", + "@inquirer/type": "^4.0.7" }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" }, "peerDependencies": { "@types/node": ">=18" @@ -558,24 +247,24 @@ } }, "node_modules/@inquirer/prompts": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-8.3.2.tgz", - "integrity": "sha512-yFroiSj2iiBFlm59amdTvAcQFvWS6ph5oKESls/uqPBect7rTU2GbjyZO2DqxMGuIwVA8z0P4K6ViPcd/cp+0w==", + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-8.5.2.tgz", + "integrity": "sha512-IYR/3C/paEVVQYQvdDlFZVjRCJVYHHON0XXMH91KO9GSxs0TdKYWlUdvfQl2EfAHDxUaN3IBffkE/BDTh5nJ6g==", "license": "MIT", "dependencies": { - "@inquirer/checkbox": "^5.1.2", - "@inquirer/confirm": "^6.0.10", - "@inquirer/editor": "^5.0.10", - "@inquirer/expand": "^5.0.10", - "@inquirer/input": "^5.0.10", - "@inquirer/number": "^4.0.10", - "@inquirer/password": "^5.0.10", - "@inquirer/rawlist": "^5.2.6", - "@inquirer/search": "^4.1.6", - "@inquirer/select": "^5.1.2" + "@inquirer/checkbox": "^5.2.1", + "@inquirer/confirm": "^6.1.1", + "@inquirer/editor": "^5.2.2", + "@inquirer/expand": "^5.1.1", + "@inquirer/input": "^5.1.2", + "@inquirer/number": "^4.1.1", + "@inquirer/password": "^5.1.1", + "@inquirer/rawlist": "^5.3.1", + "@inquirer/search": "^4.2.1", + "@inquirer/select": "^5.2.1" }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" }, "peerDependencies": { "@types/node": ">=18" @@ -587,16 +276,16 @@ } }, "node_modules/@inquirer/rawlist": { - "version": "5.2.6", - "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-5.2.6.tgz", - "integrity": "sha512-jfw0MLJ5TilNsa9zlJ6nmRM0ZFVZhhTICt4/6CU2Dv1ndY7l3sqqo1gIYZyMMDw0LvE1u1nzJNisfHEhJIxq5w==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-5.3.1.tgz", + "integrity": "sha512-QqdTqQddL3qPX/PPrjobpsO25NZ4dWXgTLenrR445L2ptLEYE6Z+PD5c5CNDJNx4ugRgELAIpSIJxZaO2jJ2Og==", "license": "MIT", "dependencies": { - "@inquirer/core": "^11.1.7", - "@inquirer/type": "^4.0.4" + "@inquirer/core": "^11.2.1", + "@inquirer/type": "^4.0.7" }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" }, "peerDependencies": { "@types/node": ">=18" @@ -608,17 +297,17 @@ } }, "node_modules/@inquirer/search": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-4.1.6.tgz", - "integrity": "sha512-3/6kTRae98hhDevENScy7cdFEuURnSpM3JbBNg8yfXLw88HgTOl+neUuy/l9W0No5NzGsLVydhBzTIxZP7yChQ==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-4.2.1.tgz", + "integrity": "sha512-xJj8QWKRSrfKoBIITLZK61dD3zwo0Rz11fgDImku30/Oe81zMdIdGgrLY2h6RkJ+KZ/GhNYIRMKnH/62qBTA5g==", "license": "MIT", "dependencies": { - "@inquirer/core": "^11.1.7", - "@inquirer/figures": "^2.0.4", - "@inquirer/type": "^4.0.4" + "@inquirer/core": "^11.2.1", + "@inquirer/figures": "^2.0.7", + "@inquirer/type": "^4.0.7" }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" }, "peerDependencies": { "@types/node": ">=18" @@ -630,18 +319,18 @@ } }, "node_modules/@inquirer/select": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-5.1.2.tgz", - "integrity": "sha512-kTK8YIkHV+f02y7bWCh7E0u2/11lul5WepVTclr3UMBtBr05PgcZNWfMa7FY57ihpQFQH/spLMHTcr0rXy50tA==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-5.2.1.tgz", + "integrity": "sha512-FlDndEUww8m7BfukO2nJa25vhD+H5jxxCv4oGioKqzyWz3nPHhhw4LKdYRSlXuAx7DsdWia7iyaBPKKS95Evfw==", "license": "MIT", "dependencies": { - "@inquirer/ansi": "^2.0.4", - "@inquirer/core": "^11.1.7", - "@inquirer/figures": "^2.0.4", - "@inquirer/type": "^4.0.4" + "@inquirer/ansi": "^2.0.7", + "@inquirer/core": "^11.2.1", + "@inquirer/figures": "^2.0.7", + "@inquirer/type": "^4.0.7" }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" }, "peerDependencies": { "@types/node": ">=18" @@ -653,12 +342,12 @@ } }, "node_modules/@inquirer/type": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.0.4.tgz", - "integrity": "sha512-PamArxO3cFJZoOzspzo6cxVlLeIftyBsZw/S9bKY5DzxqJVZgjoj1oP8d0rskKtp7sZxBycsoer1g6UeJV1BBA==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.0.7.tgz", + "integrity": "sha512-t28inv14nMQ1PhKpsJPY+kEs/c00qzeCOS2gTNRyTjG5d6qsVA2fItxW4hkvGZ5lvanGLdtCzVIx5dwdRpN1+g==", "license": "MIT", "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" }, "peerDependencies": { "@types/node": ">=18" @@ -671,8 +360,6 @@ }, "node_modules/@isaacs/fs-minipass": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", - "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", "license": "ISC", "dependencies": { "minipass": "^7.0.4" @@ -681,2481 +368,318 @@ "node": ">=18.0.0" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "node_modules/@typespec/asset-emitter": { + "version": "0.79.1", "license": "MIT", "engines": { - "node": ">= 8" + "node": ">=20.0.0" + }, + "peerDependencies": { + "@typespec/compiler": "^1.10.0" } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "node_modules/@typespec/compiler": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/@typespec/compiler/-/compiler-1.13.0.tgz", + "integrity": "sha512-DonoHiyAMx0UjSmssqTrFtya+v97wny1aHcTLU5QF2wFzLATtcwUU9hbPC+eXhepuTunMOCHf8yk3pEsH6PZYA==", "license": "MIT", + "peer": true, "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" + "@babel/code-frame": "^7.29.0", + "@inquirer/prompts": "^8.4.1", + "ajv": "^8.18.0", + "change-case": "^5.4.4", + "env-paths": "^4.0.0", + "is-unicode-supported": "^2.1.0", + "mustache": "^4.2.0", + "picocolors": "^1.1.1", + "prettier": "^3.8.1", + "semver": "^7.7.4", + "tar": "^7.5.13", + "temporal-polyfill": "^0.3.2", + "vscode-languageserver": "^9.0.1", + "vscode-languageserver-textdocument": "^1.0.12", + "yaml": "^2.8.3", + "yargs": "^18.0.0" }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@sindresorhus/merge-streams": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", - "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", - "license": "MIT", - "engines": { - "node": ">=18" + "bin": { + "tsp": "cmd/tsp.js", + "tsp-server": "cmd/tsp-server.js" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@types/debug": { - "version": "4.1.13", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", - "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/ms": "*" - } - }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/katex": { - "version": "0.16.8", - "resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.8.tgz", - "integrity": "sha512-trgaNyfU+Xh2Tc+ABIb44a5AYUpicB3uwirOioeOkNPPbmgRNtcWyDeeFRzjPZENO9Vq8gvVqfhaaXWLlevVwg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/ms": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", - "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "24.12.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.0.tgz", - "integrity": "sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "undici-types": "~7.16.0" + "engines": { + "node": ">=22.0.0" } }, - "node_modules/@types/unist": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", - "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.57.2.tgz", - "integrity": "sha512-NZZgp0Fm2IkD+La5PR81sd+g+8oS6JwJje+aRWsDocxHkjyRw0J5L5ZTlN3LI1LlOcGL7ph3eaIUmTXMIjLk0w==", - "dev": true, + "node_modules/@typespec/json-schema": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/@typespec/json-schema/-/json-schema-1.13.0.tgz", + "integrity": "sha512-o5yxs4aGhfFTkVNAkpFlO3LP2O8kWHQUgBzZ0s6tcbFlElGH86jUsdesT8O5ijoA0Cpa//m39wwxIcmBB2DiiA==", "license": "MIT", + "peer": true, "dependencies": { - "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.57.2", - "@typescript-eslint/type-utils": "8.57.2", - "@typescript-eslint/utils": "8.57.2", - "@typescript-eslint/visitor-keys": "8.57.2", - "ignore": "^7.0.5", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.4.0" + "@typespec/asset-emitter": "^0.79.1", + "yaml": "^2.8.3" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=22.0.0" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.57.2", - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "@typespec/compiler": "^1.13.0" } }, - "node_modules/@typescript-eslint/parser": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.57.2.tgz", - "integrity": "sha512-30ScMRHIAD33JJQkgfGW1t8CURZtjc2JpTrq5n2HFhOefbAhb7ucc7xJwdWcrEtqUIYJ73Nybpsggii6GtAHjA==", - "dev": true, + "node_modules/@typra/emitter": { + "version": "0.2.4", "license": "MIT", - "peer": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.57.2", - "@typescript-eslint/types": "8.57.2", - "@typescript-eslint/typescript-estree": "8.57.2", - "@typescript-eslint/visitor-keys": "8.57.2", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "xml-formatter": "^3.6.7", + "yaml": "^2.8.1" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "bin": { + "typra-generate": "dist/src/cli.js" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "@typespec/compiler": "latest", + "@typespec/json-schema": "latest" } }, - "node_modules/@typescript-eslint/project-service": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.57.2.tgz", - "integrity": "sha512-FuH0wipFywXRTHf+bTTjNyuNQQsQC3qh/dYzaM4I4W0jrCqjCVuUh99+xd9KamUfmCGPvbO8NDngo/vsnNVqgw==", - "dev": true, + "node_modules/ajv": { + "version": "8.18.0", "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.57.2", - "@typescript-eslint/types": "^8.57.2", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.57.2.tgz", - "integrity": "sha512-snZKH+W4WbWkrBqj4gUNRIGb/jipDW3qMqVJ4C9rzdFc+wLwruxk+2a5D+uoFcKPAqyqEnSb4l2ULuZf95eSkw==", - "dev": true, + "node_modules/ansi-regex": { + "version": "6.2.2", "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.57.2", - "@typescript-eslint/visitor-keys": "8.57.2" - }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=12" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.57.2.tgz", - "integrity": "sha512-3Lm5DSM+DCowsUOJC+YqHHnKEfFh5CoGkj5Z31NQSNF4l5wdOwqGn99wmwN/LImhfY3KJnmordBq/4+VDe2eKw==", - "dev": true, + "node_modules/ansi-styles": { + "version": "6.2.3", "license": "MIT", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=12" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.57.2.tgz", - "integrity": "sha512-Co6ZCShm6kIbAM/s+oYVpKFfW7LBc6FXoPXjTRQ449PPNBY8U0KZXuevz5IFuuUj2H9ss40atTaf9dlGLzbWZg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.57.2", - "@typescript-eslint/typescript-estree": "8.57.2", - "@typescript-eslint/utils": "8.57.2", - "debug": "^4.4.3", - "ts-api-utils": "^2.4.0" - }, + "node_modules/change-case": { + "version": "5.4.4", + "license": "MIT" + }, + "node_modules/chardet": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.2.0.tgz", + "integrity": "sha512-rddelWYNPRrXq6PtNEN2S3f6t9ILzvqaN5pVgi4kqt9jHQaXIial9PznB5iSPVlQSLNaaH22ItWz3EJtQ10+OA==", + "license": "MIT" + }, + "node_modules/chownr": { + "version": "3.0.0", + "license": "BlueOak-1.0.0", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "node": ">=18" } }, - "node_modules/@typescript-eslint/types": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.57.2.tgz", - "integrity": "sha512-/iZM6FnM4tnx9csuTxspMW4BOSegshwX5oBDznJ7S4WggL7Vczz5d2W11ecc4vRrQMQHXRSxzrCsyG5EsPPTbA==", - "dev": true, - "license": "MIT", + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "license": "ISC", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">= 12" } }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.57.2.tgz", - "integrity": "sha512-2MKM+I6g8tJxfSmFKOnHv2t8Sk3T6rF20A1Puk0svLK+uVapDZB/4pfAeB7nE83uAZrU6OxW+HmOd5wHVdXwXA==", - "dev": true, - "license": "MIT", + "node_modules/cliui": { + "version": "9.0.1", + "license": "ISC", "dependencies": { - "@typescript-eslint/project-service": "8.57.2", - "@typescript-eslint/tsconfig-utils": "8.57.2", - "@typescript-eslint/types": "8.57.2", - "@typescript-eslint/visitor-keys": "8.57.2", - "debug": "^4.4.3", - "minimatch": "^10.2.2", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.4.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.57.2.tgz", - "integrity": "sha512-krRIbvPK1ju1WBKIefiX+bngPs+odIQUtR7kymzPfo1POVw3jlF+nLkmexdSSd4UCbDcQn+wMBATOOmpBbqgKg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.57.2", - "@typescript-eslint/types": "8.57.2", - "@typescript-eslint/typescript-estree": "8.57.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.57.2.tgz", - "integrity": "sha512-zhahknjobV2FiD6Ee9iLbS7OV9zi10rG26odsQdfBO/hjSzUQbkIYgda+iNKK1zNiW2ey+Lf8MU5btN17V3dUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.57.2", - "eslint-visitor-keys": "^5.0.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", - "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@typespec/asset-emitter": { - "version": "0.79.1", - "resolved": "https://registry.npmjs.org/@typespec/asset-emitter/-/asset-emitter-0.79.1.tgz", - "integrity": "sha512-53s3GLu5BwNkl7Itr/OizfhymTV2u7k5/cwjUOAt03AUDfiKlwbsp+iCIsq1vccJuoDOiXOceJOfL8rAf4/9LQ==", - "license": "MIT", - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "@typespec/compiler": "^1.10.0" - } - }, - "node_modules/@typespec/compiler": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@typespec/compiler/-/compiler-1.10.0.tgz", - "integrity": "sha512-R6BATDkughntPpaxeESJF+wxma5PEjgmnnKvH0/ByqUH8VyhIckQWE9kkP0Uc/EJ0o0VYhe8qCwWQvV70k5lTw==", - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/code-frame": "~7.29.0", - "@inquirer/prompts": "^8.0.1", - "ajv": "~8.18.0", - "change-case": "~5.4.4", - "env-paths": "^4.0.0", - "globby": "~16.1.0", - "is-unicode-supported": "^2.1.0", - "mustache": "~4.2.0", - "picocolors": "~1.1.1", - "prettier": "~3.8.0", - "semver": "^7.7.1", - "tar": "^7.5.2", - "temporal-polyfill": "^0.3.0", - "vscode-languageserver": "~9.0.1", - "vscode-languageserver-textdocument": "~1.0.12", - "yaml": "~2.8.2", - "yargs": "~18.0.0" - }, - "bin": { - "tsp": "cmd/tsp.js", - "tsp-server": "cmd/tsp-server.js" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@typespec/json-schema": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@typespec/json-schema/-/json-schema-1.10.0.tgz", - "integrity": "sha512-FZTJvZoIqMbe/4qi17e8q3KF/2VDSyXiiF8QYwH4lar5dtEDGgwrw9ShLeLNiEZh8Ph3GjrQQV5qdpheDFJJvw==", - "license": "MIT", - "dependencies": { - "@typespec/asset-emitter": "^0.79.1", - "yaml": "~2.8.2" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "@typespec/compiler": "^1.10.0" - } - }, - "node_modules/acorn": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", - "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", - "dev": true, - "license": "MIT", - "peer": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/brace-expansion": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", - "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chalk/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/change-case": { - "version": "5.4.4", - "resolved": "https://registry.npmjs.org/change-case/-/change-case-5.4.4.tgz", - "integrity": "sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==", - "license": "MIT" - }, - "node_modules/character-entities": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", - "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", - "dev": true, - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/character-entities-legacy": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", - "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", - "dev": true, - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/character-reference-invalid": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", - "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", - "dev": true, - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/chardet": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.1.tgz", - "integrity": "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==", - "license": "MIT" - }, - "node_modules/chownr": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", - "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } - }, - "node_modules/cli-width": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", - "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", - "license": "ISC", - "engines": { - "node": ">= 12" - } - }, - "node_modules/cliui": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", - "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", - "license": "ISC", - "dependencies": { - "string-width": "^7.2.0", - "strip-ansi": "^7.1.0", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/commander": { - "version": "14.0.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", - "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decode-named-character-reference": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", - "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "character-entities": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/devlop": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", - "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", - "dev": true, - "license": "MIT", - "dependencies": { - "dequal": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/emoji-regex": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "license": "MIT" - }, - "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/env-paths": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-4.0.0.tgz", - "integrity": "sha512-pxP8eL2SwwaTRi/KHYwLYXinDs7gL3jxFcBYmEdYfZmZXbaVDvdppd0XBU8qVz03rDfKZMXg1omHCbsJjZrMsw==", - "license": "MIT", - "dependencies": { - "is-safe-filename": "^0.1.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "9.39.4", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", - "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.8.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.2", - "@eslint/config-helpers": "^0.4.2", - "@eslint/core": "^0.17.0", - "@eslint/eslintrc": "^3.3.5", - "@eslint/js": "9.39.4", - "@eslint/plugin-kit": "^0.4.1", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@types/estree": "^1.0.6", - "ajv": "^6.14.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.4.0", - "eslint-visitor-keys": "^4.2.1", - "espree": "^10.4.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.5", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "node_modules/eslint-scope": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", - "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/ajv": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/eslint/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", - "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/eslint/node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/eslint/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/espree": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.15.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", - "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "license": "MIT" - }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-string-truncated-width": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz", - "integrity": "sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==", - "license": "MIT" - }, - "node_modules/fast-string-width": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/fast-string-width/-/fast-string-width-3.0.2.tgz", - "integrity": "sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==", - "license": "MIT", - "dependencies": { - "fast-string-truncated-width": "^3.0.2" - } - }, - "node_modules/fast-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", - "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/fast-wrap-ansi": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.2.0.tgz", - "integrity": "sha512-rLV8JHxTyhVmFYhBJuMujcrHqOT2cnO5Zxj37qROj23CP39GXubJRBUFF0z8KFK77Uc0SukZUf7JZhsVEQ6n8w==", - "license": "MIT", - "dependencies": { - "fast-string-width": "^3.0.2" - } - }, - "node_modules/fastq": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", - "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/flatted": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", - "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", - "dev": true, - "license": "ISC" - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-east-asian-width": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz", - "integrity": "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby": { - "version": "16.1.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-16.1.1.tgz", - "integrity": "sha512-dW7vl+yiAJSp6aCekaVnVJxurRv7DCOLyXqEG3RYMYUg7AuJ2jCqPkZTA8ooqC2vtnkaMcV5WfFBMuEnTu1OQg==", - "license": "MIT", - "dependencies": { - "@sindresorhus/merge-streams": "^4.0.0", - "fast-glob": "^3.3.3", - "ignore": "^7.0.5", - "is-path-inside": "^4.0.0", - "slash": "^5.1.0", - "unicorn-magic": "^0.4.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/iconv-lite": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", - "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/ini": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz", - "integrity": "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/is-alphabetical": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", - "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", - "dev": true, - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-alphanumerical": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", - "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-alphabetical": "^2.0.0", - "is-decimal": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-decimal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", - "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", - "dev": true, - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-hexadecimal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", - "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", - "dev": true, - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-path-inside": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz", - "integrity": "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-safe-filename": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-safe-filename/-/is-safe-filename-0.1.1.tgz", - "integrity": "sha512-4SrR7AdnY11LHfDKTZY1u6Ga3RuxZdl3YKWWShO5iyuG5h8QS4GD2tOb04peBJ5I7pXbR+CGBNEhTcwK+FzN3g==", - "license": "MIT", - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-unicode-supported": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", - "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/jsonc-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", - "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/jsonpointer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", - "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/katex": { - "version": "0.16.45", - "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.45.tgz", - "integrity": "sha512-pQpZbdBu7wCTmQUh7ufPmLr0pFoObnGUoL/yhtwJDgmmQpbkg/0HSVti25Fu4rmd1oCR6NGWe9vqTWuWv3GcNA==", - "dev": true, - "funding": [ - "https://opencollective.com/katex", - "https://github.com/sponsors/katex" - ], - "license": "MIT", - "dependencies": { - "commander": "^8.3.0" - }, - "bin": { - "katex": "cli.js" - } - }, - "node_modules/katex/node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/linkify-it": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", - "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "uc.micro": "^2.0.0" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/markdown-it": { - "version": "14.1.1", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.1.tgz", - "integrity": "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1", - "entities": "^4.4.0", - "linkify-it": "^5.0.0", - "mdurl": "^2.0.0", - "punycode.js": "^2.3.1", - "uc.micro": "^2.1.0" - }, - "bin": { - "markdown-it": "bin/markdown-it.mjs" - } - }, - "node_modules/markdownlint": { - "version": "0.40.0", - "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.40.0.tgz", - "integrity": "sha512-UKybllYNheWac61Ia7T6fzuQNDZimFIpCg2w6hHjgV1Qu0w1TV0LlSgryUGzM0bkKQCBhy2FDhEELB73Kb0kAg==", - "dev": true, - "license": "MIT", - "dependencies": { - "micromark": "4.0.2", - "micromark-core-commonmark": "2.0.3", - "micromark-extension-directive": "4.0.0", - "micromark-extension-gfm-autolink-literal": "2.1.0", - "micromark-extension-gfm-footnote": "2.1.0", - "micromark-extension-gfm-table": "2.1.1", - "micromark-extension-math": "3.1.0", - "micromark-util-types": "2.0.2", - "string-width": "8.1.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/DavidAnson" - } - }, - "node_modules/markdownlint-cli": { - "version": "0.48.0", - "resolved": "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.48.0.tgz", - "integrity": "sha512-NkZQNu2E0Q5qLEEHwWj674eYISTLD4jMHkBzDobujXd1kv+yCxi8jOaD/rZoQNW1FBBMMGQpuW5So8B51N/e0A==", - "dev": true, - "license": "MIT", - "dependencies": { - "commander": "~14.0.3", - "deep-extend": "~0.6.0", - "ignore": "~7.0.5", - "js-yaml": "~4.1.1", - "jsonc-parser": "~3.3.1", - "jsonpointer": "~5.0.1", - "markdown-it": "~14.1.1", - "markdownlint": "~0.40.0", - "minimatch": "~10.2.4", - "run-con": "~1.3.2", - "smol-toml": "~1.6.0", - "tinyglobby": "~0.2.15" - }, - "bin": { - "markdownlint": "markdownlint.js" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/markdownlint/node_modules/string-width": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.1.0.tgz", - "integrity": "sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-east-asian-width": "^1.3.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mdurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", - "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", - "dev": true, - "license": "MIT" - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromark": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", - "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "@types/debug": "^4.0.0", - "debug": "^4.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-core-commonmark": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-combine-extensions": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-core-commonmark": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", - "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-factory-destination": "^2.0.0", - "micromark-factory-label": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-factory-title": "^2.0.0", - "micromark-factory-whitespace": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-html-tag-name": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-extension-directive": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-directive/-/micromark-extension-directive-4.0.0.tgz", - "integrity": "sha512-/C2nqVmXXmiseSSuCdItCMho7ybwwop6RrrRPk0KbOHW21JKoCldC+8rFOaundDoRBUWBnJJcxeA/Kvi34WQXg==", - "dev": true, - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-factory-whitespace": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0", - "parse-entities": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-autolink-literal": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", - "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", - "dev": true, - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-footnote": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", - "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", - "dev": true, - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-core-commonmark": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-table": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", - "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", - "dev": true, - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=20" } }, - "node_modules/micromark-extension-math": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-math/-/micromark-extension-math-3.1.0.tgz", - "integrity": "sha512-lvEqd+fHjATVs+2v/8kg9i5Q0AP2k85H0WUOwpIVvUML8BapsMvh1XAogmQjOCsLpoKRCVQqEkQBB3NhVBcsOg==", - "dev": true, + "node_modules/emoji-regex": { + "version": "10.6.0", + "license": "MIT" + }, + "node_modules/env-paths": { + "version": "4.0.0", "license": "MIT", "dependencies": { - "@types/katex": "^0.16.0", - "devlop": "^1.0.0", - "katex": "^0.16.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" + "is-safe-filename": "^0.1.0" + }, + "engines": { + "node": ">=20" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-factory-destination": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", - "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-label": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", - "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-space": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", - "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-title": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", - "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-whitespace": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", - "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-character": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", - "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-chunked": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", - "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-classify-character": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", - "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-combine-extensions": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", - "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-chunked": "^2.0.0", - "micromark-util-types": "^2.0.0" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/micromark-util-decode-numeric-character-reference": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", - "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/escalade": { + "version": "3.2.0", "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0" + "engines": { + "node": ">=6" } }, - "node_modules/micromark-util-encode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", - "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/fast-deep-equal": { + "version": "3.1.3", "license": "MIT" }, - "node_modules/micromark-util-html-tag-name": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", - "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/fast-string-truncated-width": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz", + "integrity": "sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==", "license": "MIT" }, - "node_modules/micromark-util-normalize-identifier": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", - "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-resolve-all": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", - "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-sanitize-uri": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", - "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-subtokenize": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", - "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/fast-string-width": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fast-string-width/-/fast-string-width-3.0.2.tgz", + "integrity": "sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==", "license": "MIT", "dependencies": { - "devlop": "^1.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" + "fast-string-truncated-width": "^3.0.2" } }, - "node_modules/micromark-util-symbol": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", - "dev": true, - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "license": "MIT" - }, - "node_modules/micromark-util-types": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", - "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", - "dev": true, + "node_modules/fast-uri": { + "version": "3.1.2", "funding": [ { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" + "type": "github", + "url": "https://github.com/sponsors/fastify" }, { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" + "type": "opencollective", + "url": "https://opencollective.com/fastify" } ], - "license": "MIT" + "license": "BSD-3-Clause" }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "node_modules/fast-wrap-ansi": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.2.2.tgz", + "integrity": "sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==", "license": "MIT", "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" + "fast-string-width": "^3.0.2" } }, - "node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.5" - }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "license": "ISC", "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": "6.* || 8.* || >= 10.*" } }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, + "node_modules/get-east-asian-width": { + "version": "1.5.0", "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/minipass": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", - "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", - "license": "BlueOak-1.0.0", "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/minizlib": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", - "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", - "license": "MIT", - "dependencies": { - "minipass": "^7.1.2" + "node": ">=18" }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/mustache": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", - "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", - "license": "MIT", - "bin": { - "mustache": "bin/mustache" - } - }, - "node_modules/mute-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-3.0.0.tgz", - "integrity": "sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==", - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, - "license": "MIT" - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, + "node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", "license": "MIT", "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, + "node_modules/is-safe-filename": { + "version": "0.1.1", "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, "engines": { - "node": ">=10" + "node": ">=20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, + "node_modules/is-unicode-supported": { + "version": "2.1.0", "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, + "node_modules/js-tokens": { + "version": "4.0.0", + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "license": "MIT" + }, + "node_modules/minipass": { + "version": "7.1.3", + "license": "BlueOak-1.0.0", "engines": { - "node": ">=6" + "node": ">=16 || 14 >=14.17" } }, - "node_modules/parse-entities": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", - "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", - "dev": true, + "node_modules/minizlib": { + "version": "3.1.0", "license": "MIT", "dependencies": { - "@types/unist": "^2.0.0", - "character-entities-legacy": "^3.0.0", - "character-reference-invalid": "^2.0.0", - "decode-named-character-reference": "^1.0.0", - "is-alphanumerical": "^2.0.0", - "is-decimal": "^2.0.0", - "is-hexadecimal": "^2.0.0" + "minipass": "^7.1.2" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "engines": { + "node": ">= 18" } }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, + "node_modules/mustache": { + "version": "4.2.0", "license": "MIT", - "engines": { - "node": ">=8" + "bin": { + "mustache": "bin/mustache" } }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "license": "MIT", + "node_modules/mute-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-3.0.0.tgz", + "integrity": "sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==", + "license": "ISC", "engines": { - "node": ">=8" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/picocolors": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "license": "ISC" }, - "node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/prettier": { "version": "3.8.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", - "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", "license": "MIT", "bin": { "prettier": "bin/prettier.cjs" @@ -3167,118 +691,13 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/prompty-emitter": { - "resolved": "emitter", - "link": true - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/punycode.js": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", - "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "node_modules/require-from-string": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", "license": "MIT", "engines": { - "iojs": ">=1.0.0", "node": ">=0.10.0" } }, - "node_modules/run-con": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/run-con/-/run-con-1.3.2.tgz", - "integrity": "sha512-CcfE+mYiTcKEzg0IqS08+efdnH0oJ3zV0wSUFBNrMHMuxCtXvBCLzCJHatwuXDcu/RlhjTziTo/a1ruQik6/Yg==", - "dev": true, - "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~4.1.0", - "minimist": "^1.2.8", - "strip-json-comments": "~3.1.1" - }, - "bin": { - "run-con": "cli.js" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -3287,8 +706,6 @@ }, "node_modules/semver": { "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -3297,29 +714,6 @@ "node": ">=10" } }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/signal-exit": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", @@ -3332,35 +726,8 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/slash": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", - "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", - "license": "MIT", - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/smol-toml": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.6.1.tgz", - "integrity": "sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">= 18" - }, - "funding": { - "url": "https://github.com/sponsors/cyyynthia" - } - }, "node_modules/string-width": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "license": "MIT", "dependencies": { "emoji-regex": "^10.3.0", @@ -3376,8 +743,6 @@ }, "node_modules/strip-ansi": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", "license": "MIT", "dependencies": { "ansi-regex": "^6.2.2" @@ -3389,36 +754,8 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/tar": { "version": "7.5.13", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.13.tgz", - "integrity": "sha512-tOG/7GyXpFevhXVh8jOPJrmtRpOTsYqUIkVdVooZYJS/z8WhfQUX8RJILmeuJNinGAMSu1veBr4asSHFt5/hng==", "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/fs-minipass": "^4.0.0", @@ -3433,8 +770,6 @@ }, "node_modules/temporal-polyfill": { "version": "0.3.2", - "resolved": "https://registry.npmjs.org/temporal-polyfill/-/temporal-polyfill-0.3.2.tgz", - "integrity": "sha512-TzHthD/heRK947GNiSu3Y5gSPpeUDH34+LESnfsq8bqpFhsB79HFBX8+Z834IVX68P3EUyRPZK5bL/1fh437Eg==", "license": "MIT", "dependencies": { "temporal-spec": "0.3.1" @@ -3442,176 +777,10 @@ }, "node_modules/temporal-spec": { "version": "0.3.1", - "resolved": "https://registry.npmjs.org/temporal-spec/-/temporal-spec-0.3.1.tgz", - "integrity": "sha512-B4TUhezh9knfSIMwt7RVggApDRJZo73uZdj8AacL2mZ8RP5KtLianh2MXxL06GN9ESYiIsiuoLQhgVfwe55Yhw==", "license": "ISC" }, - "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.3" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/ts-api-utils": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", - "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.12" - }, - "peerDependencies": { - "typescript": ">=4.8.4" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/typescript-eslint": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.57.2.tgz", - "integrity": "sha512-VEPQ0iPgWO/sBaZOU1xo4nuNdODVOajPnTIbog2GKYr31nIlZ0fWPoCQgGfF3ETyBl1vn63F/p50Um9Z4J8O8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/eslint-plugin": "8.57.2", - "@typescript-eslint/parser": "8.57.2", - "@typescript-eslint/typescript-estree": "8.57.2", - "@typescript-eslint/utils": "8.57.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/uc.micro": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", - "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", - "dev": true, - "license": "MIT" - }, - "node_modules/undici-types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", - "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/unicorn-magic": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.4.0.tgz", - "integrity": "sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==", - "license": "MIT", - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, "node_modules/vscode-jsonrpc": { "version": "8.2.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", - "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", "license": "MIT", "engines": { "node": ">=14.0.0" @@ -3619,8 +788,6 @@ }, "node_modules/vscode-languageserver": { "version": "9.0.1", - "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz", - "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==", "license": "MIT", "dependencies": { "vscode-languageserver-protocol": "3.17.5" @@ -3631,8 +798,6 @@ }, "node_modules/vscode-languageserver-protocol": { "version": "3.17.5", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", - "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", "license": "MIT", "dependencies": { "vscode-jsonrpc": "8.2.0", @@ -3641,46 +806,14 @@ }, "node_modules/vscode-languageserver-textdocument": { "version": "1.0.12", - "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", - "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", "license": "MIT" }, "node_modules/vscode-languageserver-types": { "version": "3.17.5", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", - "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", "license": "MIT" }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/wrap-ansi": { "version": "9.0.2", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", - "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", "license": "MIT", "dependencies": { "ansi-styles": "^6.2.1", @@ -3696,8 +829,6 @@ }, "node_modules/xml-formatter": { "version": "3.7.0", - "resolved": "https://registry.npmjs.org/xml-formatter/-/xml-formatter-3.7.0.tgz", - "integrity": "sha512-+8qTc3zv2UcJ1v9IsSIce37Dl4MQG14Cp7tWrwmy202UaI1wqRukw5QMX1JHsV+DX64yw77EgGsj2s5wGvuMbQ==", "license": "MIT", "dependencies": { "xml-parser-xo": "^4.1.5" @@ -3708,8 +839,6 @@ }, "node_modules/xml-parser-xo": { "version": "4.1.5", - "resolved": "https://registry.npmjs.org/xml-parser-xo/-/xml-parser-xo-4.1.5.tgz", - "integrity": "sha512-TxyRxk9sTOUg3glxSIY6f0nfuqRll2OEF8TspLgh5mZkLuBgheCn3zClcDSGJ58TvNmiwyCCuat4UajPud/5Og==", "license": "MIT", "engines": { "node": ">= 16" @@ -3717,8 +846,6 @@ }, "node_modules/y18n": { "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "license": "ISC", "engines": { "node": ">=10" @@ -3726,8 +853,6 @@ }, "node_modules/yallist": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", - "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", "license": "BlueOak-1.0.0", "engines": { "node": ">=18" @@ -3735,8 +860,6 @@ }, "node_modules/yaml": { "version": "2.8.3", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", - "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", "license": "ISC", "bin": { "yaml": "bin.mjs" @@ -3750,8 +873,6 @@ }, "node_modules/yargs": { "version": "18.0.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", - "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", "license": "MIT", "dependencies": { "cliui": "^9.0.1", @@ -3767,25 +888,10 @@ }, "node_modules/yargs-parser": { "version": "22.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", - "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", "license": "ISC", "engines": { "node": "^20.19.0 || ^22.12.0 || >=23" } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } } } } diff --git a/schema/package.json b/schema/package.json index dbc49096..e1695e34 100644 --- a/schema/package.json +++ b/schema/package.json @@ -3,15 +3,14 @@ "name": "prompty-schema", "description": "TypeSpec models and code generation for Prompty", "scripts": { - "build:emitter": "cd emitter && npm run build", "format:tsp": "npx tsp format \"model/**/*.tsp\"", "format:tsp:check": "npx tsp format \"model/**/*.tsp\" --check", "format:rust": "cargo fmt --all --manifest-path ../runtime/rust/prompty/Cargo.toml", "generate": "npx tsp compile model/main.tsp --config tspconfig.yaml", - "build": "npm run build:emitter && npm run format:tsp && npm run generate && npm run format:rust" + "build": "npm run format:tsp && npm run generate && npm run format:rust" }, "dependencies": { - "prompty-emitter": "file:./emitter", + "@typra/emitter": "0.2.4", "@typespec/compiler": "latest", "@typespec/json-schema": "latest" } diff --git a/schema/tspconfig.yaml b/schema/tspconfig.yaml index 680a1db2..a4be8b63 100644 --- a/schema/tspconfig.yaml +++ b/schema/tspconfig.yaml @@ -1,13 +1,13 @@ emit: - "@typespec/json-schema" - - "prompty-emitter" + - "@typra/emitter" options: "@typespec/json-schema": emitter-output-dir: "{cwd}/../vscode/prompty/schemas" emitAllModels: true emitAllRefs: true file-type: yaml - "prompty-emitter": + "@typra/emitter": emitter-output-dir: "{cwd}/tsp-output" root-object: "Prompty.Prompty" emit-targets: @@ -27,6 +27,7 @@ options: output-dir: "../runtime/go/prompty/model" test-dir: "../runtime/go/prompty/model" import-path: "prompty/model" + package-name: "prompty" - type: Rust output-dir: "../runtime/rust/prompty/src/model" test-dir: "../runtime/rust/prompty/tests/model" diff --git a/web/src/content/docs/reference/AnonymousConnection.md b/web/src/content/docs/reference/AnonymousConnection.md index db5b6e61..6b6c3c3c 100644 --- a/web/src/content/docs/reference/AnonymousConnection.md +++ b/web/src/content/docs/reference/AnonymousConnection.md @@ -1,3 +1,4 @@ + --- title: "AnonymousConnection" description: "Documentation for the AnonymousConnection type." diff --git a/web/src/content/docs/reference/AnthropicImageBlock.md b/web/src/content/docs/reference/AnthropicImageBlock.md index 91eec89f..a0b7e376 100644 --- a/web/src/content/docs/reference/AnthropicImageBlock.md +++ b/web/src/content/docs/reference/AnthropicImageBlock.md @@ -1,3 +1,4 @@ + --- title: "AnthropicImageBlock" description: "Documentation for the AnthropicImageBlock type." diff --git a/web/src/content/docs/reference/AnthropicImageSource.md b/web/src/content/docs/reference/AnthropicImageSource.md index 9da5252c..fcdcbb3e 100644 --- a/web/src/content/docs/reference/AnthropicImageSource.md +++ b/web/src/content/docs/reference/AnthropicImageSource.md @@ -1,3 +1,4 @@ + --- title: "AnthropicImageSource" description: "Documentation for the AnthropicImageSource type." diff --git a/web/src/content/docs/reference/AnthropicMessagesRequest.md b/web/src/content/docs/reference/AnthropicMessagesRequest.md index 456f83f2..c6f8a9b5 100644 --- a/web/src/content/docs/reference/AnthropicMessagesRequest.md +++ b/web/src/content/docs/reference/AnthropicMessagesRequest.md @@ -1,3 +1,4 @@ + --- title: "AnthropicMessagesRequest" description: "Documentation for the AnthropicMessagesRequest type." diff --git a/web/src/content/docs/reference/AnthropicMessagesResponse.md b/web/src/content/docs/reference/AnthropicMessagesResponse.md index c5e633d0..c3c77a24 100644 --- a/web/src/content/docs/reference/AnthropicMessagesResponse.md +++ b/web/src/content/docs/reference/AnthropicMessagesResponse.md @@ -1,3 +1,4 @@ + --- title: "AnthropicMessagesResponse" description: "Documentation for the AnthropicMessagesResponse type." diff --git a/web/src/content/docs/reference/AnthropicTextBlock.md b/web/src/content/docs/reference/AnthropicTextBlock.md index bef64872..11d0c93f 100644 --- a/web/src/content/docs/reference/AnthropicTextBlock.md +++ b/web/src/content/docs/reference/AnthropicTextBlock.md @@ -1,3 +1,4 @@ + --- title: "AnthropicTextBlock" description: "Documentation for the AnthropicTextBlock type." diff --git a/web/src/content/docs/reference/AnthropicToolDefinition.md b/web/src/content/docs/reference/AnthropicToolDefinition.md index bd7afa46..841bfaf8 100644 --- a/web/src/content/docs/reference/AnthropicToolDefinition.md +++ b/web/src/content/docs/reference/AnthropicToolDefinition.md @@ -1,3 +1,4 @@ + --- title: "AnthropicToolDefinition" description: "Documentation for the AnthropicToolDefinition type." diff --git a/web/src/content/docs/reference/AnthropicToolResultBlock.md b/web/src/content/docs/reference/AnthropicToolResultBlock.md index 775f14c5..5d189fa4 100644 --- a/web/src/content/docs/reference/AnthropicToolResultBlock.md +++ b/web/src/content/docs/reference/AnthropicToolResultBlock.md @@ -1,3 +1,4 @@ + --- title: "AnthropicToolResultBlock" description: "Documentation for the AnthropicToolResultBlock type." diff --git a/web/src/content/docs/reference/AnthropicToolUseBlock.md b/web/src/content/docs/reference/AnthropicToolUseBlock.md index 9643ef4d..a7537983 100644 --- a/web/src/content/docs/reference/AnthropicToolUseBlock.md +++ b/web/src/content/docs/reference/AnthropicToolUseBlock.md @@ -1,3 +1,4 @@ + --- title: "AnthropicToolUseBlock" description: "Documentation for the AnthropicToolUseBlock type." diff --git a/web/src/content/docs/reference/AnthropicUsage.md b/web/src/content/docs/reference/AnthropicUsage.md index c1ae0344..b9c9ab8a 100644 --- a/web/src/content/docs/reference/AnthropicUsage.md +++ b/web/src/content/docs/reference/AnthropicUsage.md @@ -1,3 +1,4 @@ + --- title: "AnthropicUsage" description: "Documentation for the AnthropicUsage type." diff --git a/web/src/content/docs/reference/AnthropicWireMessage.md b/web/src/content/docs/reference/AnthropicWireMessage.md index fff3ce9f..00eb038f 100644 --- a/web/src/content/docs/reference/AnthropicWireMessage.md +++ b/web/src/content/docs/reference/AnthropicWireMessage.md @@ -1,3 +1,4 @@ + --- title: "AnthropicWireMessage" description: "Documentation for the AnthropicWireMessage type." diff --git a/web/src/content/docs/reference/ApiKeyConnection.md b/web/src/content/docs/reference/ApiKeyConnection.md index ca47cc89..ce20ed1b 100644 --- a/web/src/content/docs/reference/ApiKeyConnection.md +++ b/web/src/content/docs/reference/ApiKeyConnection.md @@ -1,3 +1,4 @@ + --- title: "ApiKeyConnection" description: "Documentation for the ApiKeyConnection type." diff --git a/web/src/content/docs/reference/ArrayProperty.md b/web/src/content/docs/reference/ArrayProperty.md index 600f9bed..c1b66200 100644 --- a/web/src/content/docs/reference/ArrayProperty.md +++ b/web/src/content/docs/reference/ArrayProperty.md @@ -1,3 +1,4 @@ + --- title: "ArrayProperty" description: "Documentation for the ArrayProperty type." diff --git a/web/src/content/docs/reference/AudioPart.md b/web/src/content/docs/reference/AudioPart.md index 705ec80a..8c79f85a 100644 --- a/web/src/content/docs/reference/AudioPart.md +++ b/web/src/content/docs/reference/AudioPart.md @@ -1,3 +1,4 @@ + --- title: "AudioPart" description: "Documentation for the AudioPart type." diff --git a/web/src/content/docs/reference/Binding.md b/web/src/content/docs/reference/Binding.md index b952fc98..1a84300e 100644 --- a/web/src/content/docs/reference/Binding.md +++ b/web/src/content/docs/reference/Binding.md @@ -1,3 +1,4 @@ + --- title: "Binding" description: "Documentation for the Binding type." diff --git a/web/src/content/docs/reference/Checkpoint.md b/web/src/content/docs/reference/Checkpoint.md index e0fbb7e3..69497ce8 100644 --- a/web/src/content/docs/reference/Checkpoint.md +++ b/web/src/content/docs/reference/Checkpoint.md @@ -1,3 +1,4 @@ + --- title: "Checkpoint" description: "Documentation for the Checkpoint type." diff --git a/web/src/content/docs/reference/CheckpointStore.md b/web/src/content/docs/reference/CheckpointStore.md index a181e6a5..a18c4ed3 100644 --- a/web/src/content/docs/reference/CheckpointStore.md +++ b/web/src/content/docs/reference/CheckpointStore.md @@ -1,3 +1,4 @@ + --- title: "CheckpointStore" description: "Documentation for the CheckpointStore type." diff --git a/web/src/content/docs/reference/CompactionCompletePayload.md b/web/src/content/docs/reference/CompactionCompletePayload.md index 630fc012..cd00dc60 100644 --- a/web/src/content/docs/reference/CompactionCompletePayload.md +++ b/web/src/content/docs/reference/CompactionCompletePayload.md @@ -1,3 +1,4 @@ + --- title: "CompactionCompletePayload" description: "Documentation for the CompactionCompletePayload type." diff --git a/web/src/content/docs/reference/CompactionConfig.md b/web/src/content/docs/reference/CompactionConfig.md index 831f4bf0..85ed7d98 100644 --- a/web/src/content/docs/reference/CompactionConfig.md +++ b/web/src/content/docs/reference/CompactionConfig.md @@ -1,3 +1,4 @@ + --- title: "CompactionConfig" description: "Documentation for the CompactionConfig type." diff --git a/web/src/content/docs/reference/CompactionFailedPayload.md b/web/src/content/docs/reference/CompactionFailedPayload.md index ed8739a0..92f483c2 100644 --- a/web/src/content/docs/reference/CompactionFailedPayload.md +++ b/web/src/content/docs/reference/CompactionFailedPayload.md @@ -1,3 +1,4 @@ + --- title: "CompactionFailedPayload" description: "Documentation for the CompactionFailedPayload type." diff --git a/web/src/content/docs/reference/CompactionStartPayload.md b/web/src/content/docs/reference/CompactionStartPayload.md index 3d49c1d8..676e634a 100644 --- a/web/src/content/docs/reference/CompactionStartPayload.md +++ b/web/src/content/docs/reference/CompactionStartPayload.md @@ -1,3 +1,4 @@ + --- title: "CompactionStartPayload" description: "Documentation for the CompactionStartPayload type." diff --git a/web/src/content/docs/reference/Connection.md b/web/src/content/docs/reference/Connection.md index ad4d4ff8..06498096 100644 --- a/web/src/content/docs/reference/Connection.md +++ b/web/src/content/docs/reference/Connection.md @@ -1,3 +1,4 @@ + --- title: "Connection" description: "Documentation for the Connection type." diff --git a/web/src/content/docs/reference/ContentPart.md b/web/src/content/docs/reference/ContentPart.md index 8a5db699..1fd883a6 100644 --- a/web/src/content/docs/reference/ContentPart.md +++ b/web/src/content/docs/reference/ContentPart.md @@ -1,3 +1,4 @@ + --- title: "ContentPart" description: "Documentation for the ContentPart type." diff --git a/web/src/content/docs/reference/CustomTool.md b/web/src/content/docs/reference/CustomTool.md index 60a439d4..a89e98d4 100644 --- a/web/src/content/docs/reference/CustomTool.md +++ b/web/src/content/docs/reference/CustomTool.md @@ -1,3 +1,4 @@ + --- title: "CustomTool" description: "Documentation for the CustomTool type." diff --git a/web/src/content/docs/reference/DoneEventPayload.md b/web/src/content/docs/reference/DoneEventPayload.md index 5a426ec5..7c1c3d81 100644 --- a/web/src/content/docs/reference/DoneEventPayload.md +++ b/web/src/content/docs/reference/DoneEventPayload.md @@ -1,3 +1,4 @@ + --- title: "DoneEventPayload" description: "Documentation for the DoneEventPayload type." diff --git a/web/src/content/docs/reference/ErrorChunk.md b/web/src/content/docs/reference/ErrorChunk.md index 00021122..4949165d 100644 --- a/web/src/content/docs/reference/ErrorChunk.md +++ b/web/src/content/docs/reference/ErrorChunk.md @@ -1,3 +1,4 @@ + --- title: "ErrorChunk" description: "Documentation for the ErrorChunk type." diff --git a/web/src/content/docs/reference/ErrorEventPayload.md b/web/src/content/docs/reference/ErrorEventPayload.md index 8784a307..3b4c82cc 100644 --- a/web/src/content/docs/reference/ErrorEventPayload.md +++ b/web/src/content/docs/reference/ErrorEventPayload.md @@ -1,3 +1,4 @@ + --- title: "ErrorEventPayload" description: "Documentation for the ErrorEventPayload type." diff --git a/web/src/content/docs/reference/EventJournalWriter.md b/web/src/content/docs/reference/EventJournalWriter.md index c61d55ba..9d8b8dd6 100644 --- a/web/src/content/docs/reference/EventJournalWriter.md +++ b/web/src/content/docs/reference/EventJournalWriter.md @@ -1,3 +1,4 @@ + --- title: "EventJournalWriter" description: "Documentation for the EventJournalWriter type." diff --git a/web/src/content/docs/reference/EventSink.md b/web/src/content/docs/reference/EventSink.md index 21aa8994..ac19dd34 100644 --- a/web/src/content/docs/reference/EventSink.md +++ b/web/src/content/docs/reference/EventSink.md @@ -1,3 +1,4 @@ + --- title: "EventSink" description: "Documentation for the EventSink type." diff --git a/web/src/content/docs/reference/Executor.md b/web/src/content/docs/reference/Executor.md index a64a8356..5b9d5868 100644 --- a/web/src/content/docs/reference/Executor.md +++ b/web/src/content/docs/reference/Executor.md @@ -1,3 +1,4 @@ + --- title: "Executor" description: "Documentation for the Executor type." diff --git a/web/src/content/docs/reference/FileNotFoundError.md b/web/src/content/docs/reference/FileNotFoundError.md index f4603cc1..09d0acf9 100644 --- a/web/src/content/docs/reference/FileNotFoundError.md +++ b/web/src/content/docs/reference/FileNotFoundError.md @@ -1,3 +1,4 @@ + --- title: "FileNotFoundError" description: "Documentation for the FileNotFoundError type." diff --git a/web/src/content/docs/reference/FilePart.md b/web/src/content/docs/reference/FilePart.md index 0f46587d..c722b03c 100644 --- a/web/src/content/docs/reference/FilePart.md +++ b/web/src/content/docs/reference/FilePart.md @@ -1,3 +1,4 @@ + --- title: "FilePart" description: "Documentation for the FilePart type." diff --git a/web/src/content/docs/reference/FormatConfig.md b/web/src/content/docs/reference/FormatConfig.md index d0b34938..eb8ef78d 100644 --- a/web/src/content/docs/reference/FormatConfig.md +++ b/web/src/content/docs/reference/FormatConfig.md @@ -1,3 +1,4 @@ + --- title: "FormatConfig" description: "Documentation for the FormatConfig type." diff --git a/web/src/content/docs/reference/FoundryConnection.md b/web/src/content/docs/reference/FoundryConnection.md index 470150c5..aa8c4702 100644 --- a/web/src/content/docs/reference/FoundryConnection.md +++ b/web/src/content/docs/reference/FoundryConnection.md @@ -1,3 +1,4 @@ + --- title: "FoundryConnection" description: "Documentation for the FoundryConnection type." diff --git a/web/src/content/docs/reference/FunctionTool.md b/web/src/content/docs/reference/FunctionTool.md index da992151..14e4c1a4 100644 --- a/web/src/content/docs/reference/FunctionTool.md +++ b/web/src/content/docs/reference/FunctionTool.md @@ -1,3 +1,4 @@ + --- title: "FunctionTool" description: "Documentation for the FunctionTool type." diff --git a/web/src/content/docs/reference/GuardrailResult.md b/web/src/content/docs/reference/GuardrailResult.md index b61a62d8..46c2f69f 100644 --- a/web/src/content/docs/reference/GuardrailResult.md +++ b/web/src/content/docs/reference/GuardrailResult.md @@ -1,3 +1,4 @@ + --- title: "GuardrailResult" description: "Documentation for the GuardrailResult type." diff --git a/web/src/content/docs/reference/HarnessContext.md b/web/src/content/docs/reference/HarnessContext.md index 707a1dea..16a18d45 100644 --- a/web/src/content/docs/reference/HarnessContext.md +++ b/web/src/content/docs/reference/HarnessContext.md @@ -1,3 +1,4 @@ + --- title: "HarnessContext" description: "Documentation for the HarnessContext type." diff --git a/web/src/content/docs/reference/HookEndPayload.md b/web/src/content/docs/reference/HookEndPayload.md index 3620a9cc..2975490c 100644 --- a/web/src/content/docs/reference/HookEndPayload.md +++ b/web/src/content/docs/reference/HookEndPayload.md @@ -1,3 +1,4 @@ + --- title: "HookEndPayload" description: "Documentation for the HookEndPayload type." diff --git a/web/src/content/docs/reference/HookStartPayload.md b/web/src/content/docs/reference/HookStartPayload.md index f29b4a4d..e7e30291 100644 --- a/web/src/content/docs/reference/HookStartPayload.md +++ b/web/src/content/docs/reference/HookStartPayload.md @@ -1,3 +1,4 @@ + --- title: "HookStartPayload" description: "Documentation for the HookStartPayload type." diff --git a/web/src/content/docs/reference/HostToolExecutor.md b/web/src/content/docs/reference/HostToolExecutor.md index 08661ed8..f7606192 100644 --- a/web/src/content/docs/reference/HostToolExecutor.md +++ b/web/src/content/docs/reference/HostToolExecutor.md @@ -1,3 +1,4 @@ + --- title: "HostToolExecutor" description: "Documentation for the HostToolExecutor type." diff --git a/web/src/content/docs/reference/HostToolRequest.md b/web/src/content/docs/reference/HostToolRequest.md index f12784ec..ef5007c6 100644 --- a/web/src/content/docs/reference/HostToolRequest.md +++ b/web/src/content/docs/reference/HostToolRequest.md @@ -1,3 +1,4 @@ + --- title: "HostToolRequest" description: "Documentation for the HostToolRequest type." diff --git a/web/src/content/docs/reference/HostToolResult.md b/web/src/content/docs/reference/HostToolResult.md index 7cdf5e01..2cb52a15 100644 --- a/web/src/content/docs/reference/HostToolResult.md +++ b/web/src/content/docs/reference/HostToolResult.md @@ -1,3 +1,4 @@ + --- title: "HostToolResult" description: "Documentation for the HostToolResult type." diff --git a/web/src/content/docs/reference/ImagePart.md b/web/src/content/docs/reference/ImagePart.md index 5e2a8bbd..1b95a276 100644 --- a/web/src/content/docs/reference/ImagePart.md +++ b/web/src/content/docs/reference/ImagePart.md @@ -1,3 +1,4 @@ + --- title: "ImagePart" description: "Documentation for the ImagePart type." diff --git a/web/src/content/docs/reference/InvokerError.md b/web/src/content/docs/reference/InvokerError.md index f9ace241..83d49abf 100644 --- a/web/src/content/docs/reference/InvokerError.md +++ b/web/src/content/docs/reference/InvokerError.md @@ -1,3 +1,4 @@ + --- title: "InvokerError" description: "Documentation for the InvokerError type." diff --git a/web/src/content/docs/reference/LlmCompletePayload.md b/web/src/content/docs/reference/LlmCompletePayload.md index c64d0c9a..bbbbb48f 100644 --- a/web/src/content/docs/reference/LlmCompletePayload.md +++ b/web/src/content/docs/reference/LlmCompletePayload.md @@ -1,3 +1,4 @@ + --- title: "LlmCompletePayload" description: "Documentation for the LlmCompletePayload type." diff --git a/web/src/content/docs/reference/LlmStartPayload.md b/web/src/content/docs/reference/LlmStartPayload.md index c30ab423..2f7b23d4 100644 --- a/web/src/content/docs/reference/LlmStartPayload.md +++ b/web/src/content/docs/reference/LlmStartPayload.md @@ -1,3 +1,4 @@ + --- title: "LlmStartPayload" description: "Documentation for the LlmStartPayload type." diff --git a/web/src/content/docs/reference/McpApprovalMode.md b/web/src/content/docs/reference/McpApprovalMode.md index aa10b0ff..3fcc0d74 100644 --- a/web/src/content/docs/reference/McpApprovalMode.md +++ b/web/src/content/docs/reference/McpApprovalMode.md @@ -1,3 +1,4 @@ + --- title: "McpApprovalMode" description: "Documentation for the McpApprovalMode type." diff --git a/web/src/content/docs/reference/McpTool.md b/web/src/content/docs/reference/McpTool.md index 0169face..52d1a260 100644 --- a/web/src/content/docs/reference/McpTool.md +++ b/web/src/content/docs/reference/McpTool.md @@ -1,3 +1,4 @@ + --- title: "McpTool" description: "Documentation for the McpTool type." diff --git a/web/src/content/docs/reference/Message.md b/web/src/content/docs/reference/Message.md index 5de923c7..70f0f697 100644 --- a/web/src/content/docs/reference/Message.md +++ b/web/src/content/docs/reference/Message.md @@ -1,3 +1,4 @@ + --- title: "Message" description: "Documentation for the Message type." diff --git a/web/src/content/docs/reference/MessagesUpdatedPayload.md b/web/src/content/docs/reference/MessagesUpdatedPayload.md index 00d6c458..dbeb9052 100644 --- a/web/src/content/docs/reference/MessagesUpdatedPayload.md +++ b/web/src/content/docs/reference/MessagesUpdatedPayload.md @@ -1,3 +1,4 @@ + --- title: "MessagesUpdatedPayload" description: "Documentation for the MessagesUpdatedPayload type." diff --git a/web/src/content/docs/reference/Model.md b/web/src/content/docs/reference/Model.md index 211dfa6a..51d477d6 100644 --- a/web/src/content/docs/reference/Model.md +++ b/web/src/content/docs/reference/Model.md @@ -1,3 +1,4 @@ + --- title: "Model" description: "Documentation for the Model type." diff --git a/web/src/content/docs/reference/ModelInfo.md b/web/src/content/docs/reference/ModelInfo.md index e64c89c9..8611a4d3 100644 --- a/web/src/content/docs/reference/ModelInfo.md +++ b/web/src/content/docs/reference/ModelInfo.md @@ -1,3 +1,4 @@ + --- title: "ModelInfo" description: "Documentation for the ModelInfo type." diff --git a/web/src/content/docs/reference/ModelOptions.md b/web/src/content/docs/reference/ModelOptions.md index 594f99ef..c42c9cc7 100644 --- a/web/src/content/docs/reference/ModelOptions.md +++ b/web/src/content/docs/reference/ModelOptions.md @@ -1,3 +1,4 @@ + --- title: "ModelOptions" description: "Documentation for the ModelOptions type." diff --git a/web/src/content/docs/reference/OAuthConnection.md b/web/src/content/docs/reference/OAuthConnection.md index e81575d7..8c9171fb 100644 --- a/web/src/content/docs/reference/OAuthConnection.md +++ b/web/src/content/docs/reference/OAuthConnection.md @@ -1,3 +1,4 @@ + --- title: "OAuthConnection" description: "Documentation for the OAuthConnection type." diff --git a/web/src/content/docs/reference/ObjectProperty.md b/web/src/content/docs/reference/ObjectProperty.md index 6aeb43bb..4cd97411 100644 --- a/web/src/content/docs/reference/ObjectProperty.md +++ b/web/src/content/docs/reference/ObjectProperty.md @@ -1,3 +1,4 @@ + --- title: "ObjectProperty" description: "Documentation for the ObjectProperty type." diff --git a/web/src/content/docs/reference/OpenApiTool.md b/web/src/content/docs/reference/OpenApiTool.md index c6aa09ef..8f953b85 100644 --- a/web/src/content/docs/reference/OpenApiTool.md +++ b/web/src/content/docs/reference/OpenApiTool.md @@ -1,3 +1,4 @@ + --- title: "OpenApiTool" description: "Documentation for the OpenApiTool type." diff --git a/web/src/content/docs/reference/Parser.md b/web/src/content/docs/reference/Parser.md index 3faede3e..a440c3c9 100644 --- a/web/src/content/docs/reference/Parser.md +++ b/web/src/content/docs/reference/Parser.md @@ -1,3 +1,4 @@ + --- title: "Parser" description: "Documentation for the Parser type." diff --git a/web/src/content/docs/reference/ParserConfig.md b/web/src/content/docs/reference/ParserConfig.md index 5e214a18..436ede9d 100644 --- a/web/src/content/docs/reference/ParserConfig.md +++ b/web/src/content/docs/reference/ParserConfig.md @@ -1,3 +1,4 @@ + --- title: "ParserConfig" description: "Documentation for the ParserConfig type." diff --git a/web/src/content/docs/reference/PermissionCompletedPayload.md b/web/src/content/docs/reference/PermissionCompletedPayload.md index 5af3768d..63a60f0f 100644 --- a/web/src/content/docs/reference/PermissionCompletedPayload.md +++ b/web/src/content/docs/reference/PermissionCompletedPayload.md @@ -1,3 +1,4 @@ + --- title: "PermissionCompletedPayload" description: "Documentation for the PermissionCompletedPayload type." diff --git a/web/src/content/docs/reference/PermissionDecision.md b/web/src/content/docs/reference/PermissionDecision.md index f5021629..b635527a 100644 --- a/web/src/content/docs/reference/PermissionDecision.md +++ b/web/src/content/docs/reference/PermissionDecision.md @@ -1,3 +1,4 @@ + --- title: "PermissionDecision" description: "Documentation for the PermissionDecision type." diff --git a/web/src/content/docs/reference/PermissionRequest.md b/web/src/content/docs/reference/PermissionRequest.md index d983f051..a6ebe282 100644 --- a/web/src/content/docs/reference/PermissionRequest.md +++ b/web/src/content/docs/reference/PermissionRequest.md @@ -1,3 +1,4 @@ + --- title: "PermissionRequest" description: "Documentation for the PermissionRequest type." diff --git a/web/src/content/docs/reference/PermissionRequestedPayload.md b/web/src/content/docs/reference/PermissionRequestedPayload.md index 9c1a5e7f..364438c8 100644 --- a/web/src/content/docs/reference/PermissionRequestedPayload.md +++ b/web/src/content/docs/reference/PermissionRequestedPayload.md @@ -1,3 +1,4 @@ + --- title: "PermissionRequestedPayload" description: "Documentation for the PermissionRequestedPayload type." diff --git a/web/src/content/docs/reference/PermissionResolver.md b/web/src/content/docs/reference/PermissionResolver.md index c4cebf48..ab1646f8 100644 --- a/web/src/content/docs/reference/PermissionResolver.md +++ b/web/src/content/docs/reference/PermissionResolver.md @@ -1,3 +1,4 @@ + --- title: "PermissionResolver" description: "Documentation for the PermissionResolver type." diff --git a/web/src/content/docs/reference/Processor.md b/web/src/content/docs/reference/Processor.md index cf081633..3382d208 100644 --- a/web/src/content/docs/reference/Processor.md +++ b/web/src/content/docs/reference/Processor.md @@ -1,3 +1,4 @@ + --- title: "Processor" description: "Documentation for the Processor type." diff --git a/web/src/content/docs/reference/Prompty.md b/web/src/content/docs/reference/Prompty.md index 409c9bd6..4c2659cb 100644 --- a/web/src/content/docs/reference/Prompty.md +++ b/web/src/content/docs/reference/Prompty.md @@ -1,3 +1,4 @@ + --- title: "Prompty" description: "Documentation for the Prompty type." diff --git a/web/src/content/docs/reference/PromptyTool.md b/web/src/content/docs/reference/PromptyTool.md index 7b3c9e5a..1544c15e 100644 --- a/web/src/content/docs/reference/PromptyTool.md +++ b/web/src/content/docs/reference/PromptyTool.md @@ -1,3 +1,4 @@ + --- title: "PromptyTool" description: "Documentation for the PromptyTool type." diff --git a/web/src/content/docs/reference/Property.md b/web/src/content/docs/reference/Property.md index aff5c8c8..0663f592 100644 --- a/web/src/content/docs/reference/Property.md +++ b/web/src/content/docs/reference/Property.md @@ -1,3 +1,4 @@ + --- title: "Property" description: "Documentation for the Property type." diff --git a/web/src/content/docs/reference/RedactedField.md b/web/src/content/docs/reference/RedactedField.md index 89e63470..90530bb7 100644 --- a/web/src/content/docs/reference/RedactedField.md +++ b/web/src/content/docs/reference/RedactedField.md @@ -1,3 +1,4 @@ + --- title: "RedactedField" description: "Documentation for the RedactedField type." diff --git a/web/src/content/docs/reference/RedactionMetadata.md b/web/src/content/docs/reference/RedactionMetadata.md index 18d0617a..2efefa9d 100644 --- a/web/src/content/docs/reference/RedactionMetadata.md +++ b/web/src/content/docs/reference/RedactionMetadata.md @@ -1,3 +1,4 @@ + --- title: "RedactionMetadata" description: "Documentation for the RedactionMetadata type." diff --git a/web/src/content/docs/reference/ReferenceConnection.md b/web/src/content/docs/reference/ReferenceConnection.md index aa36f8d3..c1a7f041 100644 --- a/web/src/content/docs/reference/ReferenceConnection.md +++ b/web/src/content/docs/reference/ReferenceConnection.md @@ -1,3 +1,4 @@ + --- title: "ReferenceConnection" description: "Documentation for the ReferenceConnection type." diff --git a/web/src/content/docs/reference/RemoteConnection.md b/web/src/content/docs/reference/RemoteConnection.md index 9937dd9c..d5afa790 100644 --- a/web/src/content/docs/reference/RemoteConnection.md +++ b/web/src/content/docs/reference/RemoteConnection.md @@ -1,3 +1,4 @@ + --- title: "RemoteConnection" description: "Documentation for the RemoteConnection type." diff --git a/web/src/content/docs/reference/Renderer.md b/web/src/content/docs/reference/Renderer.md index 25834210..3544c306 100644 --- a/web/src/content/docs/reference/Renderer.md +++ b/web/src/content/docs/reference/Renderer.md @@ -1,3 +1,4 @@ + --- title: "Renderer" description: "Documentation for the Renderer type." diff --git a/web/src/content/docs/reference/RetryPayload.md b/web/src/content/docs/reference/RetryPayload.md index 7ee2d488..ec842cda 100644 --- a/web/src/content/docs/reference/RetryPayload.md +++ b/web/src/content/docs/reference/RetryPayload.md @@ -1,3 +1,4 @@ + --- title: "RetryPayload" description: "Documentation for the RetryPayload type." diff --git a/web/src/content/docs/reference/SessionEndPayload.md b/web/src/content/docs/reference/SessionEndPayload.md index a8d47344..6cd91961 100644 --- a/web/src/content/docs/reference/SessionEndPayload.md +++ b/web/src/content/docs/reference/SessionEndPayload.md @@ -1,3 +1,4 @@ + --- title: "SessionEndPayload" description: "Documentation for the SessionEndPayload type." diff --git a/web/src/content/docs/reference/SessionEvent.md b/web/src/content/docs/reference/SessionEvent.md index 3c7819a0..4bdf8c0d 100644 --- a/web/src/content/docs/reference/SessionEvent.md +++ b/web/src/content/docs/reference/SessionEvent.md @@ -1,3 +1,4 @@ + --- title: "SessionEvent" description: "Documentation for the SessionEvent type." diff --git a/web/src/content/docs/reference/SessionFileRef.md b/web/src/content/docs/reference/SessionFileRef.md index cf7d7e3c..39b818d2 100644 --- a/web/src/content/docs/reference/SessionFileRef.md +++ b/web/src/content/docs/reference/SessionFileRef.md @@ -1,3 +1,4 @@ + --- title: "SessionFileRef" description: "Documentation for the SessionFileRef type." diff --git a/web/src/content/docs/reference/SessionRef.md b/web/src/content/docs/reference/SessionRef.md index 9fc79d1d..48aa2178 100644 --- a/web/src/content/docs/reference/SessionRef.md +++ b/web/src/content/docs/reference/SessionRef.md @@ -1,3 +1,4 @@ + --- title: "SessionRef" description: "Documentation for the SessionRef type." diff --git a/web/src/content/docs/reference/SessionStartPayload.md b/web/src/content/docs/reference/SessionStartPayload.md index daf312f5..66637b88 100644 --- a/web/src/content/docs/reference/SessionStartPayload.md +++ b/web/src/content/docs/reference/SessionStartPayload.md @@ -1,3 +1,4 @@ + --- title: "SessionStartPayload" description: "Documentation for the SessionStartPayload type." diff --git a/web/src/content/docs/reference/SessionSummary.md b/web/src/content/docs/reference/SessionSummary.md index 4b75b5a5..b6e686e8 100644 --- a/web/src/content/docs/reference/SessionSummary.md +++ b/web/src/content/docs/reference/SessionSummary.md @@ -1,3 +1,4 @@ + --- title: "SessionSummary" description: "Documentation for the SessionSummary type." diff --git a/web/src/content/docs/reference/SessionTrace.md b/web/src/content/docs/reference/SessionTrace.md index 138582b0..72191d72 100644 --- a/web/src/content/docs/reference/SessionTrace.md +++ b/web/src/content/docs/reference/SessionTrace.md @@ -1,3 +1,4 @@ + --- title: "SessionTrace" description: "Documentation for the SessionTrace type." diff --git a/web/src/content/docs/reference/SessionWarningPayload.md b/web/src/content/docs/reference/SessionWarningPayload.md index e2b16fd5..dede59b1 100644 --- a/web/src/content/docs/reference/SessionWarningPayload.md +++ b/web/src/content/docs/reference/SessionWarningPayload.md @@ -1,3 +1,4 @@ + --- title: "SessionWarningPayload" description: "Documentation for the SessionWarningPayload type." diff --git a/web/src/content/docs/reference/StatusEventPayload.md b/web/src/content/docs/reference/StatusEventPayload.md index 4d059c10..eef8b1c8 100644 --- a/web/src/content/docs/reference/StatusEventPayload.md +++ b/web/src/content/docs/reference/StatusEventPayload.md @@ -1,3 +1,4 @@ + --- title: "StatusEventPayload" description: "Documentation for the StatusEventPayload type." diff --git a/web/src/content/docs/reference/StreamChunk.md b/web/src/content/docs/reference/StreamChunk.md index 31f71f70..d67e40c5 100644 --- a/web/src/content/docs/reference/StreamChunk.md +++ b/web/src/content/docs/reference/StreamChunk.md @@ -1,3 +1,4 @@ + --- title: "StreamChunk" description: "Documentation for the StreamChunk type." diff --git a/web/src/content/docs/reference/StreamOptions.md b/web/src/content/docs/reference/StreamOptions.md index 6992d51a..24230c48 100644 --- a/web/src/content/docs/reference/StreamOptions.md +++ b/web/src/content/docs/reference/StreamOptions.md @@ -1,3 +1,4 @@ + --- title: "StreamOptions" description: "Documentation for the StreamOptions type." diff --git a/web/src/content/docs/reference/Template.md b/web/src/content/docs/reference/Template.md index b3c3e50a..345150b8 100644 --- a/web/src/content/docs/reference/Template.md +++ b/web/src/content/docs/reference/Template.md @@ -1,3 +1,4 @@ + --- title: "Template" description: "Documentation for the Template type." diff --git a/web/src/content/docs/reference/TextChunk.md b/web/src/content/docs/reference/TextChunk.md index 440ce9ba..a7e4d2d5 100644 --- a/web/src/content/docs/reference/TextChunk.md +++ b/web/src/content/docs/reference/TextChunk.md @@ -1,3 +1,4 @@ + --- title: "TextChunk" description: "Documentation for the TextChunk type." diff --git a/web/src/content/docs/reference/TextPart.md b/web/src/content/docs/reference/TextPart.md index 720bc40c..f9d6710d 100644 --- a/web/src/content/docs/reference/TextPart.md +++ b/web/src/content/docs/reference/TextPart.md @@ -1,3 +1,4 @@ + --- title: "TextPart" description: "Documentation for the TextPart type." diff --git a/web/src/content/docs/reference/ThinkingChunk.md b/web/src/content/docs/reference/ThinkingChunk.md index 8d8e45c9..9bca2418 100644 --- a/web/src/content/docs/reference/ThinkingChunk.md +++ b/web/src/content/docs/reference/ThinkingChunk.md @@ -1,3 +1,4 @@ + --- title: "ThinkingChunk" description: "Documentation for the ThinkingChunk type." diff --git a/web/src/content/docs/reference/ThinkingEventPayload.md b/web/src/content/docs/reference/ThinkingEventPayload.md index 1bfcfb6b..db53de11 100644 --- a/web/src/content/docs/reference/ThinkingEventPayload.md +++ b/web/src/content/docs/reference/ThinkingEventPayload.md @@ -1,3 +1,4 @@ + --- title: "ThinkingEventPayload" description: "Documentation for the ThinkingEventPayload type." diff --git a/web/src/content/docs/reference/ThreadMarker.md b/web/src/content/docs/reference/ThreadMarker.md index 0d329524..f7aff872 100644 --- a/web/src/content/docs/reference/ThreadMarker.md +++ b/web/src/content/docs/reference/ThreadMarker.md @@ -1,3 +1,4 @@ + --- title: "ThreadMarker" description: "Documentation for the ThreadMarker type." diff --git a/web/src/content/docs/reference/TokenEventPayload.md b/web/src/content/docs/reference/TokenEventPayload.md index e3d3a6a5..9c5ded27 100644 --- a/web/src/content/docs/reference/TokenEventPayload.md +++ b/web/src/content/docs/reference/TokenEventPayload.md @@ -1,3 +1,4 @@ + --- title: "TokenEventPayload" description: "Documentation for the TokenEventPayload type." diff --git a/web/src/content/docs/reference/TokenUsage.md b/web/src/content/docs/reference/TokenUsage.md index be3c7f1d..a4688e88 100644 --- a/web/src/content/docs/reference/TokenUsage.md +++ b/web/src/content/docs/reference/TokenUsage.md @@ -1,3 +1,4 @@ + --- title: "TokenUsage" description: "Documentation for the TokenUsage type." diff --git a/web/src/content/docs/reference/Tool.md b/web/src/content/docs/reference/Tool.md index a5eaa4ab..eef66b5a 100644 --- a/web/src/content/docs/reference/Tool.md +++ b/web/src/content/docs/reference/Tool.md @@ -1,3 +1,4 @@ + --- title: "Tool" description: "Documentation for the Tool type." diff --git a/web/src/content/docs/reference/ToolCall.md b/web/src/content/docs/reference/ToolCall.md index 7c6b8b2b..1f2d3cec 100644 --- a/web/src/content/docs/reference/ToolCall.md +++ b/web/src/content/docs/reference/ToolCall.md @@ -1,3 +1,4 @@ + --- title: "ToolCall" description: "Documentation for the ToolCall type." diff --git a/web/src/content/docs/reference/ToolCallCompletePayload.md b/web/src/content/docs/reference/ToolCallCompletePayload.md index f4651659..4b488ccf 100644 --- a/web/src/content/docs/reference/ToolCallCompletePayload.md +++ b/web/src/content/docs/reference/ToolCallCompletePayload.md @@ -1,3 +1,4 @@ + --- title: "ToolCallCompletePayload" description: "Documentation for the ToolCallCompletePayload type." diff --git a/web/src/content/docs/reference/ToolCallStartPayload.md b/web/src/content/docs/reference/ToolCallStartPayload.md index c0b4920a..1d865966 100644 --- a/web/src/content/docs/reference/ToolCallStartPayload.md +++ b/web/src/content/docs/reference/ToolCallStartPayload.md @@ -1,3 +1,4 @@ + --- title: "ToolCallStartPayload" description: "Documentation for the ToolCallStartPayload type." diff --git a/web/src/content/docs/reference/ToolChunk.md b/web/src/content/docs/reference/ToolChunk.md index 6b09d23b..8e26f2f0 100644 --- a/web/src/content/docs/reference/ToolChunk.md +++ b/web/src/content/docs/reference/ToolChunk.md @@ -1,3 +1,4 @@ + --- title: "ToolChunk" description: "Documentation for the ToolChunk type." diff --git a/web/src/content/docs/reference/ToolContext.md b/web/src/content/docs/reference/ToolContext.md index ca45bcb6..737a61b5 100644 --- a/web/src/content/docs/reference/ToolContext.md +++ b/web/src/content/docs/reference/ToolContext.md @@ -1,3 +1,4 @@ + --- title: "ToolContext" description: "Documentation for the ToolContext type." diff --git a/web/src/content/docs/reference/ToolDispatchResult.md b/web/src/content/docs/reference/ToolDispatchResult.md index 3e9a66bb..51e3bd9a 100644 --- a/web/src/content/docs/reference/ToolDispatchResult.md +++ b/web/src/content/docs/reference/ToolDispatchResult.md @@ -1,3 +1,4 @@ + --- title: "ToolDispatchResult" description: "Documentation for the ToolDispatchResult type." diff --git a/web/src/content/docs/reference/ToolExecutionCompletePayload.md b/web/src/content/docs/reference/ToolExecutionCompletePayload.md index dba8d7bf..3c7ed608 100644 --- a/web/src/content/docs/reference/ToolExecutionCompletePayload.md +++ b/web/src/content/docs/reference/ToolExecutionCompletePayload.md @@ -1,3 +1,4 @@ + --- title: "ToolExecutionCompletePayload" description: "Documentation for the ToolExecutionCompletePayload type." diff --git a/web/src/content/docs/reference/ToolExecutionStartPayload.md b/web/src/content/docs/reference/ToolExecutionStartPayload.md index 12e6145a..0f7ee48b 100644 --- a/web/src/content/docs/reference/ToolExecutionStartPayload.md +++ b/web/src/content/docs/reference/ToolExecutionStartPayload.md @@ -1,3 +1,4 @@ + --- title: "ToolExecutionStartPayload" description: "Documentation for the ToolExecutionStartPayload type." diff --git a/web/src/content/docs/reference/ToolResult.md b/web/src/content/docs/reference/ToolResult.md index e6717f78..5238676e 100644 --- a/web/src/content/docs/reference/ToolResult.md +++ b/web/src/content/docs/reference/ToolResult.md @@ -1,3 +1,4 @@ + --- title: "ToolResult" description: "Documentation for the ToolResult type." diff --git a/web/src/content/docs/reference/ToolResultPayload.md b/web/src/content/docs/reference/ToolResultPayload.md index c1ba162f..0bff5533 100644 --- a/web/src/content/docs/reference/ToolResultPayload.md +++ b/web/src/content/docs/reference/ToolResultPayload.md @@ -1,3 +1,4 @@ + --- title: "ToolResultPayload" description: "Documentation for the ToolResultPayload type." diff --git a/web/src/content/docs/reference/TraceFile.md b/web/src/content/docs/reference/TraceFile.md index cf4501f7..13a36358 100644 --- a/web/src/content/docs/reference/TraceFile.md +++ b/web/src/content/docs/reference/TraceFile.md @@ -1,3 +1,4 @@ + --- title: "TraceFile" description: "Documentation for the TraceFile type." diff --git a/web/src/content/docs/reference/TraceSpan.md b/web/src/content/docs/reference/TraceSpan.md index cd1abf55..13a19f6e 100644 --- a/web/src/content/docs/reference/TraceSpan.md +++ b/web/src/content/docs/reference/TraceSpan.md @@ -1,3 +1,4 @@ + --- title: "TraceSpan" description: "Documentation for the TraceSpan type." diff --git a/web/src/content/docs/reference/TraceTime.md b/web/src/content/docs/reference/TraceTime.md index f48230e9..36dbb735 100644 --- a/web/src/content/docs/reference/TraceTime.md +++ b/web/src/content/docs/reference/TraceTime.md @@ -1,3 +1,4 @@ + --- title: "TraceTime" description: "Documentation for the TraceTime type." diff --git a/web/src/content/docs/reference/TrajectoryEvent.md b/web/src/content/docs/reference/TrajectoryEvent.md index 0a1eeae1..ca62ead2 100644 --- a/web/src/content/docs/reference/TrajectoryEvent.md +++ b/web/src/content/docs/reference/TrajectoryEvent.md @@ -1,3 +1,4 @@ + --- title: "TrajectoryEvent" description: "Documentation for the TrajectoryEvent type." diff --git a/web/src/content/docs/reference/TurnEndPayload.md b/web/src/content/docs/reference/TurnEndPayload.md index ef3f6c83..18d6967a 100644 --- a/web/src/content/docs/reference/TurnEndPayload.md +++ b/web/src/content/docs/reference/TurnEndPayload.md @@ -1,3 +1,4 @@ + --- title: "TurnEndPayload" description: "Documentation for the TurnEndPayload type." diff --git a/web/src/content/docs/reference/TurnEvent.md b/web/src/content/docs/reference/TurnEvent.md index f0b1520d..166b4c4a 100644 --- a/web/src/content/docs/reference/TurnEvent.md +++ b/web/src/content/docs/reference/TurnEvent.md @@ -1,3 +1,4 @@ + --- title: "TurnEvent" description: "Documentation for the TurnEvent type." diff --git a/web/src/content/docs/reference/TurnOptions.md b/web/src/content/docs/reference/TurnOptions.md index 2454df99..6c231e91 100644 --- a/web/src/content/docs/reference/TurnOptions.md +++ b/web/src/content/docs/reference/TurnOptions.md @@ -1,3 +1,4 @@ + --- title: "TurnOptions" description: "Documentation for the TurnOptions type." diff --git a/web/src/content/docs/reference/TurnStartPayload.md b/web/src/content/docs/reference/TurnStartPayload.md index 6f140bbf..13348266 100644 --- a/web/src/content/docs/reference/TurnStartPayload.md +++ b/web/src/content/docs/reference/TurnStartPayload.md @@ -1,3 +1,4 @@ + --- title: "TurnStartPayload" description: "Documentation for the TurnStartPayload type." diff --git a/web/src/content/docs/reference/TurnSummary.md b/web/src/content/docs/reference/TurnSummary.md index b85e83e1..dff06534 100644 --- a/web/src/content/docs/reference/TurnSummary.md +++ b/web/src/content/docs/reference/TurnSummary.md @@ -1,3 +1,4 @@ + --- title: "TurnSummary" description: "Documentation for the TurnSummary type." diff --git a/web/src/content/docs/reference/TurnTrace.md b/web/src/content/docs/reference/TurnTrace.md index 87886e75..6c260375 100644 --- a/web/src/content/docs/reference/TurnTrace.md +++ b/web/src/content/docs/reference/TurnTrace.md @@ -1,3 +1,4 @@ + --- title: "TurnTrace" description: "Documentation for the TurnTrace type." diff --git a/web/src/content/docs/reference/ValidationError.md b/web/src/content/docs/reference/ValidationError.md index bfca31c4..4f82edec 100644 --- a/web/src/content/docs/reference/ValidationError.md +++ b/web/src/content/docs/reference/ValidationError.md @@ -1,3 +1,4 @@ + --- title: "ValidationError" description: "Documentation for the ValidationError type." diff --git a/web/src/content/docs/reference/ValidationResult.md b/web/src/content/docs/reference/ValidationResult.md index 5325d166..02de1d46 100644 --- a/web/src/content/docs/reference/ValidationResult.md +++ b/web/src/content/docs/reference/ValidationResult.md @@ -1,3 +1,4 @@ + --- title: "ValidationResult" description: "Documentation for the ValidationResult type." diff --git a/web/src/content/docs/reference/index.md b/web/src/content/docs/reference/index.md index ee145108..32c210f8 100644 --- a/web/src/content/docs/reference/index.md +++ b/web/src/content/docs/reference/index.md @@ -1,3 +1,4 @@ + --- title: "Prompty Schema" description: "Overview of generated Prompty schema types." From fca3f311d0c71276f11a5365e95f7538ac6bc6fb Mon Sep 17 00:00:00 2001 From: Seth Juarez Date: Sat, 27 Jun 2026 16:59:29 -0700 Subject: [PATCH 07/22] Bump Typra emitter to 0.2.5 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- schema/package-lock.json | 361 ++++++++++++++++++++++++++++++++++++--- schema/package.json | 6 +- 2 files changed, 336 insertions(+), 31 deletions(-) diff --git a/schema/package-lock.json b/schema/package-lock.json index 6e6fac86..8c179039 100644 --- a/schema/package-lock.json +++ b/schema/package-lock.json @@ -6,9 +6,9 @@ "": { "name": "prompty-schema", "dependencies": { - "@typespec/compiler": "latest", - "@typespec/json-schema": "latest", - "@typra/emitter": "0.2.4" + "@typespec/compiler": "1.10.0", + "@typespec/json-schema": "1.10.0", + "@typra/emitter": "0.2.5" } }, "node_modules/@babel/code-frame": { @@ -368,6 +368,53 @@ "node": ">=18.0.0" } }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", + "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@typespec/asset-emitter": { "version": "0.79.1", "license": "MIT", @@ -379,56 +426,59 @@ } }, "node_modules/@typespec/compiler": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/@typespec/compiler/-/compiler-1.13.0.tgz", - "integrity": "sha512-DonoHiyAMx0UjSmssqTrFtya+v97wny1aHcTLU5QF2wFzLATtcwUU9hbPC+eXhepuTunMOCHf8yk3pEsH6PZYA==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@typespec/compiler/-/compiler-1.10.0.tgz", + "integrity": "sha512-R6BATDkughntPpaxeESJF+wxma5PEjgmnnKvH0/ByqUH8VyhIckQWE9kkP0Uc/EJ0o0VYhe8qCwWQvV70k5lTw==", "license": "MIT", "peer": true, "dependencies": { - "@babel/code-frame": "^7.29.0", - "@inquirer/prompts": "^8.4.1", - "ajv": "^8.18.0", - "change-case": "^5.4.4", + "@babel/code-frame": "~7.29.0", + "@inquirer/prompts": "^8.0.1", + "ajv": "~8.18.0", + "change-case": "~5.4.4", "env-paths": "^4.0.0", + "globby": "~16.1.0", "is-unicode-supported": "^2.1.0", - "mustache": "^4.2.0", - "picocolors": "^1.1.1", - "prettier": "^3.8.1", - "semver": "^7.7.4", - "tar": "^7.5.13", - "temporal-polyfill": "^0.3.2", - "vscode-languageserver": "^9.0.1", - "vscode-languageserver-textdocument": "^1.0.12", - "yaml": "^2.8.3", - "yargs": "^18.0.0" + "mustache": "~4.2.0", + "picocolors": "~1.1.1", + "prettier": "~3.8.0", + "semver": "^7.7.1", + "tar": "^7.5.2", + "temporal-polyfill": "^0.3.0", + "vscode-languageserver": "~9.0.1", + "vscode-languageserver-textdocument": "~1.0.12", + "yaml": "~2.8.2", + "yargs": "~18.0.0" }, "bin": { "tsp": "cmd/tsp.js", "tsp-server": "cmd/tsp-server.js" }, "engines": { - "node": ">=22.0.0" + "node": ">=20.0.0" } }, "node_modules/@typespec/json-schema": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/@typespec/json-schema/-/json-schema-1.13.0.tgz", - "integrity": "sha512-o5yxs4aGhfFTkVNAkpFlO3LP2O8kWHQUgBzZ0s6tcbFlElGH86jUsdesT8O5ijoA0Cpa//m39wwxIcmBB2DiiA==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@typespec/json-schema/-/json-schema-1.10.0.tgz", + "integrity": "sha512-FZTJvZoIqMbe/4qi17e8q3KF/2VDSyXiiF8QYwH4lar5dtEDGgwrw9ShLeLNiEZh8Ph3GjrQQV5qdpheDFJJvw==", "license": "MIT", "peer": true, "dependencies": { "@typespec/asset-emitter": "^0.79.1", - "yaml": "^2.8.3" + "yaml": "~2.8.2" }, "engines": { - "node": ">=22.0.0" + "node": ">=20.0.0" }, "peerDependencies": { - "@typespec/compiler": "^1.13.0" + "@typespec/compiler": "^1.10.0" } }, "node_modules/@typra/emitter": { - "version": "0.2.4", + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@typra/emitter/-/emitter-0.2.5.tgz", + "integrity": "sha512-NAnG9k4IEpfp17CtAmZ/v8WtpMP721CDCt32bOBTSyPcxbPrKMAQMW1KmTk+TzIIjpUg0ozN8HBGzF+Qi/7I+g==", "license": "MIT", "dependencies": { "xml-formatter": "^3.6.7", @@ -476,6 +526,18 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/change-case": { "version": "5.4.4", "license": "MIT" @@ -542,6 +604,22 @@ "version": "3.1.3", "license": "MIT" }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, "node_modules/fast-string-truncated-width": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz", @@ -580,6 +658,27 @@ "fast-string-width": "^3.0.2" } }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/get-caller-file": { "version": "2.0.5", "license": "ISC", @@ -597,6 +696,38 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globby": { + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-16.1.1.tgz", + "integrity": "sha512-dW7vl+yiAJSp6aCekaVnVJxurRv7DCOLyXqEG3RYMYUg7AuJ2jCqPkZTA8ooqC2vtnkaMcV5WfFBMuEnTu1OQg==", + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^4.0.0", + "fast-glob": "^3.3.3", + "ignore": "^7.0.5", + "is-path-inside": "^4.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.4.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/iconv-lite": { "version": "0.7.2", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", @@ -613,6 +744,57 @@ "url": "https://opencollective.com/express" } }, + "node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz", + "integrity": "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-safe-filename": { "version": "0.1.1", "license": "MIT", @@ -641,6 +823,28 @@ "version": "1.0.0", "license": "MIT" }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, "node_modules/minipass": { "version": "7.1.3", "license": "BlueOak-1.0.0", @@ -678,6 +882,18 @@ "version": "1.1.1", "license": "ISC" }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/prettier": { "version": "3.8.1", "license": "MIT", @@ -691,6 +907,26 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/require-from-string": { "version": "2.0.2", "license": "MIT", @@ -698,6 +934,39 @@ "node": ">=0.10.0" } }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -726,6 +995,18 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/string-width": { "version": "7.2.0", "license": "MIT", @@ -779,6 +1060,30 @@ "version": "0.3.1", "license": "ISC" }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/unicorn-magic": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.4.0.tgz", + "integrity": "sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/vscode-jsonrpc": { "version": "8.2.0", "license": "MIT", diff --git a/schema/package.json b/schema/package.json index e1695e34..baa124d0 100644 --- a/schema/package.json +++ b/schema/package.json @@ -10,8 +10,8 @@ "build": "npm run format:tsp && npm run generate && npm run format:rust" }, "dependencies": { - "@typra/emitter": "0.2.4", - "@typespec/compiler": "latest", - "@typespec/json-schema": "latest" + "@typra/emitter": "0.2.5", + "@typespec/compiler": "1.10.0", + "@typespec/json-schema": "1.10.0" } } From fdbd3e31522687f7cc148d32ca987fa5c727dbdd Mon Sep 17 00:00:00 2001 From: Seth Juarez Date: Sat, 27 Jun 2026 17:41:11 -0700 Subject: [PATCH 08/22] Bump Typra emitter to 0.2.6 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- schema/package-lock.json | 12 ++++++------ schema/package.json | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/schema/package-lock.json b/schema/package-lock.json index 8c179039..070c7d1d 100644 --- a/schema/package-lock.json +++ b/schema/package-lock.json @@ -8,7 +8,7 @@ "dependencies": { "@typespec/compiler": "1.10.0", "@typespec/json-schema": "1.10.0", - "@typra/emitter": "0.2.5" + "@typra/emitter": "0.2.6" } }, "node_modules/@babel/code-frame": { @@ -476,9 +476,9 @@ } }, "node_modules/@typra/emitter": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/@typra/emitter/-/emitter-0.2.5.tgz", - "integrity": "sha512-NAnG9k4IEpfp17CtAmZ/v8WtpMP721CDCt32bOBTSyPcxbPrKMAQMW1KmTk+TzIIjpUg0ozN8HBGzF+Qi/7I+g==", + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/@typra/emitter/-/emitter-0.2.6.tgz", + "integrity": "sha512-S3UnGbWD3XOKihglgOzG55+PYcBJBdHQelriJm6sfsSf7b+vVouKMEFHAqnmSH3LilUOt141vZI2buN2JtGf3A==", "license": "MIT", "dependencies": { "xml-formatter": "^3.6.7", @@ -488,8 +488,8 @@ "typra-generate": "dist/src/cli.js" }, "peerDependencies": { - "@typespec/compiler": "latest", - "@typespec/json-schema": "latest" + "@typespec/compiler": "1.10.0", + "@typespec/json-schema": "1.10.0" } }, "node_modules/ajv": { diff --git a/schema/package.json b/schema/package.json index baa124d0..845ac430 100644 --- a/schema/package.json +++ b/schema/package.json @@ -10,7 +10,7 @@ "build": "npm run format:tsp && npm run generate && npm run format:rust" }, "dependencies": { - "@typra/emitter": "0.2.5", + "@typra/emitter": "0.2.6", "@typespec/compiler": "1.10.0", "@typespec/json-schema": "1.10.0" } From 826fe3b7234103312b7c439ebdc6c3ffcc426b1a Mon Sep 17 00:00:00 2001 From: Seth Juarez Date: Sat, 27 Jun 2026 19:00:20 -0700 Subject: [PATCH 09/22] Bump Typra emitter to 0.2.7 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- schema/package-lock.json | 12 +++++++----- schema/package.json | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/schema/package-lock.json b/schema/package-lock.json index 070c7d1d..488182dd 100644 --- a/schema/package-lock.json +++ b/schema/package-lock.json @@ -8,7 +8,7 @@ "dependencies": { "@typespec/compiler": "1.10.0", "@typespec/json-schema": "1.10.0", - "@typra/emitter": "0.2.6" + "@typra/emitter": "0.2.7" } }, "node_modules/@babel/code-frame": { @@ -476,16 +476,18 @@ } }, "node_modules/@typra/emitter": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/@typra/emitter/-/emitter-0.2.6.tgz", - "integrity": "sha512-S3UnGbWD3XOKihglgOzG55+PYcBJBdHQelriJm6sfsSf7b+vVouKMEFHAqnmSH3LilUOt141vZI2buN2JtGf3A==", + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@typra/emitter/-/emitter-0.2.7.tgz", + "integrity": "sha512-L3k7U3AYVhYtcuwboGHUpvawRZyGt3/zjeljx5jkx6xL8CyC+J2Eg7EzYroQEaWuIuTU/tEk7vkWIfJp+U1xUw==", "license": "MIT", "dependencies": { "xml-formatter": "^3.6.7", "yaml": "^2.8.1" }, "bin": { - "typra-generate": "dist/src/cli.js" + "typra-consumer-smoke": "dist/src/consumer-smoke.js", + "typra-generate": "dist/src/cli.js", + "typra-verify": "dist/src/verify-cli.js" }, "peerDependencies": { "@typespec/compiler": "1.10.0", diff --git a/schema/package.json b/schema/package.json index 845ac430..334111fc 100644 --- a/schema/package.json +++ b/schema/package.json @@ -10,7 +10,7 @@ "build": "npm run format:tsp && npm run generate && npm run format:rust" }, "dependencies": { - "@typra/emitter": "0.2.6", + "@typra/emitter": "0.2.7", "@typespec/compiler": "1.10.0", "@typespec/json-schema": "1.10.0" } From 08645e194f77a15d9db294f04ed22915edfc8c4b Mon Sep 17 00:00:00 2001 From: Seth Juarez Date: Sat, 27 Jun 2026 23:08:59 -0700 Subject: [PATCH 10/22] Bump Typra emitter to 0.3.0 Regenerate Go model output with the published Typra 0.3.0 emitter. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../model/anonymous_connection_test.go | 70 + .../go/prompty/model/anthropic_image_block.go | 8 +- .../prompty/model/anthropic_image_source.go | 8 +- .../model/anthropic_image_source_test.go | 70 + .../model/anthropic_messages_request.go | 13 +- .../model/anthropic_messages_request_test.go | 173 + .../model/anthropic_messages_response.go | 11 +- .../model/anthropic_messages_response_test.go | 84 + .../go/prompty/model/anthropic_text_block.go | 8 +- .../model/anthropic_text_block_test.go | 56 + .../model/anthropic_tool_definition.go | 8 +- .../model/anthropic_tool_definition_test.go | 70 + .../model/anthropic_tool_result_block.go | 8 +- .../model/anthropic_tool_result_block_test.go | 70 + .../prompty/model/anthropic_tool_use_block.go | 8 +- .../model/anthropic_tool_use_block_test.go | 117 + runtime/go/prompty/model/anthropic_usage.go | 8 +- .../go/prompty/model/anthropic_usage_test.go | 70 + .../prompty/model/anthropic_wire_message.go | 11 +- .../model/anthropic_wire_message_test.go | 56 + .../prompty/model/api_key_connection_test.go | 84 + .../go/prompty/model/array_property_test.go | 51 + runtime/go/prompty/model/audio_part_test.go | 70 + runtime/go/prompty/model/binding.go | 8 +- runtime/go/prompty/model/binding_test.go | 70 + runtime/go/prompty/model/checkpoint.go | 8 +- runtime/go/prompty/model/checkpoint_test.go | 126 + .../model/compaction_complete_payload.go | 8 +- .../model/compaction_complete_payload_test.go | 84 + runtime/go/prompty/model/compaction_config.go | 8 +- .../prompty/model/compaction_config_test.go | 96 + .../model/compaction_failed_payload.go | 8 +- .../model/compaction_failed_payload_test.go | 56 + .../prompty/model/compaction_start_payload.go | 8 +- .../model/compaction_start_payload_test.go | 56 + runtime/go/prompty/model/connection.go | 61 +- runtime/go/prompty/model/connection_test.go | 44 + runtime/go/prompty/model/content_part.go | 40 +- runtime/go/prompty/model/context.go | 81 + runtime/go/prompty/model/custom_tool_test.go | 79 + .../go/prompty/model/done_event_payload.go | 8 +- runtime/go/prompty/model/error_chunk_test.go | 56 + .../go/prompty/model/error_event_payload.go | 8 +- .../prompty/model/error_event_payload_test.go | 84 + .../go/prompty/model/file_not_found_error.go | 8 +- .../model/file_not_found_error_test.go | 70 + runtime/go/prompty/model/file_part_test.go | 70 + runtime/go/prompty/model/format_config.go | 8 +- .../go/prompty/model/format_config_test.go | 47 + .../prompty/model/foundry_connection_test.go | 98 + .../go/prompty/model/function_tool_test.go | 205 ++ runtime/go/prompty/model/guardrail_result.go | 8 +- .../go/prompty/model/guardrail_result_test.go | 70 + runtime/go/prompty/model/harness_context.go | 8 +- .../go/prompty/model/harness_context_test.go | 70 + runtime/go/prompty/model/hook_end_payload.go | 8 +- .../go/prompty/model/hook_end_payload_test.go | 112 + .../go/prompty/model/hook_start_payload.go | 8 +- .../prompty/model/hook_start_payload_test.go | 70 + runtime/go/prompty/model/host_tool_request.go | 8 +- .../prompty/model/host_tool_request_test.go | 98 + runtime/go/prompty/model/host_tool_result.go | 8 +- .../go/prompty/model/host_tool_result_test.go | 140 + runtime/go/prompty/model/image_part_test.go | 84 + runtime/go/prompty/model/invoker_error.go | 8 +- .../go/prompty/model/invoker_error_test.go | 84 + .../go/prompty/model/llm_complete_payload.go | 8 +- .../model/llm_complete_payload_test.go | 84 + runtime/go/prompty/model/llm_start_payload.go | 8 +- .../prompty/model/llm_start_payload_test.go | 98 + runtime/go/prompty/model/mcp_approval_mode.go | 18 +- .../prompty/model/mcp_approval_mode_test.go | 150 + runtime/go/prompty/model/mcp_tool_test.go | 185 + runtime/go/prompty/model/message.go | 8 +- runtime/go/prompty/model/message_test.go | 203 + .../prompty/model/messages_updated_payload.go | 8 +- .../model/messages_updated_payload_test.go | 70 + runtime/go/prompty/model/model.go | 8 +- runtime/go/prompty/model/model_info.go | 18 +- runtime/go/prompty/model/model_info_test.go | 241 ++ runtime/go/prompty/model/model_options.go | 13 +- .../go/prompty/model/model_options_test.go | 424 +++ runtime/go/prompty/model/model_test.go | 172 + .../prompty/model/o_auth_connection_test.go | 159 + .../go/prompty/model/object_property_test.go | 59 + .../go/prompty/model/open_api_tool_test.go | 75 + runtime/go/prompty/model/parser_config.go | 8 +- .../go/prompty/model/parser_config_test.go | 45 + .../model/permission_completed_payload.go | 8 +- .../permission_completed_payload_test.go | 112 + .../go/prompty/model/permission_decision.go | 8 +- .../prompty/model/permission_decision_test.go | 112 + .../go/prompty/model/permission_request.go | 8 +- .../prompty/model/permission_request_test.go | 112 + .../model/permission_requested_payload.go | 8 +- .../permission_requested_payload_test.go | 112 + runtime/go/prompty/model/prompty.go | 11 +- runtime/go/prompty/model/prompty_test.go | 3266 ++++++++++++++++- runtime/go/prompty/model/prompty_tool_test.go | 84 + runtime/go/prompty/model/property.go | 30 +- runtime/go/prompty/model/property_test.go | 59 + runtime/go/prompty/model/redacted_field.go | 8 +- .../go/prompty/model/redacted_field_test.go | 84 + .../go/prompty/model/redaction_metadata.go | 8 +- .../prompty/model/redaction_metadata_test.go | 70 + .../model/reference_connection_test.go | 84 + .../prompty/model/remote_connection_test.go | 84 + runtime/go/prompty/model/retry_payload.go | 8 +- .../go/prompty/model/retry_payload_test.go | 112 + .../go/prompty/model/session_end_payload.go | 8 +- .../prompty/model/session_end_payload_test.go | 98 + runtime/go/prompty/model/session_event.go | 8 +- .../go/prompty/model/session_event_test.go | 126 + runtime/go/prompty/model/session_file_ref.go | 8 +- .../go/prompty/model/session_file_ref_test.go | 112 + runtime/go/prompty/model/session_ref.go | 8 +- runtime/go/prompty/model/session_ref_test.go | 112 + .../go/prompty/model/session_start_payload.go | 8 +- .../model/session_start_payload_test.go | 154 + runtime/go/prompty/model/session_summary.go | 8 +- .../go/prompty/model/session_summary_test.go | 112 + runtime/go/prompty/model/session_trace.go | 8 +- .../go/prompty/model/session_trace_test.go | 98 + .../prompty/model/session_warning_payload.go | 8 +- .../model/session_warning_payload_test.go | 70 + .../go/prompty/model/status_event_payload.go | 8 +- .../model/status_event_payload_test.go | 56 + runtime/go/prompty/model/stream_chunk.go | 40 +- runtime/go/prompty/model/stream_options.go | 8 +- .../go/prompty/model/stream_options_test.go | 56 + runtime/go/prompty/model/template.go | 14 +- runtime/go/prompty/model/template_test.go | 98 + runtime/go/prompty/model/text_chunk_test.go | 56 + runtime/go/prompty/model/text_part_test.go | 56 + .../go/prompty/model/thinking_chunk_test.go | 56 + .../prompty/model/thinking_event_payload.go | 8 +- .../model/thinking_event_payload_test.go | 56 + runtime/go/prompty/model/thread_marker.go | 8 +- .../go/prompty/model/thread_marker_test.go | 70 + .../go/prompty/model/token_event_payload.go | 8 +- .../prompty/model/token_event_payload_test.go | 56 + runtime/go/prompty/model/token_usage.go | 8 +- runtime/go/prompty/model/token_usage_test.go | 139 + runtime/go/prompty/model/tool.go | 56 +- runtime/go/prompty/model/tool_call.go | 8 +- .../model/tool_call_complete_payload.go | 8 +- .../model/tool_call_complete_payload_test.go | 112 + .../prompty/model/tool_call_start_payload.go | 8 +- .../model/tool_call_start_payload_test.go | 84 + runtime/go/prompty/model/tool_call_test.go | 84 + runtime/go/prompty/model/tool_chunk_test.go | 118 + runtime/go/prompty/model/tool_context.go | 8 +- runtime/go/prompty/model/tool_context_test.go | 93 + .../go/prompty/model/tool_dispatch_result.go | 8 +- .../model/tool_dispatch_result_test.go | 82 + .../model/tool_execution_complete_payload.go | 8 +- .../tool_execution_complete_payload_test.go | 140 + .../model/tool_execution_start_payload.go | 8 +- .../tool_execution_start_payload_test.go | 98 + runtime/go/prompty/model/tool_result.go | 8 +- .../go/prompty/model/tool_result_payload.go | 8 +- .../prompty/model/tool_result_payload_test.go | 68 + runtime/go/prompty/model/tool_result_test.go | 184 + runtime/go/prompty/model/tool_test.go | 49 + runtime/go/prompty/model/trace_file.go | 8 +- runtime/go/prompty/model/trace_file_test.go | 70 + runtime/go/prompty/model/trace_span.go | 11 +- runtime/go/prompty/model/trace_span_test.go | 84 + runtime/go/prompty/model/trace_time.go | 8 +- runtime/go/prompty/model/trace_time_test.go | 84 + runtime/go/prompty/model/trajectory_event.go | 8 +- .../go/prompty/model/trajectory_event_test.go | 140 + runtime/go/prompty/model/turn_end_payload.go | 8 +- .../go/prompty/model/turn_end_payload_test.go | 70 + runtime/go/prompty/model/turn_event.go | 8 +- runtime/go/prompty/model/turn_event_test.go | 126 + runtime/go/prompty/model/turn_options.go | 8 +- runtime/go/prompty/model/turn_options_test.go | 152 + .../go/prompty/model/turn_start_payload.go | 8 +- .../prompty/model/turn_start_payload_test.go | 70 + runtime/go/prompty/model/turn_summary.go | 8 +- runtime/go/prompty/model/turn_summary_test.go | 140 + runtime/go/prompty/model/turn_trace.go | 8 +- runtime/go/prompty/model/turn_trace_test.go | 84 + runtime/go/prompty/model/validation_error.go | 8 +- .../go/prompty/model/validation_error_test.go | 84 + runtime/go/prompty/model/validation_result.go | 8 +- .../prompty/model/validation_result_test.go | 79 + schema/package-lock.json | 8 +- schema/package.json | 4 +- 190 files changed, 13417 insertions(+), 733 deletions(-) diff --git a/runtime/go/prompty/model/anonymous_connection_test.go b/runtime/go/prompty/model/anonymous_connection_test.go index 053b28dc..ee56eba9 100644 --- a/runtime/go/prompty/model/anonymous_connection_test.go +++ b/runtime/go/prompty/model/anonymous_connection_test.go @@ -63,6 +63,47 @@ endpoint: "https://{your-custom-endpoint}.openai.azure.com/" } } +// TestAnonymousConnectionFromJSON tests loading AnonymousConnection through the generated JSON helper +func TestAnonymousConnectionFromJSON(t *testing.T) { + jsonData := ` +{ + "kind": "anonymous", + "endpoint": "https://{your-custom-endpoint}.openai.azure.com/" +} +` + + instance, err := prompty.AnonymousConnectionFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load AnonymousConnection from JSON helper: %v", err) + } + if instance.Kind != "anonymous" { + t.Errorf(`Expected Kind to be "anonymous", got %v`, instance.Kind) + } + if instance.Endpoint != "https://{your-custom-endpoint}.openai.azure.com/" { + t.Errorf(`Expected Endpoint to be "https://{your-custom-endpoint}.openai.azure.com/", got %v`, instance.Endpoint) + } +} + +// TestAnonymousConnectionFromYAML tests loading AnonymousConnection through the generated YAML helper +func TestAnonymousConnectionFromYAML(t *testing.T) { + yamlData := ` +kind: anonymous +endpoint: "https://{your-custom-endpoint}.openai.azure.com/" + +` + + instance, err := prompty.AnonymousConnectionFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load AnonymousConnection from YAML helper: %v", err) + } + if instance.Kind != "anonymous" { + t.Errorf(`Expected Kind to be "anonymous", got %v`, instance.Kind) + } + if instance.Endpoint != "https://{your-custom-endpoint}.openai.azure.com/" { + t.Errorf(`Expected Endpoint to be "https://{your-custom-endpoint}.openai.azure.com/", got %v`, instance.Endpoint) + } +} + // TestAnonymousConnectionRoundtrip tests load -> save -> load produces equivalent data func TestAnonymousConnectionRoundtrip(t *testing.T) { jsonData := ` @@ -123,6 +164,17 @@ func TestAnonymousConnectionToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadAnonymousConnection(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Kind != "anonymous" { + t.Errorf(`Expected Kind to be "anonymous", got %v`, reloaded.Kind) + } + if reloaded.Endpoint != "https://{your-custom-endpoint}.openai.azure.com/" { + t.Errorf(`Expected Endpoint to be "https://{your-custom-endpoint}.openai.azure.com/", got %v`, reloaded.Endpoint) + } } // TestAnonymousConnectionToYAML tests that ToYAML produces valid YAML @@ -152,4 +204,22 @@ func TestAnonymousConnectionToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadAnonymousConnection(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Kind != "anonymous" { + t.Errorf(`Expected Kind to be "anonymous", got %v`, reloaded.Kind) + } + if reloaded.Endpoint != "https://{your-custom-endpoint}.openai.azure.com/" { + t.Errorf(`Expected Endpoint to be "https://{your-custom-endpoint}.openai.azure.com/", got %v`, reloaded.Endpoint) + } +} + +// TestAnonymousConnectionFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestAnonymousConnectionFromJSONInvalid(t *testing.T) { + if _, err := prompty.AnonymousConnectionFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/anthropic_image_block.go b/runtime/go/prompty/model/anthropic_image_block.go index 2e357896..ff4b9f2a 100644 --- a/runtime/go/prompty/model/anthropic_image_block.go +++ b/runtime/go/prompty/model/anthropic_image_block.go @@ -39,7 +39,7 @@ func LoadAnthropicImageBlock(data interface{}, ctx *LoadContext) (AnthropicImage } // Save serializes AnthropicImageBlock to map[string]interface{} -func (obj *AnthropicImageBlock) Save(ctx *SaveContext) map[string]interface{} { +func (obj AnthropicImageBlock) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["type"] = obj.Type @@ -63,11 +63,7 @@ func (obj *AnthropicImageBlock) ToJSON() (string, error) { func (obj *AnthropicImageBlock) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates AnthropicImageBlock from JSON string diff --git a/runtime/go/prompty/model/anthropic_image_source.go b/runtime/go/prompty/model/anthropic_image_source.go index 6d049e9d..b3afae85 100644 --- a/runtime/go/prompty/model/anthropic_image_source.go +++ b/runtime/go/prompty/model/anthropic_image_source.go @@ -39,7 +39,7 @@ func LoadAnthropicImageSource(data interface{}, ctx *LoadContext) (AnthropicImag } // Save serializes AnthropicImageSource to map[string]interface{} -func (obj *AnthropicImageSource) Save(ctx *SaveContext) map[string]interface{} { +func (obj AnthropicImageSource) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["type"] = obj.Type result["media_type"] = obj.MediaType @@ -63,11 +63,7 @@ func (obj *AnthropicImageSource) ToJSON() (string, error) { func (obj *AnthropicImageSource) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates AnthropicImageSource from JSON string diff --git a/runtime/go/prompty/model/anthropic_image_source_test.go b/runtime/go/prompty/model/anthropic_image_source_test.go index 019efb04..844d95fd 100644 --- a/runtime/go/prompty/model/anthropic_image_source_test.go +++ b/runtime/go/prompty/model/anthropic_image_source_test.go @@ -63,6 +63,47 @@ data: iVBORw0KGgo... } } +// TestAnthropicImageSourceFromJSON tests loading AnthropicImageSource through the generated JSON helper +func TestAnthropicImageSourceFromJSON(t *testing.T) { + jsonData := ` +{ + "media_type": "image/png", + "data": "iVBORw0KGgo..." +} +` + + instance, err := prompty.AnthropicImageSourceFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load AnthropicImageSource from JSON helper: %v", err) + } + if instance.MediaType != "image/png" { + t.Errorf(`Expected MediaType to be "image/png", got %v`, instance.MediaType) + } + if instance.Data != "iVBORw0KGgo..." { + t.Errorf(`Expected Data to be "iVBORw0KGgo...", got %v`, instance.Data) + } +} + +// TestAnthropicImageSourceFromYAML tests loading AnthropicImageSource through the generated YAML helper +func TestAnthropicImageSourceFromYAML(t *testing.T) { + yamlData := ` +media_type: image/png +data: iVBORw0KGgo... + +` + + instance, err := prompty.AnthropicImageSourceFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load AnthropicImageSource from YAML helper: %v", err) + } + if instance.MediaType != "image/png" { + t.Errorf(`Expected MediaType to be "image/png", got %v`, instance.MediaType) + } + if instance.Data != "iVBORw0KGgo..." { + t.Errorf(`Expected Data to be "iVBORw0KGgo...", got %v`, instance.Data) + } +} + // TestAnthropicImageSourceRoundtrip tests load -> save -> load produces equivalent data func TestAnthropicImageSourceRoundtrip(t *testing.T) { jsonData := ` @@ -123,6 +164,17 @@ func TestAnthropicImageSourceToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadAnthropicImageSource(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.MediaType != "image/png" { + t.Errorf(`Expected MediaType to be "image/png", got %v`, reloaded.MediaType) + } + if reloaded.Data != "iVBORw0KGgo..." { + t.Errorf(`Expected Data to be "iVBORw0KGgo...", got %v`, reloaded.Data) + } } // TestAnthropicImageSourceToYAML tests that ToYAML produces valid YAML @@ -152,4 +204,22 @@ func TestAnthropicImageSourceToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadAnthropicImageSource(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.MediaType != "image/png" { + t.Errorf(`Expected MediaType to be "image/png", got %v`, reloaded.MediaType) + } + if reloaded.Data != "iVBORw0KGgo..." { + t.Errorf(`Expected Data to be "iVBORw0KGgo...", got %v`, reloaded.Data) + } +} + +// TestAnthropicImageSourceFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestAnthropicImageSourceFromJSONInvalid(t *testing.T) { + if _, err := prompty.AnthropicImageSourceFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/anthropic_messages_request.go b/runtime/go/prompty/model/anthropic_messages_request.go index 9f6f58e0..3aad6783 100644 --- a/runtime/go/prompty/model/anthropic_messages_request.go +++ b/runtime/go/prompty/model/anthropic_messages_request.go @@ -109,11 +109,14 @@ func LoadAnthropicMessagesRequest(data interface{}, ctx *LoadContext) (Anthropic result.TopK = &v } if val, ok := m["stop_sequences"]; ok && val != nil { - if arr, ok := val.([]interface{}); ok { + switch arr := val.(type) { + case []interface{}: result.StopSequences = make([]string, len(arr)) for i, v := range arr { result.StopSequences[i] = v.(string) } + case []string: + result.StopSequences = arr } } if val, ok := m["tools"]; ok && val != nil { @@ -133,7 +136,7 @@ func LoadAnthropicMessagesRequest(data interface{}, ctx *LoadContext) (Anthropic } // Save serializes AnthropicMessagesRequest to map[string]interface{} -func (obj *AnthropicMessagesRequest) Save(ctx *SaveContext) map[string]interface{} { +func (obj AnthropicMessagesRequest) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["model"] = obj.Model if obj.Messages != nil { @@ -183,11 +186,7 @@ func (obj *AnthropicMessagesRequest) ToJSON() (string, error) { func (obj *AnthropicMessagesRequest) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates AnthropicMessagesRequest from JSON string diff --git a/runtime/go/prompty/model/anthropic_messages_request_test.go b/runtime/go/prompty/model/anthropic_messages_request_test.go index c2ac945d..b53c142b 100644 --- a/runtime/go/prompty/model/anthropic_messages_request_test.go +++ b/runtime/go/prompty/model/anthropic_messages_request_test.go @@ -55,6 +55,12 @@ func TestAnthropicMessagesRequestLoadJSON(t *testing.T) { if instance.TopK == nil || *instance.TopK != 40 { t.Errorf(`Expected TopK to be 40, got %v`, instance.TopK) } + if len(instance.StopSequences) != 1 { + t.Fatalf("Expected StopSequences length to be 1, got %d", len(instance.StopSequences)) + } + if instance.StopSequences[0] != "\n\nHuman:" { + t.Errorf(`Expected StopSequences[0] to be "\n\nHuman:", got %v`, instance.StopSequences[0]) + } } // TestAnthropicMessagesRequestLoadYAML tests loading AnthropicMessagesRequest from YAML @@ -98,6 +104,102 @@ stop_sequences: if instance.TopK == nil || *instance.TopK != 40 { t.Errorf(`Expected TopK to be 40, got %v`, instance.TopK) } + if len(instance.StopSequences) != 1 { + t.Fatalf("Expected StopSequences length to be 1, got %d", len(instance.StopSequences)) + } + if instance.StopSequences[0] != "\n\nHuman:" { + t.Errorf(`Expected StopSequences[0] to be "\n\nHuman:", got %v`, instance.StopSequences[0]) + } +} + +// TestAnthropicMessagesRequestFromJSON tests loading AnthropicMessagesRequest through the generated JSON helper +func TestAnthropicMessagesRequestFromJSON(t *testing.T) { + jsonData := ` +{ + "model": "claude-sonnet-4-20250514", + "max_tokens": 4096, + "system": "You are a helpful assistant.", + "temperature": 0.7, + "top_p": 0.9, + "top_k": 40, + "stop_sequences": [ + "\n\nHuman:" + ] +} +` + + instance, err := prompty.AnthropicMessagesRequestFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load AnthropicMessagesRequest from JSON helper: %v", err) + } + if instance.Model != "claude-sonnet-4-20250514" { + t.Errorf(`Expected Model to be "claude-sonnet-4-20250514", got %v`, instance.Model) + } + if instance.MaxTokens != 4096 { + t.Errorf(`Expected MaxTokens to be 4096, got %v`, instance.MaxTokens) + } + if instance.System == nil || *instance.System != "You are a helpful assistant." { + t.Errorf(`Expected System to be "You are a helpful assistant.", got %v`, instance.System) + } + if instance.Temperature == nil || *instance.Temperature != 0.7 { + t.Errorf(`Expected Temperature to be 0.7, got %v`, instance.Temperature) + } + if instance.TopP == nil || *instance.TopP != 0.9 { + t.Errorf(`Expected TopP to be 0.9, got %v`, instance.TopP) + } + if instance.TopK == nil || *instance.TopK != 40 { + t.Errorf(`Expected TopK to be 40, got %v`, instance.TopK) + } + if len(instance.StopSequences) != 1 { + t.Fatalf("Expected StopSequences length to be 1, got %d", len(instance.StopSequences)) + } + if instance.StopSequences[0] != "\n\nHuman:" { + t.Errorf(`Expected StopSequences[0] to be "\n\nHuman:", got %v`, instance.StopSequences[0]) + } +} + +// TestAnthropicMessagesRequestFromYAML tests loading AnthropicMessagesRequest through the generated YAML helper +func TestAnthropicMessagesRequestFromYAML(t *testing.T) { + yamlData := ` +model: claude-sonnet-4-20250514 +max_tokens: 4096 +system: You are a helpful assistant. +temperature: 0.7 +top_p: 0.9 +top_k: 40 +stop_sequences: + - "\n\nHuman:" + +` + + instance, err := prompty.AnthropicMessagesRequestFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load AnthropicMessagesRequest from YAML helper: %v", err) + } + if instance.Model != "claude-sonnet-4-20250514" { + t.Errorf(`Expected Model to be "claude-sonnet-4-20250514", got %v`, instance.Model) + } + if instance.MaxTokens != 4096 { + t.Errorf(`Expected MaxTokens to be 4096, got %v`, instance.MaxTokens) + } + if instance.System == nil || *instance.System != "You are a helpful assistant." { + t.Errorf(`Expected System to be "You are a helpful assistant.", got %v`, instance.System) + } + if instance.Temperature == nil || *instance.Temperature != 0.7 { + t.Errorf(`Expected Temperature to be 0.7, got %v`, instance.Temperature) + } + if instance.TopP == nil || *instance.TopP != 0.9 { + t.Errorf(`Expected TopP to be 0.9, got %v`, instance.TopP) + } + if instance.TopK == nil || *instance.TopK != 40 { + t.Errorf(`Expected TopK to be 40, got %v`, instance.TopK) + } + if len(instance.StopSequences) != 1 { + t.Fatalf("Expected StopSequences length to be 1, got %d", len(instance.StopSequences)) + } + if instance.StopSequences[0] != "\n\nHuman:" { + t.Errorf(`Expected StopSequences[0] to be "\n\nHuman:", got %v`, instance.StopSequences[0]) + } } // TestAnthropicMessagesRequestRoundtrip tests load -> save -> load produces equivalent data @@ -150,6 +252,12 @@ func TestAnthropicMessagesRequestRoundtrip(t *testing.T) { if reloaded.TopK == nil || *reloaded.TopK != 40 { t.Errorf(`Expected TopK to be 40, got %v`, reloaded.TopK) } + if len(reloaded.StopSequences) != 1 { + t.Fatalf("Expected StopSequences length to be 1, got %d", len(reloaded.StopSequences)) + } + if reloaded.StopSequences[0] != "\n\nHuman:" { + t.Errorf(`Expected StopSequences[0] to be "\n\nHuman:", got %v`, reloaded.StopSequences[0]) + } } // TestAnthropicMessagesRequestToJSON tests that ToJSON produces valid JSON @@ -186,6 +294,35 @@ func TestAnthropicMessagesRequestToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadAnthropicMessagesRequest(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Model != "claude-sonnet-4-20250514" { + t.Errorf(`Expected Model to be "claude-sonnet-4-20250514", got %v`, reloaded.Model) + } + if reloaded.MaxTokens != 4096 { + t.Errorf(`Expected MaxTokens to be 4096, got %v`, reloaded.MaxTokens) + } + if reloaded.System == nil || *reloaded.System != "You are a helpful assistant." { + t.Errorf(`Expected System to be "You are a helpful assistant.", got %v`, reloaded.System) + } + if reloaded.Temperature == nil || *reloaded.Temperature != 0.7 { + t.Errorf(`Expected Temperature to be 0.7, got %v`, reloaded.Temperature) + } + if reloaded.TopP == nil || *reloaded.TopP != 0.9 { + t.Errorf(`Expected TopP to be 0.9, got %v`, reloaded.TopP) + } + if reloaded.TopK == nil || *reloaded.TopK != 40 { + t.Errorf(`Expected TopK to be 40, got %v`, reloaded.TopK) + } + if len(reloaded.StopSequences) != 1 { + t.Fatalf("Expected StopSequences length to be 1, got %d", len(reloaded.StopSequences)) + } + if reloaded.StopSequences[0] != "\n\nHuman:" { + t.Errorf(`Expected StopSequences[0] to be "\n\nHuman:", got %v`, reloaded.StopSequences[0]) + } } // TestAnthropicMessagesRequestToYAML tests that ToYAML produces valid YAML @@ -222,4 +359,40 @@ func TestAnthropicMessagesRequestToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadAnthropicMessagesRequest(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Model != "claude-sonnet-4-20250514" { + t.Errorf(`Expected Model to be "claude-sonnet-4-20250514", got %v`, reloaded.Model) + } + if reloaded.MaxTokens != 4096 { + t.Errorf(`Expected MaxTokens to be 4096, got %v`, reloaded.MaxTokens) + } + if reloaded.System == nil || *reloaded.System != "You are a helpful assistant." { + t.Errorf(`Expected System to be "You are a helpful assistant.", got %v`, reloaded.System) + } + if reloaded.Temperature == nil || *reloaded.Temperature != 0.7 { + t.Errorf(`Expected Temperature to be 0.7, got %v`, reloaded.Temperature) + } + if reloaded.TopP == nil || *reloaded.TopP != 0.9 { + t.Errorf(`Expected TopP to be 0.9, got %v`, reloaded.TopP) + } + if reloaded.TopK == nil || *reloaded.TopK != 40 { + t.Errorf(`Expected TopK to be 40, got %v`, reloaded.TopK) + } + if len(reloaded.StopSequences) != 1 { + t.Fatalf("Expected StopSequences length to be 1, got %d", len(reloaded.StopSequences)) + } + if reloaded.StopSequences[0] != "\n\nHuman:" { + t.Errorf(`Expected StopSequences[0] to be "\n\nHuman:", got %v`, reloaded.StopSequences[0]) + } +} + +// TestAnthropicMessagesRequestFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestAnthropicMessagesRequestFromJSONInvalid(t *testing.T) { + if _, err := prompty.AnthropicMessagesRequestFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/anthropic_messages_response.go b/runtime/go/prompty/model/anthropic_messages_response.go index 03aac94b..3666cb9d 100644 --- a/runtime/go/prompty/model/anthropic_messages_response.go +++ b/runtime/go/prompty/model/anthropic_messages_response.go @@ -38,7 +38,8 @@ func LoadAnthropicMessagesResponse(data interface{}, ctx *LoadContext) (Anthropi result.Role = string(val.(string)) } if val, ok := m["content"]; ok && val != nil { - if arr, ok := val.([]interface{}); ok { + switch arr := val.(type) { + case []interface{}: result.Content = arr } } @@ -60,7 +61,7 @@ func LoadAnthropicMessagesResponse(data interface{}, ctx *LoadContext) (Anthropi } // Save serializes AnthropicMessagesResponse to map[string]interface{} -func (obj *AnthropicMessagesResponse) Save(ctx *SaveContext) map[string]interface{} { +func (obj AnthropicMessagesResponse) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["id"] = obj.Id result["type"] = obj.Type @@ -89,11 +90,7 @@ func (obj *AnthropicMessagesResponse) ToJSON() (string, error) { func (obj *AnthropicMessagesResponse) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates AnthropicMessagesResponse from JSON string diff --git a/runtime/go/prompty/model/anthropic_messages_response_test.go b/runtime/go/prompty/model/anthropic_messages_response_test.go index 08f6d66c..8be3d5cf 100644 --- a/runtime/go/prompty/model/anthropic_messages_response_test.go +++ b/runtime/go/prompty/model/anthropic_messages_response_test.go @@ -71,6 +71,55 @@ stop_reason: end_turn } } +// TestAnthropicMessagesResponseFromJSON tests loading AnthropicMessagesResponse through the generated JSON helper +func TestAnthropicMessagesResponseFromJSON(t *testing.T) { + jsonData := ` +{ + "id": "msg_01XFDUDYJgAACzvnptvVoYEL", + "model": "claude-sonnet-4-20250514", + "stop_reason": "end_turn" +} +` + + instance, err := prompty.AnthropicMessagesResponseFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load AnthropicMessagesResponse from JSON helper: %v", err) + } + if instance.Id != "msg_01XFDUDYJgAACzvnptvVoYEL" { + t.Errorf(`Expected Id to be "msg_01XFDUDYJgAACzvnptvVoYEL", got %v`, instance.Id) + } + if instance.Model != "claude-sonnet-4-20250514" { + t.Errorf(`Expected Model to be "claude-sonnet-4-20250514", got %v`, instance.Model) + } + if instance.StopReason != "end_turn" { + t.Errorf(`Expected StopReason to be "end_turn", got %v`, instance.StopReason) + } +} + +// TestAnthropicMessagesResponseFromYAML tests loading AnthropicMessagesResponse through the generated YAML helper +func TestAnthropicMessagesResponseFromYAML(t *testing.T) { + yamlData := ` +id: msg_01XFDUDYJgAACzvnptvVoYEL +model: claude-sonnet-4-20250514 +stop_reason: end_turn + +` + + instance, err := prompty.AnthropicMessagesResponseFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load AnthropicMessagesResponse from YAML helper: %v", err) + } + if instance.Id != "msg_01XFDUDYJgAACzvnptvVoYEL" { + t.Errorf(`Expected Id to be "msg_01XFDUDYJgAACzvnptvVoYEL", got %v`, instance.Id) + } + if instance.Model != "claude-sonnet-4-20250514" { + t.Errorf(`Expected Model to be "claude-sonnet-4-20250514", got %v`, instance.Model) + } + if instance.StopReason != "end_turn" { + t.Errorf(`Expected StopReason to be "end_turn", got %v`, instance.StopReason) + } +} + // TestAnthropicMessagesResponseRoundtrip tests load -> save -> load produces equivalent data func TestAnthropicMessagesResponseRoundtrip(t *testing.T) { jsonData := ` @@ -136,6 +185,20 @@ func TestAnthropicMessagesResponseToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadAnthropicMessagesResponse(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Id != "msg_01XFDUDYJgAACzvnptvVoYEL" { + t.Errorf(`Expected Id to be "msg_01XFDUDYJgAACzvnptvVoYEL", got %v`, reloaded.Id) + } + if reloaded.Model != "claude-sonnet-4-20250514" { + t.Errorf(`Expected Model to be "claude-sonnet-4-20250514", got %v`, reloaded.Model) + } + if reloaded.StopReason != "end_turn" { + t.Errorf(`Expected StopReason to be "end_turn", got %v`, reloaded.StopReason) + } } // TestAnthropicMessagesResponseToYAML tests that ToYAML produces valid YAML @@ -166,4 +229,25 @@ func TestAnthropicMessagesResponseToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadAnthropicMessagesResponse(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Id != "msg_01XFDUDYJgAACzvnptvVoYEL" { + t.Errorf(`Expected Id to be "msg_01XFDUDYJgAACzvnptvVoYEL", got %v`, reloaded.Id) + } + if reloaded.Model != "claude-sonnet-4-20250514" { + t.Errorf(`Expected Model to be "claude-sonnet-4-20250514", got %v`, reloaded.Model) + } + if reloaded.StopReason != "end_turn" { + t.Errorf(`Expected StopReason to be "end_turn", got %v`, reloaded.StopReason) + } +} + +// TestAnthropicMessagesResponseFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestAnthropicMessagesResponseFromJSONInvalid(t *testing.T) { + if _, err := prompty.AnthropicMessagesResponseFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/anthropic_text_block.go b/runtime/go/prompty/model/anthropic_text_block.go index cfd40fef..f2d782e2 100644 --- a/runtime/go/prompty/model/anthropic_text_block.go +++ b/runtime/go/prompty/model/anthropic_text_block.go @@ -35,7 +35,7 @@ func LoadAnthropicTextBlock(data interface{}, ctx *LoadContext) (AnthropicTextBl } // Save serializes AnthropicTextBlock to map[string]interface{} -func (obj *AnthropicTextBlock) Save(ctx *SaveContext) map[string]interface{} { +func (obj AnthropicTextBlock) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["type"] = obj.Type result["text"] = obj.Text @@ -58,11 +58,7 @@ func (obj *AnthropicTextBlock) ToJSON() (string, error) { func (obj *AnthropicTextBlock) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates AnthropicTextBlock from JSON string diff --git a/runtime/go/prompty/model/anthropic_text_block_test.go b/runtime/go/prompty/model/anthropic_text_block_test.go index 857054e7..71410762 100644 --- a/runtime/go/prompty/model/anthropic_text_block_test.go +++ b/runtime/go/prompty/model/anthropic_text_block_test.go @@ -55,6 +55,39 @@ text: Hello, how can I help? } } +// TestAnthropicTextBlockFromJSON tests loading AnthropicTextBlock through the generated JSON helper +func TestAnthropicTextBlockFromJSON(t *testing.T) { + jsonData := ` +{ + "text": "Hello, how can I help?" +} +` + + instance, err := prompty.AnthropicTextBlockFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load AnthropicTextBlock from JSON helper: %v", err) + } + if instance.Text != "Hello, how can I help?" { + t.Errorf(`Expected Text to be "Hello, how can I help?", got %v`, instance.Text) + } +} + +// TestAnthropicTextBlockFromYAML tests loading AnthropicTextBlock through the generated YAML helper +func TestAnthropicTextBlockFromYAML(t *testing.T) { + yamlData := ` +text: Hello, how can I help? + +` + + instance, err := prompty.AnthropicTextBlockFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load AnthropicTextBlock from YAML helper: %v", err) + } + if instance.Text != "Hello, how can I help?" { + t.Errorf(`Expected Text to be "Hello, how can I help?", got %v`, instance.Text) + } +} + // TestAnthropicTextBlockRoundtrip tests load -> save -> load produces equivalent data func TestAnthropicTextBlockRoundtrip(t *testing.T) { jsonData := ` @@ -110,6 +143,14 @@ func TestAnthropicTextBlockToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadAnthropicTextBlock(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Text != "Hello, how can I help?" { + t.Errorf(`Expected Text to be "Hello, how can I help?", got %v`, reloaded.Text) + } } // TestAnthropicTextBlockToYAML tests that ToYAML produces valid YAML @@ -138,4 +179,19 @@ func TestAnthropicTextBlockToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadAnthropicTextBlock(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Text != "Hello, how can I help?" { + t.Errorf(`Expected Text to be "Hello, how can I help?", got %v`, reloaded.Text) + } +} + +// TestAnthropicTextBlockFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestAnthropicTextBlockFromJSONInvalid(t *testing.T) { + if _, err := prompty.AnthropicTextBlockFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/anthropic_tool_definition.go b/runtime/go/prompty/model/anthropic_tool_definition.go index f75e7939..eebdc3e1 100644 --- a/runtime/go/prompty/model/anthropic_tool_definition.go +++ b/runtime/go/prompty/model/anthropic_tool_definition.go @@ -44,7 +44,7 @@ func LoadAnthropicToolDefinition(data interface{}, ctx *LoadContext) (AnthropicT } // Save serializes AnthropicToolDefinition to map[string]interface{} -func (obj *AnthropicToolDefinition) Save(ctx *SaveContext) map[string]interface{} { +func (obj AnthropicToolDefinition) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["name"] = obj.Name if obj.Description != nil { @@ -70,11 +70,7 @@ func (obj *AnthropicToolDefinition) ToJSON() (string, error) { func (obj *AnthropicToolDefinition) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates AnthropicToolDefinition from JSON string diff --git a/runtime/go/prompty/model/anthropic_tool_definition_test.go b/runtime/go/prompty/model/anthropic_tool_definition_test.go index cd293aec..239753d9 100644 --- a/runtime/go/prompty/model/anthropic_tool_definition_test.go +++ b/runtime/go/prompty/model/anthropic_tool_definition_test.go @@ -63,6 +63,47 @@ description: Get the current weather for a city } } +// TestAnthropicToolDefinitionFromJSON tests loading AnthropicToolDefinition through the generated JSON helper +func TestAnthropicToolDefinitionFromJSON(t *testing.T) { + jsonData := ` +{ + "name": "get_weather", + "description": "Get the current weather for a city" +} +` + + instance, err := prompty.AnthropicToolDefinitionFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load AnthropicToolDefinition from JSON helper: %v", err) + } + if instance.Name != "get_weather" { + t.Errorf(`Expected Name to be "get_weather", got %v`, instance.Name) + } + if instance.Description == nil || *instance.Description != "Get the current weather for a city" { + t.Errorf(`Expected Description to be "Get the current weather for a city", got %v`, instance.Description) + } +} + +// TestAnthropicToolDefinitionFromYAML tests loading AnthropicToolDefinition through the generated YAML helper +func TestAnthropicToolDefinitionFromYAML(t *testing.T) { + yamlData := ` +name: get_weather +description: Get the current weather for a city + +` + + instance, err := prompty.AnthropicToolDefinitionFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load AnthropicToolDefinition from YAML helper: %v", err) + } + if instance.Name != "get_weather" { + t.Errorf(`Expected Name to be "get_weather", got %v`, instance.Name) + } + if instance.Description == nil || *instance.Description != "Get the current weather for a city" { + t.Errorf(`Expected Description to be "Get the current weather for a city", got %v`, instance.Description) + } +} + // TestAnthropicToolDefinitionRoundtrip tests load -> save -> load produces equivalent data func TestAnthropicToolDefinitionRoundtrip(t *testing.T) { jsonData := ` @@ -123,6 +164,17 @@ func TestAnthropicToolDefinitionToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadAnthropicToolDefinition(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Name != "get_weather" { + t.Errorf(`Expected Name to be "get_weather", got %v`, reloaded.Name) + } + if reloaded.Description == nil || *reloaded.Description != "Get the current weather for a city" { + t.Errorf(`Expected Description to be "Get the current weather for a city", got %v`, reloaded.Description) + } } // TestAnthropicToolDefinitionToYAML tests that ToYAML produces valid YAML @@ -152,4 +204,22 @@ func TestAnthropicToolDefinitionToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadAnthropicToolDefinition(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Name != "get_weather" { + t.Errorf(`Expected Name to be "get_weather", got %v`, reloaded.Name) + } + if reloaded.Description == nil || *reloaded.Description != "Get the current weather for a city" { + t.Errorf(`Expected Description to be "Get the current weather for a city", got %v`, reloaded.Description) + } +} + +// TestAnthropicToolDefinitionFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestAnthropicToolDefinitionFromJSONInvalid(t *testing.T) { + if _, err := prompty.AnthropicToolDefinitionFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/anthropic_tool_result_block.go b/runtime/go/prompty/model/anthropic_tool_result_block.go index 63f088ae..bb7ecfce 100644 --- a/runtime/go/prompty/model/anthropic_tool_result_block.go +++ b/runtime/go/prompty/model/anthropic_tool_result_block.go @@ -39,7 +39,7 @@ func LoadAnthropicToolResultBlock(data interface{}, ctx *LoadContext) (Anthropic } // Save serializes AnthropicToolResultBlock to map[string]interface{} -func (obj *AnthropicToolResultBlock) Save(ctx *SaveContext) map[string]interface{} { +func (obj AnthropicToolResultBlock) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["type"] = obj.Type result["tool_use_id"] = obj.ToolUseId @@ -63,11 +63,7 @@ func (obj *AnthropicToolResultBlock) ToJSON() (string, error) { func (obj *AnthropicToolResultBlock) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates AnthropicToolResultBlock from JSON string diff --git a/runtime/go/prompty/model/anthropic_tool_result_block_test.go b/runtime/go/prompty/model/anthropic_tool_result_block_test.go index 92f699ee..ca0769dc 100644 --- a/runtime/go/prompty/model/anthropic_tool_result_block_test.go +++ b/runtime/go/prompty/model/anthropic_tool_result_block_test.go @@ -63,6 +63,47 @@ content: 72°F and sunny in Paris } } +// TestAnthropicToolResultBlockFromJSON tests loading AnthropicToolResultBlock through the generated JSON helper +func TestAnthropicToolResultBlockFromJSON(t *testing.T) { + jsonData := ` +{ + "tool_use_id": "toolu_01A09q90qw90lq917835lq9", + "content": "72°F and sunny in Paris" +} +` + + instance, err := prompty.AnthropicToolResultBlockFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load AnthropicToolResultBlock from JSON helper: %v", err) + } + if instance.ToolUseId != "toolu_01A09q90qw90lq917835lq9" { + t.Errorf(`Expected ToolUseId to be "toolu_01A09q90qw90lq917835lq9", got %v`, instance.ToolUseId) + } + if instance.Content != "72°F and sunny in Paris" { + t.Errorf(`Expected Content to be "72°F and sunny in Paris", got %v`, instance.Content) + } +} + +// TestAnthropicToolResultBlockFromYAML tests loading AnthropicToolResultBlock through the generated YAML helper +func TestAnthropicToolResultBlockFromYAML(t *testing.T) { + yamlData := ` +tool_use_id: toolu_01A09q90qw90lq917835lq9 +content: 72°F and sunny in Paris + +` + + instance, err := prompty.AnthropicToolResultBlockFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load AnthropicToolResultBlock from YAML helper: %v", err) + } + if instance.ToolUseId != "toolu_01A09q90qw90lq917835lq9" { + t.Errorf(`Expected ToolUseId to be "toolu_01A09q90qw90lq917835lq9", got %v`, instance.ToolUseId) + } + if instance.Content != "72°F and sunny in Paris" { + t.Errorf(`Expected Content to be "72°F and sunny in Paris", got %v`, instance.Content) + } +} + // TestAnthropicToolResultBlockRoundtrip tests load -> save -> load produces equivalent data func TestAnthropicToolResultBlockRoundtrip(t *testing.T) { jsonData := ` @@ -123,6 +164,17 @@ func TestAnthropicToolResultBlockToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadAnthropicToolResultBlock(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.ToolUseId != "toolu_01A09q90qw90lq917835lq9" { + t.Errorf(`Expected ToolUseId to be "toolu_01A09q90qw90lq917835lq9", got %v`, reloaded.ToolUseId) + } + if reloaded.Content != "72°F and sunny in Paris" { + t.Errorf(`Expected Content to be "72°F and sunny in Paris", got %v`, reloaded.Content) + } } // TestAnthropicToolResultBlockToYAML tests that ToYAML produces valid YAML @@ -152,4 +204,22 @@ func TestAnthropicToolResultBlockToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadAnthropicToolResultBlock(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.ToolUseId != "toolu_01A09q90qw90lq917835lq9" { + t.Errorf(`Expected ToolUseId to be "toolu_01A09q90qw90lq917835lq9", got %v`, reloaded.ToolUseId) + } + if reloaded.Content != "72°F and sunny in Paris" { + t.Errorf(`Expected Content to be "72°F and sunny in Paris", got %v`, reloaded.Content) + } +} + +// TestAnthropicToolResultBlockFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestAnthropicToolResultBlockFromJSONInvalid(t *testing.T) { + if _, err := prompty.AnthropicToolResultBlockFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/anthropic_tool_use_block.go b/runtime/go/prompty/model/anthropic_tool_use_block.go index 63852350..35e8fdc6 100644 --- a/runtime/go/prompty/model/anthropic_tool_use_block.go +++ b/runtime/go/prompty/model/anthropic_tool_use_block.go @@ -46,7 +46,7 @@ func LoadAnthropicToolUseBlock(data interface{}, ctx *LoadContext) (AnthropicToo } // Save serializes AnthropicToolUseBlock to map[string]interface{} -func (obj *AnthropicToolUseBlock) Save(ctx *SaveContext) map[string]interface{} { +func (obj AnthropicToolUseBlock) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["type"] = obj.Type result["id"] = obj.Id @@ -71,11 +71,7 @@ func (obj *AnthropicToolUseBlock) ToJSON() (string, error) { func (obj *AnthropicToolUseBlock) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates AnthropicToolUseBlock from JSON string diff --git a/runtime/go/prompty/model/anthropic_tool_use_block_test.go b/runtime/go/prompty/model/anthropic_tool_use_block_test.go index 88f049a5..bd94d4a0 100644 --- a/runtime/go/prompty/model/anthropic_tool_use_block_test.go +++ b/runtime/go/prompty/model/anthropic_tool_use_block_test.go @@ -39,6 +39,12 @@ func TestAnthropicToolUseBlockLoadJSON(t *testing.T) { if instance.Name != "get_weather" { t.Errorf(`Expected Name to be "get_weather", got %v`, instance.Name) } + if instance.Input == nil { + t.Fatalf("Expected Input to be populated") + } + if got := instance.Input["city"]; got != "Paris" { + t.Errorf(`Expected Input["city"] to be "Paris", got %v`, got) + } } // TestAnthropicToolUseBlockLoadYAML tests loading AnthropicToolUseBlock from YAML @@ -66,6 +72,70 @@ input: if instance.Name != "get_weather" { t.Errorf(`Expected Name to be "get_weather", got %v`, instance.Name) } + if instance.Input == nil { + t.Fatalf("Expected Input to be populated") + } + if got := instance.Input["city"]; got != "Paris" { + t.Errorf(`Expected Input["city"] to be "Paris", got %v`, got) + } +} + +// TestAnthropicToolUseBlockFromJSON tests loading AnthropicToolUseBlock through the generated JSON helper +func TestAnthropicToolUseBlockFromJSON(t *testing.T) { + jsonData := ` +{ + "id": "toolu_01A09q90qw90lq917835lq9", + "name": "get_weather", + "input": { + "city": "Paris" + } +} +` + + instance, err := prompty.AnthropicToolUseBlockFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load AnthropicToolUseBlock from JSON helper: %v", err) + } + if instance.Id != "toolu_01A09q90qw90lq917835lq9" { + t.Errorf(`Expected Id to be "toolu_01A09q90qw90lq917835lq9", got %v`, instance.Id) + } + if instance.Name != "get_weather" { + t.Errorf(`Expected Name to be "get_weather", got %v`, instance.Name) + } + if instance.Input == nil { + t.Fatalf("Expected Input to be populated") + } + if got := instance.Input["city"]; got != "Paris" { + t.Errorf(`Expected Input["city"] to be "Paris", got %v`, got) + } +} + +// TestAnthropicToolUseBlockFromYAML tests loading AnthropicToolUseBlock through the generated YAML helper +func TestAnthropicToolUseBlockFromYAML(t *testing.T) { + yamlData := ` +id: toolu_01A09q90qw90lq917835lq9 +name: get_weather +input: + city: Paris + +` + + instance, err := prompty.AnthropicToolUseBlockFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load AnthropicToolUseBlock from YAML helper: %v", err) + } + if instance.Id != "toolu_01A09q90qw90lq917835lq9" { + t.Errorf(`Expected Id to be "toolu_01A09q90qw90lq917835lq9", got %v`, instance.Id) + } + if instance.Name != "get_weather" { + t.Errorf(`Expected Name to be "get_weather", got %v`, instance.Name) + } + if instance.Input == nil { + t.Fatalf("Expected Input to be populated") + } + if got := instance.Input["city"]; got != "Paris" { + t.Errorf(`Expected Input["city"] to be "Paris", got %v`, got) + } } // TestAnthropicToolUseBlockRoundtrip tests load -> save -> load produces equivalent data @@ -102,6 +172,12 @@ func TestAnthropicToolUseBlockRoundtrip(t *testing.T) { if reloaded.Name != "get_weather" { t.Errorf(`Expected Name to be "get_weather", got %v`, reloaded.Name) } + if reloaded.Input == nil { + t.Fatalf("Expected Input to be populated") + } + if got := reloaded.Input["city"]; got != "Paris" { + t.Errorf(`Expected Input["city"] to be "Paris", got %v`, got) + } } // TestAnthropicToolUseBlockToJSON tests that ToJSON produces valid JSON @@ -134,6 +210,23 @@ func TestAnthropicToolUseBlockToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadAnthropicToolUseBlock(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Id != "toolu_01A09q90qw90lq917835lq9" { + t.Errorf(`Expected Id to be "toolu_01A09q90qw90lq917835lq9", got %v`, reloaded.Id) + } + if reloaded.Name != "get_weather" { + t.Errorf(`Expected Name to be "get_weather", got %v`, reloaded.Name) + } + if reloaded.Input == nil { + t.Fatalf("Expected Input to be populated") + } + if got := reloaded.Input["city"]; got != "Paris" { + t.Errorf(`Expected Input["city"] to be "Paris", got %v`, got) + } } // TestAnthropicToolUseBlockToYAML tests that ToYAML produces valid YAML @@ -166,4 +259,28 @@ func TestAnthropicToolUseBlockToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadAnthropicToolUseBlock(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Id != "toolu_01A09q90qw90lq917835lq9" { + t.Errorf(`Expected Id to be "toolu_01A09q90qw90lq917835lq9", got %v`, reloaded.Id) + } + if reloaded.Name != "get_weather" { + t.Errorf(`Expected Name to be "get_weather", got %v`, reloaded.Name) + } + if reloaded.Input == nil { + t.Fatalf("Expected Input to be populated") + } + if got := reloaded.Input["city"]; got != "Paris" { + t.Errorf(`Expected Input["city"] to be "Paris", got %v`, got) + } +} + +// TestAnthropicToolUseBlockFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestAnthropicToolUseBlockFromJSONInvalid(t *testing.T) { + if _, err := prompty.AnthropicToolUseBlockFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/anthropic_usage.go b/runtime/go/prompty/model/anthropic_usage.go index a03e3bcd..1a95ac2e 100644 --- a/runtime/go/prompty/model/anthropic_usage.go +++ b/runtime/go/prompty/model/anthropic_usage.go @@ -57,7 +57,7 @@ func LoadAnthropicUsage(data interface{}, ctx *LoadContext) (AnthropicUsage, err } // Save serializes AnthropicUsage to map[string]interface{} -func (obj *AnthropicUsage) Save(ctx *SaveContext) map[string]interface{} { +func (obj AnthropicUsage) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["input_tokens"] = obj.InputTokens result["output_tokens"] = obj.OutputTokens @@ -80,11 +80,7 @@ func (obj *AnthropicUsage) ToJSON() (string, error) { func (obj *AnthropicUsage) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates AnthropicUsage from JSON string diff --git a/runtime/go/prompty/model/anthropic_usage_test.go b/runtime/go/prompty/model/anthropic_usage_test.go index c6c31a6d..e522865a 100644 --- a/runtime/go/prompty/model/anthropic_usage_test.go +++ b/runtime/go/prompty/model/anthropic_usage_test.go @@ -63,6 +63,47 @@ output_tokens: 42 } } +// TestAnthropicUsageFromJSON tests loading AnthropicUsage through the generated JSON helper +func TestAnthropicUsageFromJSON(t *testing.T) { + jsonData := ` +{ + "input_tokens": 150, + "output_tokens": 42 +} +` + + instance, err := prompty.AnthropicUsageFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load AnthropicUsage from JSON helper: %v", err) + } + if instance.InputTokens != 150 { + t.Errorf(`Expected InputTokens to be 150, got %v`, instance.InputTokens) + } + if instance.OutputTokens != 42 { + t.Errorf(`Expected OutputTokens to be 42, got %v`, instance.OutputTokens) + } +} + +// TestAnthropicUsageFromYAML tests loading AnthropicUsage through the generated YAML helper +func TestAnthropicUsageFromYAML(t *testing.T) { + yamlData := ` +input_tokens: 150 +output_tokens: 42 + +` + + instance, err := prompty.AnthropicUsageFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load AnthropicUsage from YAML helper: %v", err) + } + if instance.InputTokens != 150 { + t.Errorf(`Expected InputTokens to be 150, got %v`, instance.InputTokens) + } + if instance.OutputTokens != 42 { + t.Errorf(`Expected OutputTokens to be 42, got %v`, instance.OutputTokens) + } +} + // TestAnthropicUsageRoundtrip tests load -> save -> load produces equivalent data func TestAnthropicUsageRoundtrip(t *testing.T) { jsonData := ` @@ -123,6 +164,17 @@ func TestAnthropicUsageToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadAnthropicUsage(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.InputTokens != 150 { + t.Errorf(`Expected InputTokens to be 150, got %v`, reloaded.InputTokens) + } + if reloaded.OutputTokens != 42 { + t.Errorf(`Expected OutputTokens to be 42, got %v`, reloaded.OutputTokens) + } } // TestAnthropicUsageToYAML tests that ToYAML produces valid YAML @@ -152,4 +204,22 @@ func TestAnthropicUsageToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadAnthropicUsage(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.InputTokens != 150 { + t.Errorf(`Expected InputTokens to be 150, got %v`, reloaded.InputTokens) + } + if reloaded.OutputTokens != 42 { + t.Errorf(`Expected OutputTokens to be 42, got %v`, reloaded.OutputTokens) + } +} + +// TestAnthropicUsageFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestAnthropicUsageFromJSONInvalid(t *testing.T) { + if _, err := prompty.AnthropicUsageFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/anthropic_wire_message.go b/runtime/go/prompty/model/anthropic_wire_message.go index 4b988eac..60c23b37 100644 --- a/runtime/go/prompty/model/anthropic_wire_message.go +++ b/runtime/go/prompty/model/anthropic_wire_message.go @@ -29,7 +29,8 @@ func LoadAnthropicWireMessage(data interface{}, ctx *LoadContext) (AnthropicWire result.Role = string(val.(string)) } if val, ok := m["content"]; ok && val != nil { - if arr, ok := val.([]interface{}); ok { + switch arr := val.(type) { + case []interface{}: result.Content = arr } } @@ -39,7 +40,7 @@ func LoadAnthropicWireMessage(data interface{}, ctx *LoadContext) (AnthropicWire } // Save serializes AnthropicWireMessage to map[string]interface{} -func (obj *AnthropicWireMessage) Save(ctx *SaveContext) map[string]interface{} { +func (obj AnthropicWireMessage) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["role"] = obj.Role result["content"] = obj.Content @@ -62,11 +63,7 @@ func (obj *AnthropicWireMessage) ToJSON() (string, error) { func (obj *AnthropicWireMessage) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates AnthropicWireMessage from JSON string diff --git a/runtime/go/prompty/model/anthropic_wire_message_test.go b/runtime/go/prompty/model/anthropic_wire_message_test.go index 6facf18a..ed29e634 100644 --- a/runtime/go/prompty/model/anthropic_wire_message_test.go +++ b/runtime/go/prompty/model/anthropic_wire_message_test.go @@ -55,6 +55,39 @@ role: user } } +// TestAnthropicWireMessageFromJSON tests loading AnthropicWireMessage through the generated JSON helper +func TestAnthropicWireMessageFromJSON(t *testing.T) { + jsonData := ` +{ + "role": "user" +} +` + + instance, err := prompty.AnthropicWireMessageFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load AnthropicWireMessage from JSON helper: %v", err) + } + if instance.Role != "user" { + t.Errorf(`Expected Role to be "user", got %v`, instance.Role) + } +} + +// TestAnthropicWireMessageFromYAML tests loading AnthropicWireMessage through the generated YAML helper +func TestAnthropicWireMessageFromYAML(t *testing.T) { + yamlData := ` +role: user + +` + + instance, err := prompty.AnthropicWireMessageFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load AnthropicWireMessage from YAML helper: %v", err) + } + if instance.Role != "user" { + t.Errorf(`Expected Role to be "user", got %v`, instance.Role) + } +} + // TestAnthropicWireMessageRoundtrip tests load -> save -> load produces equivalent data func TestAnthropicWireMessageRoundtrip(t *testing.T) { jsonData := ` @@ -110,6 +143,14 @@ func TestAnthropicWireMessageToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadAnthropicWireMessage(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Role != "user" { + t.Errorf(`Expected Role to be "user", got %v`, reloaded.Role) + } } // TestAnthropicWireMessageToYAML tests that ToYAML produces valid YAML @@ -138,4 +179,19 @@ func TestAnthropicWireMessageToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadAnthropicWireMessage(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Role != "user" { + t.Errorf(`Expected Role to be "user", got %v`, reloaded.Role) + } +} + +// TestAnthropicWireMessageFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestAnthropicWireMessageFromJSONInvalid(t *testing.T) { + if _, err := prompty.AnthropicWireMessageFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/api_key_connection_test.go b/runtime/go/prompty/model/api_key_connection_test.go index fdf030a7..7dad4655 100644 --- a/runtime/go/prompty/model/api_key_connection_test.go +++ b/runtime/go/prompty/model/api_key_connection_test.go @@ -71,6 +71,55 @@ apiKey: your-api-key } } +// TestApiKeyConnectionFromJSON tests loading ApiKeyConnection through the generated JSON helper +func TestApiKeyConnectionFromJSON(t *testing.T) { + jsonData := ` +{ + "kind": "key", + "endpoint": "https://{your-custom-endpoint}.openai.azure.com/", + "apiKey": "your-api-key" +} +` + + instance, err := prompty.ApiKeyConnectionFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load ApiKeyConnection from JSON helper: %v", err) + } + if instance.Kind != "key" { + t.Errorf(`Expected Kind to be "key", got %v`, instance.Kind) + } + if instance.Endpoint != "https://{your-custom-endpoint}.openai.azure.com/" { + t.Errorf(`Expected Endpoint to be "https://{your-custom-endpoint}.openai.azure.com/", got %v`, instance.Endpoint) + } + if instance.ApiKey != "your-api-key" { + t.Errorf(`Expected ApiKey to be "your-api-key", got %v`, instance.ApiKey) + } +} + +// TestApiKeyConnectionFromYAML tests loading ApiKeyConnection through the generated YAML helper +func TestApiKeyConnectionFromYAML(t *testing.T) { + yamlData := ` +kind: key +endpoint: "https://{your-custom-endpoint}.openai.azure.com/" +apiKey: your-api-key + +` + + instance, err := prompty.ApiKeyConnectionFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load ApiKeyConnection from YAML helper: %v", err) + } + if instance.Kind != "key" { + t.Errorf(`Expected Kind to be "key", got %v`, instance.Kind) + } + if instance.Endpoint != "https://{your-custom-endpoint}.openai.azure.com/" { + t.Errorf(`Expected Endpoint to be "https://{your-custom-endpoint}.openai.azure.com/", got %v`, instance.Endpoint) + } + if instance.ApiKey != "your-api-key" { + t.Errorf(`Expected ApiKey to be "your-api-key", got %v`, instance.ApiKey) + } +} + // TestApiKeyConnectionRoundtrip tests load -> save -> load produces equivalent data func TestApiKeyConnectionRoundtrip(t *testing.T) { jsonData := ` @@ -136,6 +185,20 @@ func TestApiKeyConnectionToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadApiKeyConnection(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Kind != "key" { + t.Errorf(`Expected Kind to be "key", got %v`, reloaded.Kind) + } + if reloaded.Endpoint != "https://{your-custom-endpoint}.openai.azure.com/" { + t.Errorf(`Expected Endpoint to be "https://{your-custom-endpoint}.openai.azure.com/", got %v`, reloaded.Endpoint) + } + if reloaded.ApiKey != "your-api-key" { + t.Errorf(`Expected ApiKey to be "your-api-key", got %v`, reloaded.ApiKey) + } } // TestApiKeyConnectionToYAML tests that ToYAML produces valid YAML @@ -166,4 +229,25 @@ func TestApiKeyConnectionToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadApiKeyConnection(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Kind != "key" { + t.Errorf(`Expected Kind to be "key", got %v`, reloaded.Kind) + } + if reloaded.Endpoint != "https://{your-custom-endpoint}.openai.azure.com/" { + t.Errorf(`Expected Endpoint to be "https://{your-custom-endpoint}.openai.azure.com/", got %v`, reloaded.Endpoint) + } + if reloaded.ApiKey != "your-api-key" { + t.Errorf(`Expected ApiKey to be "your-api-key", got %v`, reloaded.ApiKey) + } +} + +// TestApiKeyConnectionFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestApiKeyConnectionFromJSONInvalid(t *testing.T) { + if _, err := prompty.ApiKeyConnectionFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/array_property_test.go b/runtime/go/prompty/model/array_property_test.go index 5438638a..2373f3fa 100644 --- a/runtime/go/prompty/model/array_property_test.go +++ b/runtime/go/prompty/model/array_property_test.go @@ -54,6 +54,38 @@ items: _ = instance // No scalar properties to validate } +// TestArrayPropertyFromJSON tests loading ArrayProperty through the generated JSON helper +func TestArrayPropertyFromJSON(t *testing.T) { + jsonData := ` +{ + "items": { + "kind": "string" + } +} +` + + instance, err := prompty.ArrayPropertyFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load ArrayProperty from JSON helper: %v", err) + } + _ = instance // No scalar properties to validate +} + +// TestArrayPropertyFromYAML tests loading ArrayProperty through the generated YAML helper +func TestArrayPropertyFromYAML(t *testing.T) { + yamlData := ` +items: + kind: string + +` + + instance, err := prompty.ArrayPropertyFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load ArrayProperty from YAML helper: %v", err) + } + _ = instance // No scalar properties to validate +} + // TestArrayPropertyRoundtrip tests load -> save -> load produces equivalent data func TestArrayPropertyRoundtrip(t *testing.T) { jsonData := ` @@ -111,6 +143,12 @@ func TestArrayPropertyToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadArrayProperty(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + _ = reloaded // No scalar properties to validate } // TestArrayPropertyToYAML tests that ToYAML produces valid YAML @@ -141,4 +179,17 @@ func TestArrayPropertyToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadArrayProperty(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + _ = reloaded // No scalar properties to validate +} + +// TestArrayPropertyFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestArrayPropertyFromJSONInvalid(t *testing.T) { + if _, err := prompty.ArrayPropertyFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/audio_part_test.go b/runtime/go/prompty/model/audio_part_test.go index 85f74fbd..6d8c43ba 100644 --- a/runtime/go/prompty/model/audio_part_test.go +++ b/runtime/go/prompty/model/audio_part_test.go @@ -63,6 +63,47 @@ mediaType: audio/wav } } +// TestAudioPartFromJSON tests loading AudioPart through the generated JSON helper +func TestAudioPartFromJSON(t *testing.T) { + jsonData := ` +{ + "source": "https://example.com/audio.wav", + "mediaType": "audio/wav" +} +` + + instance, err := prompty.AudioPartFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load AudioPart from JSON helper: %v", err) + } + if instance.Source != "https://example.com/audio.wav" { + t.Errorf(`Expected Source to be "https://example.com/audio.wav", got %v`, instance.Source) + } + if instance.MediaType == nil || *instance.MediaType != "audio/wav" { + t.Errorf(`Expected MediaType to be "audio/wav", got %v`, instance.MediaType) + } +} + +// TestAudioPartFromYAML tests loading AudioPart through the generated YAML helper +func TestAudioPartFromYAML(t *testing.T) { + yamlData := ` +source: "https://example.com/audio.wav" +mediaType: audio/wav + +` + + instance, err := prompty.AudioPartFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load AudioPart from YAML helper: %v", err) + } + if instance.Source != "https://example.com/audio.wav" { + t.Errorf(`Expected Source to be "https://example.com/audio.wav", got %v`, instance.Source) + } + if instance.MediaType == nil || *instance.MediaType != "audio/wav" { + t.Errorf(`Expected MediaType to be "audio/wav", got %v`, instance.MediaType) + } +} + // TestAudioPartRoundtrip tests load -> save -> load produces equivalent data func TestAudioPartRoundtrip(t *testing.T) { jsonData := ` @@ -123,6 +164,17 @@ func TestAudioPartToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadAudioPart(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Source != "https://example.com/audio.wav" { + t.Errorf(`Expected Source to be "https://example.com/audio.wav", got %v`, reloaded.Source) + } + if reloaded.MediaType == nil || *reloaded.MediaType != "audio/wav" { + t.Errorf(`Expected MediaType to be "audio/wav", got %v`, reloaded.MediaType) + } } // TestAudioPartToYAML tests that ToYAML produces valid YAML @@ -152,4 +204,22 @@ func TestAudioPartToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadAudioPart(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Source != "https://example.com/audio.wav" { + t.Errorf(`Expected Source to be "https://example.com/audio.wav", got %v`, reloaded.Source) + } + if reloaded.MediaType == nil || *reloaded.MediaType != "audio/wav" { + t.Errorf(`Expected MediaType to be "audio/wav", got %v`, reloaded.MediaType) + } +} + +// TestAudioPartFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestAudioPartFromJSONInvalid(t *testing.T) { + if _, err := prompty.AudioPartFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/binding.go b/runtime/go/prompty/model/binding.go index bc578f25..41ba4324 100644 --- a/runtime/go/prompty/model/binding.go +++ b/runtime/go/prompty/model/binding.go @@ -42,7 +42,7 @@ func LoadBinding(data interface{}, ctx *LoadContext) (Binding, error) { } // Save serializes Binding to map[string]interface{} -func (obj *Binding) Save(ctx *SaveContext) map[string]interface{} { +func (obj Binding) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["name"] = obj.Name result["input"] = obj.Input @@ -65,11 +65,7 @@ func (obj *Binding) ToJSON() (string, error) { func (obj *Binding) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates Binding from JSON string diff --git a/runtime/go/prompty/model/binding_test.go b/runtime/go/prompty/model/binding_test.go index 87f8362b..c8ab9dce 100644 --- a/runtime/go/prompty/model/binding_test.go +++ b/runtime/go/prompty/model/binding_test.go @@ -63,6 +63,47 @@ input: input-variable } } +// TestBindingFromJSON tests loading Binding through the generated JSON helper +func TestBindingFromJSON(t *testing.T) { + jsonData := ` +{ + "name": "my-tool", + "input": "input-variable" +} +` + + instance, err := prompty.BindingFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load Binding from JSON helper: %v", err) + } + if instance.Name != "my-tool" { + t.Errorf(`Expected Name to be "my-tool", got %v`, instance.Name) + } + if instance.Input != "input-variable" { + t.Errorf(`Expected Input to be "input-variable", got %v`, instance.Input) + } +} + +// TestBindingFromYAML tests loading Binding through the generated YAML helper +func TestBindingFromYAML(t *testing.T) { + yamlData := ` +name: my-tool +input: input-variable + +` + + instance, err := prompty.BindingFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load Binding from YAML helper: %v", err) + } + if instance.Name != "my-tool" { + t.Errorf(`Expected Name to be "my-tool", got %v`, instance.Name) + } + if instance.Input != "input-variable" { + t.Errorf(`Expected Input to be "input-variable", got %v`, instance.Input) + } +} + // TestBindingRoundtrip tests load -> save -> load produces equivalent data func TestBindingRoundtrip(t *testing.T) { jsonData := ` @@ -123,6 +164,17 @@ func TestBindingToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadBinding(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Name != "my-tool" { + t.Errorf(`Expected Name to be "my-tool", got %v`, reloaded.Name) + } + if reloaded.Input != "input-variable" { + t.Errorf(`Expected Input to be "input-variable", got %v`, reloaded.Input) + } } // TestBindingToYAML tests that ToYAML produces valid YAML @@ -152,6 +204,24 @@ func TestBindingToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadBinding(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Name != "my-tool" { + t.Errorf(`Expected Name to be "my-tool", got %v`, reloaded.Name) + } + if reloaded.Input != "input-variable" { + t.Errorf(`Expected Input to be "input-variable", got %v`, reloaded.Input) + } +} + +// TestBindingFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestBindingFromJSONInvalid(t *testing.T) { + if _, err := prompty.BindingFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } // TestBindingFromString tests loading Binding from string diff --git a/runtime/go/prompty/model/checkpoint.go b/runtime/go/prompty/model/checkpoint.go index a7a1f13a..ed9fd0a3 100644 --- a/runtime/go/prompty/model/checkpoint.go +++ b/runtime/go/prompty/model/checkpoint.go @@ -95,7 +95,7 @@ func LoadCheckpoint(data interface{}, ctx *LoadContext) (Checkpoint, error) { } // Save serializes Checkpoint to map[string]interface{} -func (obj *Checkpoint) Save(ctx *SaveContext) map[string]interface{} { +func (obj Checkpoint) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) if obj.Id != nil { result["id"] = *obj.Id @@ -147,11 +147,7 @@ func (obj *Checkpoint) ToJSON() (string, error) { func (obj *Checkpoint) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates Checkpoint from JSON string diff --git a/runtime/go/prompty/model/checkpoint_test.go b/runtime/go/prompty/model/checkpoint_test.go index a1a646a2..528c0b2e 100644 --- a/runtime/go/prompty/model/checkpoint_test.go +++ b/runtime/go/prompty/model/checkpoint_test.go @@ -95,6 +95,79 @@ createdAt: "2026-06-09T20:00:00Z" } } +// TestCheckpointFromJSON tests loading Checkpoint through the generated JSON helper +func TestCheckpointFromJSON(t *testing.T) { + jsonData := ` +{ + "id": "chk_abc123", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "checkpointNumber": 3, + "title": "Added harness contracts", + "createdAt": "2026-06-09T20:00:00Z" +} +` + + instance, err := prompty.CheckpointFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load Checkpoint from JSON helper: %v", err) + } + if instance.Id == nil || *instance.Id != "chk_abc123" { + t.Errorf(`Expected Id to be "chk_abc123", got %v`, instance.Id) + } + if instance.SessionId == nil || *instance.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, instance.SessionId) + } + if instance.TurnId == nil || *instance.TurnId != "turn_001" { + t.Errorf(`Expected TurnId to be "turn_001", got %v`, instance.TurnId) + } + if instance.CheckpointNumber == nil || *instance.CheckpointNumber != 3 { + t.Errorf(`Expected CheckpointNumber to be 3, got %v`, instance.CheckpointNumber) + } + if instance.Title != "Added harness contracts" { + t.Errorf(`Expected Title to be "Added harness contracts", got %v`, instance.Title) + } + if instance.CreatedAt == nil || *instance.CreatedAt != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected CreatedAt to be "2026-06-09T20:00:00Z", got %v`, instance.CreatedAt) + } +} + +// TestCheckpointFromYAML tests loading Checkpoint through the generated YAML helper +func TestCheckpointFromYAML(t *testing.T) { + yamlData := ` +id: chk_abc123 +sessionId: sess_abc123 +turnId: turn_001 +checkpointNumber: 3 +title: Added harness contracts +createdAt: "2026-06-09T20:00:00Z" + +` + + instance, err := prompty.CheckpointFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load Checkpoint from YAML helper: %v", err) + } + if instance.Id == nil || *instance.Id != "chk_abc123" { + t.Errorf(`Expected Id to be "chk_abc123", got %v`, instance.Id) + } + if instance.SessionId == nil || *instance.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, instance.SessionId) + } + if instance.TurnId == nil || *instance.TurnId != "turn_001" { + t.Errorf(`Expected TurnId to be "turn_001", got %v`, instance.TurnId) + } + if instance.CheckpointNumber == nil || *instance.CheckpointNumber != 3 { + t.Errorf(`Expected CheckpointNumber to be 3, got %v`, instance.CheckpointNumber) + } + if instance.Title != "Added harness contracts" { + t.Errorf(`Expected Title to be "Added harness contracts", got %v`, instance.Title) + } + if instance.CreatedAt == nil || *instance.CreatedAt != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected CreatedAt to be "2026-06-09T20:00:00Z", got %v`, instance.CreatedAt) + } +} + // TestCheckpointRoundtrip tests load -> save -> load produces equivalent data func TestCheckpointRoundtrip(t *testing.T) { jsonData := ` @@ -175,6 +248,29 @@ func TestCheckpointToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadCheckpoint(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Id == nil || *reloaded.Id != "chk_abc123" { + t.Errorf(`Expected Id to be "chk_abc123", got %v`, reloaded.Id) + } + if reloaded.SessionId == nil || *reloaded.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, reloaded.SessionId) + } + if reloaded.TurnId == nil || *reloaded.TurnId != "turn_001" { + t.Errorf(`Expected TurnId to be "turn_001", got %v`, reloaded.TurnId) + } + if reloaded.CheckpointNumber == nil || *reloaded.CheckpointNumber != 3 { + t.Errorf(`Expected CheckpointNumber to be 3, got %v`, reloaded.CheckpointNumber) + } + if reloaded.Title != "Added harness contracts" { + t.Errorf(`Expected Title to be "Added harness contracts", got %v`, reloaded.Title) + } + if reloaded.CreatedAt == nil || *reloaded.CreatedAt != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected CreatedAt to be "2026-06-09T20:00:00Z", got %v`, reloaded.CreatedAt) + } } // TestCheckpointToYAML tests that ToYAML produces valid YAML @@ -208,4 +304,34 @@ func TestCheckpointToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadCheckpoint(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Id == nil || *reloaded.Id != "chk_abc123" { + t.Errorf(`Expected Id to be "chk_abc123", got %v`, reloaded.Id) + } + if reloaded.SessionId == nil || *reloaded.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, reloaded.SessionId) + } + if reloaded.TurnId == nil || *reloaded.TurnId != "turn_001" { + t.Errorf(`Expected TurnId to be "turn_001", got %v`, reloaded.TurnId) + } + if reloaded.CheckpointNumber == nil || *reloaded.CheckpointNumber != 3 { + t.Errorf(`Expected CheckpointNumber to be 3, got %v`, reloaded.CheckpointNumber) + } + if reloaded.Title != "Added harness contracts" { + t.Errorf(`Expected Title to be "Added harness contracts", got %v`, reloaded.Title) + } + if reloaded.CreatedAt == nil || *reloaded.CreatedAt != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected CreatedAt to be "2026-06-09T20:00:00Z", got %v`, reloaded.CreatedAt) + } +} + +// TestCheckpointFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestCheckpointFromJSONInvalid(t *testing.T) { + if _, err := prompty.CheckpointFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/compaction_complete_payload.go b/runtime/go/prompty/model/compaction_complete_payload.go index 1ff077c1..b2a955e3 100644 --- a/runtime/go/prompty/model/compaction_complete_payload.go +++ b/runtime/go/prompty/model/compaction_complete_payload.go @@ -72,7 +72,7 @@ func LoadCompactionCompletePayload(data interface{}, ctx *LoadContext) (Compacti } // Save serializes CompactionCompletePayload to map[string]interface{} -func (obj *CompactionCompletePayload) Save(ctx *SaveContext) map[string]interface{} { +func (obj CompactionCompletePayload) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["removed"] = obj.Removed result["remaining"] = obj.Remaining @@ -98,11 +98,7 @@ func (obj *CompactionCompletePayload) ToJSON() (string, error) { func (obj *CompactionCompletePayload) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates CompactionCompletePayload from JSON string diff --git a/runtime/go/prompty/model/compaction_complete_payload_test.go b/runtime/go/prompty/model/compaction_complete_payload_test.go index 29a0eb73..ee6ac4f9 100644 --- a/runtime/go/prompty/model/compaction_complete_payload_test.go +++ b/runtime/go/prompty/model/compaction_complete_payload_test.go @@ -71,6 +71,55 @@ summaryLength: 1200 } } +// TestCompactionCompletePayloadFromJSON tests loading CompactionCompletePayload through the generated JSON helper +func TestCompactionCompletePayloadFromJSON(t *testing.T) { + jsonData := ` +{ + "removed": 5, + "remaining": 3, + "summaryLength": 1200 +} +` + + instance, err := prompty.CompactionCompletePayloadFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load CompactionCompletePayload from JSON helper: %v", err) + } + if instance.Removed != 5 { + t.Errorf(`Expected Removed to be 5, got %v`, instance.Removed) + } + if instance.Remaining != 3 { + t.Errorf(`Expected Remaining to be 3, got %v`, instance.Remaining) + } + if instance.SummaryLength == nil || *instance.SummaryLength != 1200 { + t.Errorf(`Expected SummaryLength to be 1200, got %v`, instance.SummaryLength) + } +} + +// TestCompactionCompletePayloadFromYAML tests loading CompactionCompletePayload through the generated YAML helper +func TestCompactionCompletePayloadFromYAML(t *testing.T) { + yamlData := ` +removed: 5 +remaining: 3 +summaryLength: 1200 + +` + + instance, err := prompty.CompactionCompletePayloadFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load CompactionCompletePayload from YAML helper: %v", err) + } + if instance.Removed != 5 { + t.Errorf(`Expected Removed to be 5, got %v`, instance.Removed) + } + if instance.Remaining != 3 { + t.Errorf(`Expected Remaining to be 3, got %v`, instance.Remaining) + } + if instance.SummaryLength == nil || *instance.SummaryLength != 1200 { + t.Errorf(`Expected SummaryLength to be 1200, got %v`, instance.SummaryLength) + } +} + // TestCompactionCompletePayloadRoundtrip tests load -> save -> load produces equivalent data func TestCompactionCompletePayloadRoundtrip(t *testing.T) { jsonData := ` @@ -136,6 +185,20 @@ func TestCompactionCompletePayloadToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadCompactionCompletePayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Removed != 5 { + t.Errorf(`Expected Removed to be 5, got %v`, reloaded.Removed) + } + if reloaded.Remaining != 3 { + t.Errorf(`Expected Remaining to be 3, got %v`, reloaded.Remaining) + } + if reloaded.SummaryLength == nil || *reloaded.SummaryLength != 1200 { + t.Errorf(`Expected SummaryLength to be 1200, got %v`, reloaded.SummaryLength) + } } // TestCompactionCompletePayloadToYAML tests that ToYAML produces valid YAML @@ -166,4 +229,25 @@ func TestCompactionCompletePayloadToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadCompactionCompletePayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Removed != 5 { + t.Errorf(`Expected Removed to be 5, got %v`, reloaded.Removed) + } + if reloaded.Remaining != 3 { + t.Errorf(`Expected Remaining to be 3, got %v`, reloaded.Remaining) + } + if reloaded.SummaryLength == nil || *reloaded.SummaryLength != 1200 { + t.Errorf(`Expected SummaryLength to be 1200, got %v`, reloaded.SummaryLength) + } +} + +// TestCompactionCompletePayloadFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestCompactionCompletePayloadFromJSONInvalid(t *testing.T) { + if _, err := prompty.CompactionCompletePayloadFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/compaction_config.go b/runtime/go/prompty/model/compaction_config.go index ba121403..4a699760 100644 --- a/runtime/go/prompty/model/compaction_config.go +++ b/runtime/go/prompty/model/compaction_config.go @@ -55,7 +55,7 @@ func LoadCompactionConfig(data interface{}, ctx *LoadContext) (CompactionConfig, } // Save serializes CompactionConfig to map[string]interface{} -func (obj *CompactionConfig) Save(ctx *SaveContext) map[string]interface{} { +func (obj CompactionConfig) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) if obj.Strategy != nil { result["strategy"] = *obj.Strategy @@ -85,11 +85,7 @@ func (obj *CompactionConfig) ToJSON() (string, error) { func (obj *CompactionConfig) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates CompactionConfig from JSON string diff --git a/runtime/go/prompty/model/compaction_config_test.go b/runtime/go/prompty/model/compaction_config_test.go index c70a452c..c6cfb88a 100644 --- a/runtime/go/prompty/model/compaction_config_test.go +++ b/runtime/go/prompty/model/compaction_config_test.go @@ -39,6 +39,9 @@ func TestCompactionConfigLoadJSON(t *testing.T) { if instance.Budget == nil || *instance.Budget != 50000 { t.Errorf(`Expected Budget to be 50000, got %v`, instance.Budget) } + if instance.Options == nil { + t.Fatalf("Expected Options to be populated") + } } // TestCompactionConfigLoadYAML tests loading CompactionConfig from YAML @@ -66,6 +69,61 @@ options: if instance.Budget == nil || *instance.Budget != 50000 { t.Errorf(`Expected Budget to be 50000, got %v`, instance.Budget) } + if instance.Options == nil { + t.Fatalf("Expected Options to be populated") + } +} + +// TestCompactionConfigFromJSON tests loading CompactionConfig through the generated JSON helper +func TestCompactionConfigFromJSON(t *testing.T) { + jsonData := ` +{ + "strategy": "summarize", + "budget": 50000, + "options": { + "preserveSystemMessages": true + } +} +` + + instance, err := prompty.CompactionConfigFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load CompactionConfig from JSON helper: %v", err) + } + if instance.Strategy == nil || *instance.Strategy != "summarize" { + t.Errorf(`Expected Strategy to be "summarize", got %v`, instance.Strategy) + } + if instance.Budget == nil || *instance.Budget != 50000 { + t.Errorf(`Expected Budget to be 50000, got %v`, instance.Budget) + } + if instance.Options == nil { + t.Fatalf("Expected Options to be populated") + } +} + +// TestCompactionConfigFromYAML tests loading CompactionConfig through the generated YAML helper +func TestCompactionConfigFromYAML(t *testing.T) { + yamlData := ` +strategy: summarize +budget: 50000 +options: + preserveSystemMessages: true + +` + + instance, err := prompty.CompactionConfigFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load CompactionConfig from YAML helper: %v", err) + } + if instance.Strategy == nil || *instance.Strategy != "summarize" { + t.Errorf(`Expected Strategy to be "summarize", got %v`, instance.Strategy) + } + if instance.Budget == nil || *instance.Budget != 50000 { + t.Errorf(`Expected Budget to be 50000, got %v`, instance.Budget) + } + if instance.Options == nil { + t.Fatalf("Expected Options to be populated") + } } // TestCompactionConfigRoundtrip tests load -> save -> load produces equivalent data @@ -102,6 +160,9 @@ func TestCompactionConfigRoundtrip(t *testing.T) { if reloaded.Budget == nil || *reloaded.Budget != 50000 { t.Errorf(`Expected Budget to be 50000, got %v`, reloaded.Budget) } + if reloaded.Options == nil { + t.Fatalf("Expected Options to be populated") + } } // TestCompactionConfigToJSON tests that ToJSON produces valid JSON @@ -134,6 +195,20 @@ func TestCompactionConfigToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadCompactionConfig(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Strategy == nil || *reloaded.Strategy != "summarize" { + t.Errorf(`Expected Strategy to be "summarize", got %v`, reloaded.Strategy) + } + if reloaded.Budget == nil || *reloaded.Budget != 50000 { + t.Errorf(`Expected Budget to be 50000, got %v`, reloaded.Budget) + } + if reloaded.Options == nil { + t.Fatalf("Expected Options to be populated") + } } // TestCompactionConfigToYAML tests that ToYAML produces valid YAML @@ -166,4 +241,25 @@ func TestCompactionConfigToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadCompactionConfig(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Strategy == nil || *reloaded.Strategy != "summarize" { + t.Errorf(`Expected Strategy to be "summarize", got %v`, reloaded.Strategy) + } + if reloaded.Budget == nil || *reloaded.Budget != 50000 { + t.Errorf(`Expected Budget to be 50000, got %v`, reloaded.Budget) + } + if reloaded.Options == nil { + t.Fatalf("Expected Options to be populated") + } +} + +// TestCompactionConfigFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestCompactionConfigFromJSONInvalid(t *testing.T) { + if _, err := prompty.CompactionConfigFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/compaction_failed_payload.go b/runtime/go/prompty/model/compaction_failed_payload.go index 0d902cf0..4fabe9c0 100644 --- a/runtime/go/prompty/model/compaction_failed_payload.go +++ b/runtime/go/prompty/model/compaction_failed_payload.go @@ -31,7 +31,7 @@ func LoadCompactionFailedPayload(data interface{}, ctx *LoadContext) (Compaction } // Save serializes CompactionFailedPayload to map[string]interface{} -func (obj *CompactionFailedPayload) Save(ctx *SaveContext) map[string]interface{} { +func (obj CompactionFailedPayload) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["message"] = obj.Message @@ -53,11 +53,7 @@ func (obj *CompactionFailedPayload) ToJSON() (string, error) { func (obj *CompactionFailedPayload) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates CompactionFailedPayload from JSON string diff --git a/runtime/go/prompty/model/compaction_failed_payload_test.go b/runtime/go/prompty/model/compaction_failed_payload_test.go index 6e4a1752..833d5576 100644 --- a/runtime/go/prompty/model/compaction_failed_payload_test.go +++ b/runtime/go/prompty/model/compaction_failed_payload_test.go @@ -55,6 +55,39 @@ message: Summarization prompt exceeded context window } } +// TestCompactionFailedPayloadFromJSON tests loading CompactionFailedPayload through the generated JSON helper +func TestCompactionFailedPayloadFromJSON(t *testing.T) { + jsonData := ` +{ + "message": "Summarization prompt exceeded context window" +} +` + + instance, err := prompty.CompactionFailedPayloadFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load CompactionFailedPayload from JSON helper: %v", err) + } + if instance.Message != "Summarization prompt exceeded context window" { + t.Errorf(`Expected Message to be "Summarization prompt exceeded context window", got %v`, instance.Message) + } +} + +// TestCompactionFailedPayloadFromYAML tests loading CompactionFailedPayload through the generated YAML helper +func TestCompactionFailedPayloadFromYAML(t *testing.T) { + yamlData := ` +message: Summarization prompt exceeded context window + +` + + instance, err := prompty.CompactionFailedPayloadFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load CompactionFailedPayload from YAML helper: %v", err) + } + if instance.Message != "Summarization prompt exceeded context window" { + t.Errorf(`Expected Message to be "Summarization prompt exceeded context window", got %v`, instance.Message) + } +} + // TestCompactionFailedPayloadRoundtrip tests load -> save -> load produces equivalent data func TestCompactionFailedPayloadRoundtrip(t *testing.T) { jsonData := ` @@ -110,6 +143,14 @@ func TestCompactionFailedPayloadToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadCompactionFailedPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Message != "Summarization prompt exceeded context window" { + t.Errorf(`Expected Message to be "Summarization prompt exceeded context window", got %v`, reloaded.Message) + } } // TestCompactionFailedPayloadToYAML tests that ToYAML produces valid YAML @@ -138,4 +179,19 @@ func TestCompactionFailedPayloadToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadCompactionFailedPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Message != "Summarization prompt exceeded context window" { + t.Errorf(`Expected Message to be "Summarization prompt exceeded context window", got %v`, reloaded.Message) + } +} + +// TestCompactionFailedPayloadFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestCompactionFailedPayloadFromJSONInvalid(t *testing.T) { + if _, err := prompty.CompactionFailedPayloadFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/compaction_start_payload.go b/runtime/go/prompty/model/compaction_start_payload.go index 2eb39772..1113823d 100644 --- a/runtime/go/prompty/model/compaction_start_payload.go +++ b/runtime/go/prompty/model/compaction_start_payload.go @@ -42,7 +42,7 @@ func LoadCompactionStartPayload(data interface{}, ctx *LoadContext) (CompactionS } // Save serializes CompactionStartPayload to map[string]interface{} -func (obj *CompactionStartPayload) Save(ctx *SaveContext) map[string]interface{} { +func (obj CompactionStartPayload) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["droppedCount"] = obj.DroppedCount @@ -64,11 +64,7 @@ func (obj *CompactionStartPayload) ToJSON() (string, error) { func (obj *CompactionStartPayload) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates CompactionStartPayload from JSON string diff --git a/runtime/go/prompty/model/compaction_start_payload_test.go b/runtime/go/prompty/model/compaction_start_payload_test.go index ebd6c3d7..cdaec953 100644 --- a/runtime/go/prompty/model/compaction_start_payload_test.go +++ b/runtime/go/prompty/model/compaction_start_payload_test.go @@ -55,6 +55,39 @@ droppedCount: 5 } } +// TestCompactionStartPayloadFromJSON tests loading CompactionStartPayload through the generated JSON helper +func TestCompactionStartPayloadFromJSON(t *testing.T) { + jsonData := ` +{ + "droppedCount": 5 +} +` + + instance, err := prompty.CompactionStartPayloadFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load CompactionStartPayload from JSON helper: %v", err) + } + if instance.DroppedCount != 5 { + t.Errorf(`Expected DroppedCount to be 5, got %v`, instance.DroppedCount) + } +} + +// TestCompactionStartPayloadFromYAML tests loading CompactionStartPayload through the generated YAML helper +func TestCompactionStartPayloadFromYAML(t *testing.T) { + yamlData := ` +droppedCount: 5 + +` + + instance, err := prompty.CompactionStartPayloadFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load CompactionStartPayload from YAML helper: %v", err) + } + if instance.DroppedCount != 5 { + t.Errorf(`Expected DroppedCount to be 5, got %v`, instance.DroppedCount) + } +} + // TestCompactionStartPayloadRoundtrip tests load -> save -> load produces equivalent data func TestCompactionStartPayloadRoundtrip(t *testing.T) { jsonData := ` @@ -110,6 +143,14 @@ func TestCompactionStartPayloadToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadCompactionStartPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.DroppedCount != 5 { + t.Errorf(`Expected DroppedCount to be 5, got %v`, reloaded.DroppedCount) + } } // TestCompactionStartPayloadToYAML tests that ToYAML produces valid YAML @@ -138,4 +179,19 @@ func TestCompactionStartPayloadToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadCompactionStartPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.DroppedCount != 5 { + t.Errorf(`Expected DroppedCount to be 5, got %v`, reloaded.DroppedCount) + } +} + +// TestCompactionStartPayloadFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestCompactionStartPayloadFromJSONInvalid(t *testing.T) { + if _, err := prompty.CompactionStartPayloadFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/connection.go b/runtime/go/prompty/model/connection.go index 88b12b92..87e9b95a 100644 --- a/runtime/go/prompty/model/connection.go +++ b/runtime/go/prompty/model/connection.go @@ -71,7 +71,7 @@ func LoadConnection(data interface{}, ctx *LoadContext) (interface{}, error) { } // Save serializes Connection to map[string]interface{} -func (obj *Connection) Save(ctx *SaveContext) map[string]interface{} { +func (obj Connection) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["kind"] = obj.Kind if obj.AuthenticationMode != nil { @@ -99,11 +99,7 @@ func (obj *Connection) ToJSON() (string, error) { func (obj *Connection) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates Connection from JSON string @@ -158,7 +154,7 @@ func LoadReferenceConnection(data interface{}, ctx *LoadContext) (ReferenceConne } // Save serializes ReferenceConnection to map[string]interface{} -func (obj *ReferenceConnection) Save(ctx *SaveContext) map[string]interface{} { +func (obj ReferenceConnection) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["kind"] = obj.Kind result["name"] = obj.Name @@ -184,11 +180,7 @@ func (obj *ReferenceConnection) ToJSON() (string, error) { func (obj *ReferenceConnection) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates ReferenceConnection from JSON string @@ -240,7 +232,7 @@ func LoadRemoteConnection(data interface{}, ctx *LoadContext) (RemoteConnection, } // Save serializes RemoteConnection to map[string]interface{} -func (obj *RemoteConnection) Save(ctx *SaveContext) map[string]interface{} { +func (obj RemoteConnection) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["kind"] = obj.Kind result["name"] = obj.Name @@ -264,11 +256,7 @@ func (obj *RemoteConnection) ToJSON() (string, error) { func (obj *RemoteConnection) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates RemoteConnection from JSON string @@ -320,7 +308,7 @@ func LoadApiKeyConnection(data interface{}, ctx *LoadContext) (ApiKeyConnection, } // Save serializes ApiKeyConnection to map[string]interface{} -func (obj *ApiKeyConnection) Save(ctx *SaveContext) map[string]interface{} { +func (obj ApiKeyConnection) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["kind"] = obj.Kind result["endpoint"] = obj.Endpoint @@ -344,11 +332,7 @@ func (obj *ApiKeyConnection) ToJSON() (string, error) { func (obj *ApiKeyConnection) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates ApiKeyConnection from JSON string @@ -395,7 +379,7 @@ func LoadAnonymousConnection(data interface{}, ctx *LoadContext) (AnonymousConne } // Save serializes AnonymousConnection to map[string]interface{} -func (obj *AnonymousConnection) Save(ctx *SaveContext) map[string]interface{} { +func (obj AnonymousConnection) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["kind"] = obj.Kind result["endpoint"] = obj.Endpoint @@ -418,11 +402,7 @@ func (obj *AnonymousConnection) ToJSON() (string, error) { func (obj *AnonymousConnection) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates AnonymousConnection from JSON string @@ -480,11 +460,14 @@ func LoadOAuthConnection(data interface{}, ctx *LoadContext) (OAuthConnection, e result.TokenUrl = string(val.(string)) } if val, ok := m["scopes"]; ok && val != nil { - if arr, ok := val.([]interface{}); ok { + switch arr := val.(type) { + case []interface{}: result.Scopes = make([]string, len(arr)) for i, v := range arr { result.Scopes[i] = v.(string) } + case []string: + result.Scopes = arr } } } @@ -493,7 +476,7 @@ func LoadOAuthConnection(data interface{}, ctx *LoadContext) (OAuthConnection, e } // Save serializes OAuthConnection to map[string]interface{} -func (obj *OAuthConnection) Save(ctx *SaveContext) map[string]interface{} { +func (obj OAuthConnection) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["kind"] = obj.Kind result["endpoint"] = obj.Endpoint @@ -520,11 +503,7 @@ func (obj *OAuthConnection) ToJSON() (string, error) { func (obj *OAuthConnection) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates OAuthConnection from JSON string @@ -584,7 +563,7 @@ func LoadFoundryConnection(data interface{}, ctx *LoadContext) (FoundryConnectio } // Save serializes FoundryConnection to map[string]interface{} -func (obj *FoundryConnection) Save(ctx *SaveContext) map[string]interface{} { +func (obj FoundryConnection) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["kind"] = obj.Kind result["endpoint"] = obj.Endpoint @@ -613,11 +592,7 @@ func (obj *FoundryConnection) ToJSON() (string, error) { func (obj *FoundryConnection) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates FoundryConnection from JSON string diff --git a/runtime/go/prompty/model/connection_test.go b/runtime/go/prompty/model/connection_test.go index 07be686a..93921abb 100644 --- a/runtime/go/prompty/model/connection_test.go +++ b/runtime/go/prompty/model/connection_test.go @@ -59,6 +59,43 @@ usageDescription: This will allow the agent to respond to an email on your behal // Note: Validation skipped for polymorphic base types - test child types directly } +// TestConnectionFromJSON tests loading Connection through the generated JSON helper +func TestConnectionFromJSON(t *testing.T) { + jsonData := ` +{ + "kind": "reference", + "authenticationMode": "system", + "usageDescription": "This will allow the agent to respond to an email on your behalf" +} +` + + instance, err := prompty.ConnectionFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load Connection from JSON helper: %v", err) + } + // Polymorphic types return interface{}, extract common fields via reflection or type-specific access + _ = instance // Load succeeded, exact type depends on discriminator + // Note: Validation skipped for polymorphic base types - test child types directly +} + +// TestConnectionFromYAML tests loading Connection through the generated YAML helper +func TestConnectionFromYAML(t *testing.T) { + yamlData := ` +kind: reference +authenticationMode: system +usageDescription: This will allow the agent to respond to an email on your behalf + +` + + instance, err := prompty.ConnectionFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load Connection from YAML helper: %v", err) + } + // Polymorphic types return interface{}, extract common fields via reflection or type-specific access + _ = instance // Load succeeded, exact type depends on discriminator + // Note: Validation skipped for polymorphic base types - test child types directly +} + // TestConnectionRoundtrip tests load -> save -> load produces equivalent data func TestConnectionRoundtrip(t *testing.T) { jsonData := ` @@ -130,3 +167,10 @@ func TestConnectionToYAML(t *testing.T) { _ = instance // Load succeeded, exact type depends on discriminator // Note: ToYAML test skipped for polymorphic base types - test child types directly } + +// TestConnectionFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestConnectionFromJSONInvalid(t *testing.T) { + if _, err := prompty.ConnectionFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } +} diff --git a/runtime/go/prompty/model/content_part.go b/runtime/go/prompty/model/content_part.go index 8b68a1ce..c517478e 100644 --- a/runtime/go/prompty/model/content_part.go +++ b/runtime/go/prompty/model/content_part.go @@ -48,7 +48,7 @@ func LoadContentPart(data interface{}, ctx *LoadContext) (interface{}, error) { } // Save serializes ContentPart to map[string]interface{} -func (obj *ContentPart) Save(ctx *SaveContext) map[string]interface{} { +func (obj ContentPart) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["kind"] = obj.Kind @@ -70,11 +70,7 @@ func (obj *ContentPart) ToJSON() (string, error) { func (obj *ContentPart) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates ContentPart from JSON string @@ -124,7 +120,7 @@ func LoadTextPart(data interface{}, ctx *LoadContext) (TextPart, error) { } // Save serializes TextPart to map[string]interface{} -func (obj *TextPart) Save(ctx *SaveContext) map[string]interface{} { +func (obj TextPart) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["kind"] = obj.Kind result["value"] = obj.Value @@ -147,11 +143,7 @@ func (obj *TextPart) ToJSON() (string, error) { func (obj *TextPart) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates TextPart from JSON string @@ -209,7 +201,7 @@ func LoadImagePart(data interface{}, ctx *LoadContext) (ImagePart, error) { } // Save serializes ImagePart to map[string]interface{} -func (obj *ImagePart) Save(ctx *SaveContext) map[string]interface{} { +func (obj ImagePart) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["kind"] = obj.Kind result["source"] = obj.Source @@ -238,11 +230,7 @@ func (obj *ImagePart) ToJSON() (string, error) { func (obj *ImagePart) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates ImagePart from JSON string @@ -295,7 +283,7 @@ func LoadFilePart(data interface{}, ctx *LoadContext) (FilePart, error) { } // Save serializes FilePart to map[string]interface{} -func (obj *FilePart) Save(ctx *SaveContext) map[string]interface{} { +func (obj FilePart) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["kind"] = obj.Kind result["source"] = obj.Source @@ -321,11 +309,7 @@ func (obj *FilePart) ToJSON() (string, error) { func (obj *FilePart) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates FilePart from JSON string @@ -378,7 +362,7 @@ func LoadAudioPart(data interface{}, ctx *LoadContext) (AudioPart, error) { } // Save serializes AudioPart to map[string]interface{} -func (obj *AudioPart) Save(ctx *SaveContext) map[string]interface{} { +func (obj AudioPart) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["kind"] = obj.Kind result["source"] = obj.Source @@ -404,11 +388,7 @@ func (obj *AudioPart) ToJSON() (string, error) { func (obj *AudioPart) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates AudioPart from JSON string diff --git a/runtime/go/prompty/model/context.go b/runtime/go/prompty/model/context.go index 01a2c614..f18a5c98 100644 --- a/runtime/go/prompty/model/context.go +++ b/runtime/go/prompty/model/context.go @@ -4,6 +4,15 @@ package prompty +import ( + "fmt" + "reflect" + "sort" + "strings" + + "gopkg.in/yaml.v3" +) + // LoadContext provides context for loading operations type LoadContext struct { // Add any context fields needed for loading @@ -31,3 +40,75 @@ func NewSaveContext() *SaveContext { func ptrOf[T any](v T) *T { return &v } + +func marshalYAMLDocument(data interface{}) (string, error) { + node := toYAMLNode(data) + bytes, err := yaml.Marshal(node) + if err != nil { + return "", err + } + return string(bytes), nil +} + +func toYAMLNode(value interface{}) *yaml.Node { + switch v := value.(type) { + case nil: + return &yaml.Node{Kind: yaml.ScalarNode, Tag: "!!null"} + case string: + node := &yaml.Node{Kind: yaml.ScalarNode, Tag: "!!str", Value: v} + if strings.Contains(v, "\n") { + node.Style = yaml.DoubleQuotedStyle + } + return node + case map[string]interface{}: + return mapToYAMLNode(v) + case []interface{}: + node := &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"} + for _, item := range v { + node.Content = append(node.Content, toYAMLNode(item)) + } + return node + } + + rv := reflect.ValueOf(value) + if rv.IsValid() { + switch rv.Kind() { + case reflect.Slice, reflect.Array: + node := &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"} + for i := 0; i < rv.Len(); i++ { + node.Content = append(node.Content, toYAMLNode(rv.Index(i).Interface())) + } + return node + case reflect.Map: + if rv.Type().Key().Kind() == reflect.String { + items := make(map[string]interface{}, rv.Len()) + for _, key := range rv.MapKeys() { + items[key.String()] = rv.MapIndex(key).Interface() + } + return mapToYAMLNode(items) + } + } + } + + node := &yaml.Node{} + if err := node.Encode(value); err == nil { + if node.Kind == yaml.ScalarNode && node.Tag == "!!str" && strings.Contains(node.Value, "\n") { + node.Style = yaml.DoubleQuotedStyle + } + return node + } + return &yaml.Node{Kind: yaml.ScalarNode, Tag: "!!str", Value: fmt.Sprint(value)} +} + +func mapToYAMLNode(items map[string]interface{}) *yaml.Node { + node := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} + keys := make([]string, 0, len(items)) + for key := range items { + keys = append(keys, key) + } + sort.Strings(keys) + for _, key := range keys { + node.Content = append(node.Content, &yaml.Node{Kind: yaml.ScalarNode, Tag: "!!str", Value: key}, toYAMLNode(items[key])) + } + return node +} diff --git a/runtime/go/prompty/model/custom_tool_test.go b/runtime/go/prompty/model/custom_tool_test.go index 3fa2dc7d..2087ebb5 100644 --- a/runtime/go/prompty/model/custom_tool_test.go +++ b/runtime/go/prompty/model/custom_tool_test.go @@ -36,6 +36,9 @@ func TestCustomToolLoadJSON(t *testing.T) { t.Fatalf("Failed to load CustomTool: %v", err) } _ = instance // No scalar properties to validate + if instance.Options == nil { + t.Fatalf("Expected Options to be populated") + } } // TestCustomToolLoadYAML tests loading CustomTool from YAML @@ -59,6 +62,54 @@ options: t.Fatalf("Failed to load CustomTool: %v", err) } _ = instance // No scalar properties to validate + if instance.Options == nil { + t.Fatalf("Expected Options to be populated") + } +} + +// TestCustomToolFromJSON tests loading CustomTool through the generated JSON helper +func TestCustomToolFromJSON(t *testing.T) { + jsonData := ` +{ + "connection": { + "kind": "reference" + }, + "options": { + "timeout": 30, + "retries": 3 + } +} +` + + instance, err := prompty.CustomToolFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load CustomTool from JSON helper: %v", err) + } + _ = instance // No scalar properties to validate + if instance.Options == nil { + t.Fatalf("Expected Options to be populated") + } +} + +// TestCustomToolFromYAML tests loading CustomTool through the generated YAML helper +func TestCustomToolFromYAML(t *testing.T) { + yamlData := ` +connection: + kind: reference +options: + timeout: 30 + retries: 3 + +` + + instance, err := prompty.CustomToolFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load CustomTool from YAML helper: %v", err) + } + _ = instance // No scalar properties to validate + if instance.Options == nil { + t.Fatalf("Expected Options to be populated") + } } // TestCustomToolRoundtrip tests load -> save -> load produces equivalent data @@ -92,6 +143,9 @@ func TestCustomToolRoundtrip(t *testing.T) { t.Fatalf("Failed to reload CustomTool: %v", err) } _ = reloaded // No scalar properties to validate + if reloaded.Options == nil { + t.Fatalf("Expected Options to be populated") + } } // TestCustomToolToJSON tests that ToJSON produces valid JSON @@ -126,6 +180,15 @@ func TestCustomToolToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadCustomTool(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + _ = reloaded // No scalar properties to validate + if reloaded.Options == nil { + t.Fatalf("Expected Options to be populated") + } } // TestCustomToolToYAML tests that ToYAML produces valid YAML @@ -160,4 +223,20 @@ func TestCustomToolToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadCustomTool(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + _ = reloaded // No scalar properties to validate + if reloaded.Options == nil { + t.Fatalf("Expected Options to be populated") + } +} + +// TestCustomToolFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestCustomToolFromJSONInvalid(t *testing.T) { + if _, err := prompty.CustomToolFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/done_event_payload.go b/runtime/go/prompty/model/done_event_payload.go index aa004931..92bb0325 100644 --- a/runtime/go/prompty/model/done_event_payload.go +++ b/runtime/go/prompty/model/done_event_payload.go @@ -43,7 +43,7 @@ func LoadDoneEventPayload(data interface{}, ctx *LoadContext) (DoneEventPayload, } // Save serializes DoneEventPayload to map[string]interface{} -func (obj *DoneEventPayload) Save(ctx *SaveContext) map[string]interface{} { +func (obj DoneEventPayload) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["response"] = obj.Response if obj.Messages != nil { @@ -72,11 +72,7 @@ func (obj *DoneEventPayload) ToJSON() (string, error) { func (obj *DoneEventPayload) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates DoneEventPayload from JSON string diff --git a/runtime/go/prompty/model/error_chunk_test.go b/runtime/go/prompty/model/error_chunk_test.go index 27eec536..b3255ee0 100644 --- a/runtime/go/prompty/model/error_chunk_test.go +++ b/runtime/go/prompty/model/error_chunk_test.go @@ -55,6 +55,39 @@ message: Rate limit exceeded } } +// TestErrorChunkFromJSON tests loading ErrorChunk through the generated JSON helper +func TestErrorChunkFromJSON(t *testing.T) { + jsonData := ` +{ + "message": "Rate limit exceeded" +} +` + + instance, err := prompty.ErrorChunkFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load ErrorChunk from JSON helper: %v", err) + } + if instance.Message != "Rate limit exceeded" { + t.Errorf(`Expected Message to be "Rate limit exceeded", got %v`, instance.Message) + } +} + +// TestErrorChunkFromYAML tests loading ErrorChunk through the generated YAML helper +func TestErrorChunkFromYAML(t *testing.T) { + yamlData := ` +message: Rate limit exceeded + +` + + instance, err := prompty.ErrorChunkFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load ErrorChunk from YAML helper: %v", err) + } + if instance.Message != "Rate limit exceeded" { + t.Errorf(`Expected Message to be "Rate limit exceeded", got %v`, instance.Message) + } +} + // TestErrorChunkRoundtrip tests load -> save -> load produces equivalent data func TestErrorChunkRoundtrip(t *testing.T) { jsonData := ` @@ -110,6 +143,14 @@ func TestErrorChunkToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadErrorChunk(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Message != "Rate limit exceeded" { + t.Errorf(`Expected Message to be "Rate limit exceeded", got %v`, reloaded.Message) + } } // TestErrorChunkToYAML tests that ToYAML produces valid YAML @@ -138,4 +179,19 @@ func TestErrorChunkToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadErrorChunk(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Message != "Rate limit exceeded" { + t.Errorf(`Expected Message to be "Rate limit exceeded", got %v`, reloaded.Message) + } +} + +// TestErrorChunkFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestErrorChunkFromJSONInvalid(t *testing.T) { + if _, err := prompty.ErrorChunkFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/error_event_payload.go b/runtime/go/prompty/model/error_event_payload.go index a6010eeb..e2bc5922 100644 --- a/runtime/go/prompty/model/error_event_payload.go +++ b/runtime/go/prompty/model/error_event_payload.go @@ -41,7 +41,7 @@ func LoadErrorEventPayload(data interface{}, ctx *LoadContext) (ErrorEventPayloa } // Save serializes ErrorEventPayload to map[string]interface{} -func (obj *ErrorEventPayload) Save(ctx *SaveContext) map[string]interface{} { +func (obj ErrorEventPayload) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["message"] = obj.Message if obj.ErrorKind != nil { @@ -69,11 +69,7 @@ func (obj *ErrorEventPayload) ToJSON() (string, error) { func (obj *ErrorEventPayload) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates ErrorEventPayload from JSON string diff --git a/runtime/go/prompty/model/error_event_payload_test.go b/runtime/go/prompty/model/error_event_payload_test.go index ea1023f0..a9d58594 100644 --- a/runtime/go/prompty/model/error_event_payload_test.go +++ b/runtime/go/prompty/model/error_event_payload_test.go @@ -71,6 +71,55 @@ phase: llm } } +// TestErrorEventPayloadFromJSON tests loading ErrorEventPayload through the generated JSON helper +func TestErrorEventPayloadFromJSON(t *testing.T) { + jsonData := ` +{ + "message": "Rate limit exceeded", + "errorKind": "rate_limit", + "phase": "llm" +} +` + + instance, err := prompty.ErrorEventPayloadFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load ErrorEventPayload from JSON helper: %v", err) + } + if instance.Message != "Rate limit exceeded" { + t.Errorf(`Expected Message to be "Rate limit exceeded", got %v`, instance.Message) + } + if instance.ErrorKind == nil || *instance.ErrorKind != "rate_limit" { + t.Errorf(`Expected ErrorKind to be "rate_limit", got %v`, instance.ErrorKind) + } + if instance.Phase == nil || *instance.Phase != "llm" { + t.Errorf(`Expected Phase to be "llm", got %v`, instance.Phase) + } +} + +// TestErrorEventPayloadFromYAML tests loading ErrorEventPayload through the generated YAML helper +func TestErrorEventPayloadFromYAML(t *testing.T) { + yamlData := ` +message: Rate limit exceeded +errorKind: rate_limit +phase: llm + +` + + instance, err := prompty.ErrorEventPayloadFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load ErrorEventPayload from YAML helper: %v", err) + } + if instance.Message != "Rate limit exceeded" { + t.Errorf(`Expected Message to be "Rate limit exceeded", got %v`, instance.Message) + } + if instance.ErrorKind == nil || *instance.ErrorKind != "rate_limit" { + t.Errorf(`Expected ErrorKind to be "rate_limit", got %v`, instance.ErrorKind) + } + if instance.Phase == nil || *instance.Phase != "llm" { + t.Errorf(`Expected Phase to be "llm", got %v`, instance.Phase) + } +} + // TestErrorEventPayloadRoundtrip tests load -> save -> load produces equivalent data func TestErrorEventPayloadRoundtrip(t *testing.T) { jsonData := ` @@ -136,6 +185,20 @@ func TestErrorEventPayloadToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadErrorEventPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Message != "Rate limit exceeded" { + t.Errorf(`Expected Message to be "Rate limit exceeded", got %v`, reloaded.Message) + } + if reloaded.ErrorKind == nil || *reloaded.ErrorKind != "rate_limit" { + t.Errorf(`Expected ErrorKind to be "rate_limit", got %v`, reloaded.ErrorKind) + } + if reloaded.Phase == nil || *reloaded.Phase != "llm" { + t.Errorf(`Expected Phase to be "llm", got %v`, reloaded.Phase) + } } // TestErrorEventPayloadToYAML tests that ToYAML produces valid YAML @@ -166,4 +229,25 @@ func TestErrorEventPayloadToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadErrorEventPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Message != "Rate limit exceeded" { + t.Errorf(`Expected Message to be "Rate limit exceeded", got %v`, reloaded.Message) + } + if reloaded.ErrorKind == nil || *reloaded.ErrorKind != "rate_limit" { + t.Errorf(`Expected ErrorKind to be "rate_limit", got %v`, reloaded.ErrorKind) + } + if reloaded.Phase == nil || *reloaded.Phase != "llm" { + t.Errorf(`Expected Phase to be "llm", got %v`, reloaded.Phase) + } +} + +// TestErrorEventPayloadFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestErrorEventPayloadFromJSONInvalid(t *testing.T) { + if _, err := prompty.ErrorEventPayloadFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/file_not_found_error.go b/runtime/go/prompty/model/file_not_found_error.go index 4d84b270..7a47f4d7 100644 --- a/runtime/go/prompty/model/file_not_found_error.go +++ b/runtime/go/prompty/model/file_not_found_error.go @@ -36,7 +36,7 @@ func LoadFileNotFoundError(data interface{}, ctx *LoadContext) (FileNotFoundErro } // Save serializes FileNotFoundError to map[string]interface{} -func (obj *FileNotFoundError) Save(ctx *SaveContext) map[string]interface{} { +func (obj FileNotFoundError) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["message"] = obj.Message result["path"] = obj.Path @@ -59,11 +59,7 @@ func (obj *FileNotFoundError) ToJSON() (string, error) { func (obj *FileNotFoundError) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates FileNotFoundError from JSON string diff --git a/runtime/go/prompty/model/file_not_found_error_test.go b/runtime/go/prompty/model/file_not_found_error_test.go index fd5990c6..aabfacf9 100644 --- a/runtime/go/prompty/model/file_not_found_error_test.go +++ b/runtime/go/prompty/model/file_not_found_error_test.go @@ -63,6 +63,47 @@ path: ./chat.prompty } } +// TestFileNotFoundErrorFromJSON tests loading FileNotFoundError through the generated JSON helper +func TestFileNotFoundErrorFromJSON(t *testing.T) { + jsonData := ` +{ + "message": "Prompty file not found: ./chat.prompty", + "path": "./chat.prompty" +} +` + + instance, err := prompty.FileNotFoundErrorFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load FileNotFoundError from JSON helper: %v", err) + } + if instance.Message != "Prompty file not found: ./chat.prompty" { + t.Errorf(`Expected Message to be "Prompty file not found: ./chat.prompty", got %v`, instance.Message) + } + if instance.Path != "./chat.prompty" { + t.Errorf(`Expected Path to be "./chat.prompty", got %v`, instance.Path) + } +} + +// TestFileNotFoundErrorFromYAML tests loading FileNotFoundError through the generated YAML helper +func TestFileNotFoundErrorFromYAML(t *testing.T) { + yamlData := ` +message: "Prompty file not found: ./chat.prompty" +path: ./chat.prompty + +` + + instance, err := prompty.FileNotFoundErrorFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load FileNotFoundError from YAML helper: %v", err) + } + if instance.Message != "Prompty file not found: ./chat.prompty" { + t.Errorf(`Expected Message to be "Prompty file not found: ./chat.prompty", got %v`, instance.Message) + } + if instance.Path != "./chat.prompty" { + t.Errorf(`Expected Path to be "./chat.prompty", got %v`, instance.Path) + } +} + // TestFileNotFoundErrorRoundtrip tests load -> save -> load produces equivalent data func TestFileNotFoundErrorRoundtrip(t *testing.T) { jsonData := ` @@ -123,6 +164,17 @@ func TestFileNotFoundErrorToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadFileNotFoundError(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Message != "Prompty file not found: ./chat.prompty" { + t.Errorf(`Expected Message to be "Prompty file not found: ./chat.prompty", got %v`, reloaded.Message) + } + if reloaded.Path != "./chat.prompty" { + t.Errorf(`Expected Path to be "./chat.prompty", got %v`, reloaded.Path) + } } // TestFileNotFoundErrorToYAML tests that ToYAML produces valid YAML @@ -152,4 +204,22 @@ func TestFileNotFoundErrorToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadFileNotFoundError(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Message != "Prompty file not found: ./chat.prompty" { + t.Errorf(`Expected Message to be "Prompty file not found: ./chat.prompty", got %v`, reloaded.Message) + } + if reloaded.Path != "./chat.prompty" { + t.Errorf(`Expected Path to be "./chat.prompty", got %v`, reloaded.Path) + } +} + +// TestFileNotFoundErrorFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestFileNotFoundErrorFromJSONInvalid(t *testing.T) { + if _, err := prompty.FileNotFoundErrorFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/file_part_test.go b/runtime/go/prompty/model/file_part_test.go index e96edd93..7068dff3 100644 --- a/runtime/go/prompty/model/file_part_test.go +++ b/runtime/go/prompty/model/file_part_test.go @@ -63,6 +63,47 @@ mediaType: application/pdf } } +// TestFilePartFromJSON tests loading FilePart through the generated JSON helper +func TestFilePartFromJSON(t *testing.T) { + jsonData := ` +{ + "source": "https://example.com/document.pdf", + "mediaType": "application/pdf" +} +` + + instance, err := prompty.FilePartFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load FilePart from JSON helper: %v", err) + } + if instance.Source != "https://example.com/document.pdf" { + t.Errorf(`Expected Source to be "https://example.com/document.pdf", got %v`, instance.Source) + } + if instance.MediaType == nil || *instance.MediaType != "application/pdf" { + t.Errorf(`Expected MediaType to be "application/pdf", got %v`, instance.MediaType) + } +} + +// TestFilePartFromYAML tests loading FilePart through the generated YAML helper +func TestFilePartFromYAML(t *testing.T) { + yamlData := ` +source: "https://example.com/document.pdf" +mediaType: application/pdf + +` + + instance, err := prompty.FilePartFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load FilePart from YAML helper: %v", err) + } + if instance.Source != "https://example.com/document.pdf" { + t.Errorf(`Expected Source to be "https://example.com/document.pdf", got %v`, instance.Source) + } + if instance.MediaType == nil || *instance.MediaType != "application/pdf" { + t.Errorf(`Expected MediaType to be "application/pdf", got %v`, instance.MediaType) + } +} + // TestFilePartRoundtrip tests load -> save -> load produces equivalent data func TestFilePartRoundtrip(t *testing.T) { jsonData := ` @@ -123,6 +164,17 @@ func TestFilePartToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadFilePart(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Source != "https://example.com/document.pdf" { + t.Errorf(`Expected Source to be "https://example.com/document.pdf", got %v`, reloaded.Source) + } + if reloaded.MediaType == nil || *reloaded.MediaType != "application/pdf" { + t.Errorf(`Expected MediaType to be "application/pdf", got %v`, reloaded.MediaType) + } } // TestFilePartToYAML tests that ToYAML produces valid YAML @@ -152,4 +204,22 @@ func TestFilePartToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadFilePart(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Source != "https://example.com/document.pdf" { + t.Errorf(`Expected Source to be "https://example.com/document.pdf", got %v`, reloaded.Source) + } + if reloaded.MediaType == nil || *reloaded.MediaType != "application/pdf" { + t.Errorf(`Expected MediaType to be "application/pdf", got %v`, reloaded.MediaType) + } +} + +// TestFilePartFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestFilePartFromJSONInvalid(t *testing.T) { + if _, err := prompty.FilePartFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/format_config.go b/runtime/go/prompty/model/format_config.go index 009007d0..8cfb37b1 100644 --- a/runtime/go/prompty/model/format_config.go +++ b/runtime/go/prompty/model/format_config.go @@ -49,7 +49,7 @@ func LoadFormatConfig(data interface{}, ctx *LoadContext) (FormatConfig, error) } // Save serializes FormatConfig to map[string]interface{} -func (obj *FormatConfig) Save(ctx *SaveContext) map[string]interface{} { +func (obj FormatConfig) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["kind"] = obj.Kind if obj.Strict != nil { @@ -77,11 +77,7 @@ func (obj *FormatConfig) ToJSON() (string, error) { func (obj *FormatConfig) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates FormatConfig from JSON string diff --git a/runtime/go/prompty/model/format_config_test.go b/runtime/go/prompty/model/format_config_test.go index 49fe81ce..35d46b22 100644 --- a/runtime/go/prompty/model/format_config_test.go +++ b/runtime/go/prompty/model/format_config_test.go @@ -62,6 +62,46 @@ options: // Note: Validation skipped for polymorphic base types - test child types directly } +// TestFormatConfigFromJSON tests loading FormatConfig through the generated JSON helper +func TestFormatConfigFromJSON(t *testing.T) { + jsonData := ` +{ + "kind": "mustache", + "strict": true, + "options": { + "key": "value" + } +} +` + + instance, err := prompty.FormatConfigFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load FormatConfig from JSON helper: %v", err) + } + // Polymorphic types return interface{}, extract common fields via reflection or type-specific access + _ = instance // Load succeeded, exact type depends on discriminator + // Note: Validation skipped for polymorphic base types - test child types directly +} + +// TestFormatConfigFromYAML tests loading FormatConfig through the generated YAML helper +func TestFormatConfigFromYAML(t *testing.T) { + yamlData := ` +kind: mustache +strict: true +options: + key: value + +` + + instance, err := prompty.FormatConfigFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load FormatConfig from YAML helper: %v", err) + } + // Polymorphic types return interface{}, extract common fields via reflection or type-specific access + _ = instance // Load succeeded, exact type depends on discriminator + // Note: Validation skipped for polymorphic base types - test child types directly +} + // TestFormatConfigRoundtrip tests load -> save -> load produces equivalent data func TestFormatConfigRoundtrip(t *testing.T) { jsonData := ` @@ -140,6 +180,13 @@ func TestFormatConfigToYAML(t *testing.T) { // Note: ToYAML test skipped for polymorphic base types - test child types directly } +// TestFormatConfigFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestFormatConfigFromJSONInvalid(t *testing.T) { + if _, err := prompty.FormatConfigFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } +} + // TestFormatConfigFromFormat tests loading FormatConfig from string func TestFormatConfigFromFormat(t *testing.T) { ctx := prompty.NewLoadContext() diff --git a/runtime/go/prompty/model/foundry_connection_test.go b/runtime/go/prompty/model/foundry_connection_test.go index 4956eaee..629ad433 100644 --- a/runtime/go/prompty/model/foundry_connection_test.go +++ b/runtime/go/prompty/model/foundry_connection_test.go @@ -79,6 +79,63 @@ connectionType: model } } +// TestFoundryConnectionFromJSON tests loading FoundryConnection through the generated JSON helper +func TestFoundryConnectionFromJSON(t *testing.T) { + jsonData := ` +{ + "kind": "foundry", + "endpoint": "https://myresource.services.ai.azure.com/api/projects/myproject", + "name": "my-openai-connection", + "connectionType": "model" +} +` + + instance, err := prompty.FoundryConnectionFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load FoundryConnection from JSON helper: %v", err) + } + if instance.Kind != "foundry" { + t.Errorf(`Expected Kind to be "foundry", got %v`, instance.Kind) + } + if instance.Endpoint != "https://myresource.services.ai.azure.com/api/projects/myproject" { + t.Errorf(`Expected Endpoint to be "https://myresource.services.ai.azure.com/api/projects/myproject", got %v`, instance.Endpoint) + } + if instance.Name == nil || *instance.Name != "my-openai-connection" { + t.Errorf(`Expected Name to be "my-openai-connection", got %v`, instance.Name) + } + if instance.ConnectionType == nil || *instance.ConnectionType != "model" { + t.Errorf(`Expected ConnectionType to be "model", got %v`, instance.ConnectionType) + } +} + +// TestFoundryConnectionFromYAML tests loading FoundryConnection through the generated YAML helper +func TestFoundryConnectionFromYAML(t *testing.T) { + yamlData := ` +kind: foundry +endpoint: "https://myresource.services.ai.azure.com/api/projects/myproject" +name: my-openai-connection +connectionType: model + +` + + instance, err := prompty.FoundryConnectionFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load FoundryConnection from YAML helper: %v", err) + } + if instance.Kind != "foundry" { + t.Errorf(`Expected Kind to be "foundry", got %v`, instance.Kind) + } + if instance.Endpoint != "https://myresource.services.ai.azure.com/api/projects/myproject" { + t.Errorf(`Expected Endpoint to be "https://myresource.services.ai.azure.com/api/projects/myproject", got %v`, instance.Endpoint) + } + if instance.Name == nil || *instance.Name != "my-openai-connection" { + t.Errorf(`Expected Name to be "my-openai-connection", got %v`, instance.Name) + } + if instance.ConnectionType == nil || *instance.ConnectionType != "model" { + t.Errorf(`Expected ConnectionType to be "model", got %v`, instance.ConnectionType) + } +} + // TestFoundryConnectionRoundtrip tests load -> save -> load produces equivalent data func TestFoundryConnectionRoundtrip(t *testing.T) { jsonData := ` @@ -149,6 +206,23 @@ func TestFoundryConnectionToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadFoundryConnection(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Kind != "foundry" { + t.Errorf(`Expected Kind to be "foundry", got %v`, reloaded.Kind) + } + if reloaded.Endpoint != "https://myresource.services.ai.azure.com/api/projects/myproject" { + t.Errorf(`Expected Endpoint to be "https://myresource.services.ai.azure.com/api/projects/myproject", got %v`, reloaded.Endpoint) + } + if reloaded.Name == nil || *reloaded.Name != "my-openai-connection" { + t.Errorf(`Expected Name to be "my-openai-connection", got %v`, reloaded.Name) + } + if reloaded.ConnectionType == nil || *reloaded.ConnectionType != "model" { + t.Errorf(`Expected ConnectionType to be "model", got %v`, reloaded.ConnectionType) + } } // TestFoundryConnectionToYAML tests that ToYAML produces valid YAML @@ -180,4 +254,28 @@ func TestFoundryConnectionToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadFoundryConnection(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Kind != "foundry" { + t.Errorf(`Expected Kind to be "foundry", got %v`, reloaded.Kind) + } + if reloaded.Endpoint != "https://myresource.services.ai.azure.com/api/projects/myproject" { + t.Errorf(`Expected Endpoint to be "https://myresource.services.ai.azure.com/api/projects/myproject", got %v`, reloaded.Endpoint) + } + if reloaded.Name == nil || *reloaded.Name != "my-openai-connection" { + t.Errorf(`Expected Name to be "my-openai-connection", got %v`, reloaded.Name) + } + if reloaded.ConnectionType == nil || *reloaded.ConnectionType != "model" { + t.Errorf(`Expected ConnectionType to be "model", got %v`, reloaded.ConnectionType) + } +} + +// TestFoundryConnectionFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestFoundryConnectionFromJSONInvalid(t *testing.T) { + if _, err := prompty.FoundryConnectionFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/function_tool_test.go b/runtime/go/prompty/model/function_tool_test.go index 111930dc..c70f8d50 100644 --- a/runtime/go/prompty/model/function_tool_test.go +++ b/runtime/go/prompty/model/function_tool_test.go @@ -87,6 +87,71 @@ strict: true } } +// TestFunctionToolFromJSON tests loading FunctionTool through the generated JSON helper +func TestFunctionToolFromJSON(t *testing.T) { + jsonData := ` +{ + "kind": "function", + "parameters": { + "firstName": { + "kind": "string", + "default": "Jane" + }, + "lastName": { + "kind": "string", + "default": "Doe" + }, + "question": { + "kind": "string", + "default": "What is the meaning of life?" + } + }, + "strict": true +} +` + + instance, err := prompty.FunctionToolFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load FunctionTool from JSON helper: %v", err) + } + if instance.Kind != "function" { + t.Errorf(`Expected Kind to be "function", got %v`, instance.Kind) + } + if instance.Strict == nil || *instance.Strict != true { + t.Errorf(`Expected Strict to be true, got %v`, instance.Strict) + } +} + +// TestFunctionToolFromYAML tests loading FunctionTool through the generated YAML helper +func TestFunctionToolFromYAML(t *testing.T) { + yamlData := ` +kind: function +parameters: + firstName: + kind: string + default: Jane + lastName: + kind: string + default: Doe + question: + kind: string + default: What is the meaning of life? +strict: true + +` + + instance, err := prompty.FunctionToolFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load FunctionTool from YAML helper: %v", err) + } + if instance.Kind != "function" { + t.Errorf(`Expected Kind to be "function", got %v`, instance.Kind) + } + if instance.Strict == nil || *instance.Strict != true { + t.Errorf(`Expected Strict to be true, got %v`, instance.Strict) + } +} + // TestFunctionToolRoundtrip tests load -> save -> load produces equivalent data func TestFunctionToolRoundtrip(t *testing.T) { jsonData := ` @@ -175,6 +240,17 @@ func TestFunctionToolToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadFunctionTool(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Kind != "function" { + t.Errorf(`Expected Kind to be "function", got %v`, reloaded.Kind) + } + if reloaded.Strict == nil || *reloaded.Strict != true { + t.Errorf(`Expected Strict to be true, got %v`, reloaded.Strict) + } } // TestFunctionToolToYAML tests that ToYAML produces valid YAML @@ -218,6 +294,17 @@ func TestFunctionToolToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadFunctionTool(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Kind != "function" { + t.Errorf(`Expected Kind to be "function", got %v`, reloaded.Kind) + } + if reloaded.Strict == nil || *reloaded.Strict != true { + t.Errorf(`Expected Strict to be true, got %v`, reloaded.Strict) + } } // TestFunctionToolLoadJSON1 tests loading FunctionTool from JSON @@ -261,6 +348,9 @@ func TestFunctionToolLoadJSON1(t *testing.T) { if instance.Strict == nil || *instance.Strict != true { t.Errorf(`Expected Strict to be true, got %v`, instance.Strict) } + if len(instance.Parameters) != 3 { + t.Fatalf("Expected Parameters length to be 3, got %d", len(instance.Parameters)) + } } // TestFunctionToolLoadYAML1 tests loading FunctionTool from YAML @@ -296,6 +386,83 @@ strict: true if instance.Strict == nil || *instance.Strict != true { t.Errorf(`Expected Strict to be true, got %v`, instance.Strict) } + if len(instance.Parameters) != 3 { + t.Fatalf("Expected Parameters length to be 3, got %d", len(instance.Parameters)) + } +} + +// TestFunctionToolFromJSON1 tests loading FunctionTool through the generated JSON helper +func TestFunctionToolFromJSON1(t *testing.T) { + jsonData := ` +{ + "kind": "function", + "parameters": [ + { + "name": "firstName", + "kind": "string", + "default": "Jane" + }, + { + "name": "lastName", + "kind": "string", + "default": "Doe" + }, + { + "name": "question", + "kind": "string", + "default": "What is the meaning of life?" + } + ], + "strict": true +} +` + + instance, err := prompty.FunctionToolFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load FunctionTool from JSON helper: %v", err) + } + if instance.Kind != "function" { + t.Errorf(`Expected Kind to be "function", got %v`, instance.Kind) + } + if instance.Strict == nil || *instance.Strict != true { + t.Errorf(`Expected Strict to be true, got %v`, instance.Strict) + } + if len(instance.Parameters) != 3 { + t.Fatalf("Expected Parameters length to be 3, got %d", len(instance.Parameters)) + } +} + +// TestFunctionToolFromYAML1 tests loading FunctionTool through the generated YAML helper +func TestFunctionToolFromYAML1(t *testing.T) { + yamlData := ` +kind: function +parameters: + - name: firstName + kind: string + default: Jane + - name: lastName + kind: string + default: Doe + - name: question + kind: string + default: What is the meaning of life? +strict: true + +` + + instance, err := prompty.FunctionToolFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load FunctionTool from YAML helper: %v", err) + } + if instance.Kind != "function" { + t.Errorf(`Expected Kind to be "function", got %v`, instance.Kind) + } + if instance.Strict == nil || *instance.Strict != true { + t.Errorf(`Expected Strict to be true, got %v`, instance.Strict) + } + if len(instance.Parameters) != 3 { + t.Fatalf("Expected Parameters length to be 3, got %d", len(instance.Parameters)) + } } // TestFunctionToolRoundtrip1 tests load -> save -> load produces equivalent data @@ -346,6 +513,9 @@ func TestFunctionToolRoundtrip1(t *testing.T) { if reloaded.Strict == nil || *reloaded.Strict != true { t.Errorf(`Expected Strict to be true, got %v`, reloaded.Strict) } + if len(reloaded.Parameters) != 3 { + t.Fatalf("Expected Parameters length to be 3, got %d", len(reloaded.Parameters)) + } } // TestFunctionToolToJSON1 tests that ToJSON produces valid JSON @@ -392,6 +562,20 @@ func TestFunctionToolToJSON1(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadFunctionTool(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Kind != "function" { + t.Errorf(`Expected Kind to be "function", got %v`, reloaded.Kind) + } + if reloaded.Strict == nil || *reloaded.Strict != true { + t.Errorf(`Expected Strict to be true, got %v`, reloaded.Strict) + } + if len(reloaded.Parameters) != 3 { + t.Fatalf("Expected Parameters length to be 3, got %d", len(reloaded.Parameters)) + } } // TestFunctionToolToYAML1 tests that ToYAML produces valid YAML @@ -438,4 +622,25 @@ func TestFunctionToolToYAML1(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadFunctionTool(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Kind != "function" { + t.Errorf(`Expected Kind to be "function", got %v`, reloaded.Kind) + } + if reloaded.Strict == nil || *reloaded.Strict != true { + t.Errorf(`Expected Strict to be true, got %v`, reloaded.Strict) + } + if len(reloaded.Parameters) != 3 { + t.Fatalf("Expected Parameters length to be 3, got %d", len(reloaded.Parameters)) + } +} + +// TestFunctionToolFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestFunctionToolFromJSONInvalid(t *testing.T) { + if _, err := prompty.FunctionToolFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/guardrail_result.go b/runtime/go/prompty/model/guardrail_result.go index 53a4e83f..9373ec97 100644 --- a/runtime/go/prompty/model/guardrail_result.go +++ b/runtime/go/prompty/model/guardrail_result.go @@ -42,7 +42,7 @@ func LoadGuardrailResult(data interface{}, ctx *LoadContext) (GuardrailResult, e } // Save serializes GuardrailResult to map[string]interface{} -func (obj *GuardrailResult) Save(ctx *SaveContext) map[string]interface{} { +func (obj GuardrailResult) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["allowed"] = obj.Allowed if obj.Reason != nil { @@ -70,11 +70,7 @@ func (obj *GuardrailResult) ToJSON() (string, error) { func (obj *GuardrailResult) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates GuardrailResult from JSON string diff --git a/runtime/go/prompty/model/guardrail_result_test.go b/runtime/go/prompty/model/guardrail_result_test.go index 0a895378..cf59b9fa 100644 --- a/runtime/go/prompty/model/guardrail_result_test.go +++ b/runtime/go/prompty/model/guardrail_result_test.go @@ -63,6 +63,47 @@ reason: Content is safe } } +// TestGuardrailResultFromJSON tests loading GuardrailResult through the generated JSON helper +func TestGuardrailResultFromJSON(t *testing.T) { + jsonData := ` +{ + "allowed": true, + "reason": "Content is safe" +} +` + + instance, err := prompty.GuardrailResultFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load GuardrailResult from JSON helper: %v", err) + } + if instance.Allowed != true { + t.Errorf(`Expected Allowed to be true, got %v`, instance.Allowed) + } + if instance.Reason == nil || *instance.Reason != "Content is safe" { + t.Errorf(`Expected Reason to be "Content is safe", got %v`, instance.Reason) + } +} + +// TestGuardrailResultFromYAML tests loading GuardrailResult through the generated YAML helper +func TestGuardrailResultFromYAML(t *testing.T) { + yamlData := ` +allowed: true +reason: Content is safe + +` + + instance, err := prompty.GuardrailResultFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load GuardrailResult from YAML helper: %v", err) + } + if instance.Allowed != true { + t.Errorf(`Expected Allowed to be true, got %v`, instance.Allowed) + } + if instance.Reason == nil || *instance.Reason != "Content is safe" { + t.Errorf(`Expected Reason to be "Content is safe", got %v`, instance.Reason) + } +} + // TestGuardrailResultRoundtrip tests load -> save -> load produces equivalent data func TestGuardrailResultRoundtrip(t *testing.T) { jsonData := ` @@ -123,6 +164,17 @@ func TestGuardrailResultToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadGuardrailResult(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Allowed != true { + t.Errorf(`Expected Allowed to be true, got %v`, reloaded.Allowed) + } + if reloaded.Reason == nil || *reloaded.Reason != "Content is safe" { + t.Errorf(`Expected Reason to be "Content is safe", got %v`, reloaded.Reason) + } } // TestGuardrailResultToYAML tests that ToYAML produces valid YAML @@ -152,4 +204,22 @@ func TestGuardrailResultToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadGuardrailResult(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Allowed != true { + t.Errorf(`Expected Allowed to be true, got %v`, reloaded.Allowed) + } + if reloaded.Reason == nil || *reloaded.Reason != "Content is safe" { + t.Errorf(`Expected Reason to be "Content is safe", got %v`, reloaded.Reason) + } +} + +// TestGuardrailResultFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestGuardrailResultFromJSONInvalid(t *testing.T) { + if _, err := prompty.GuardrailResultFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/harness_context.go b/runtime/go/prompty/model/harness_context.go index 648a78bb..adc63ec7 100644 --- a/runtime/go/prompty/model/harness_context.go +++ b/runtime/go/prompty/model/harness_context.go @@ -45,7 +45,7 @@ func LoadHarnessContext(data interface{}, ctx *LoadContext) (HarnessContext, err } // Save serializes HarnessContext to map[string]interface{} -func (obj *HarnessContext) Save(ctx *SaveContext) map[string]interface{} { +func (obj HarnessContext) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) if obj.Cwd != nil { result["cwd"] = *obj.Cwd @@ -75,11 +75,7 @@ func (obj *HarnessContext) ToJSON() (string, error) { func (obj *HarnessContext) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates HarnessContext from JSON string diff --git a/runtime/go/prompty/model/harness_context_test.go b/runtime/go/prompty/model/harness_context_test.go index 329da9b7..ad293fa5 100644 --- a/runtime/go/prompty/model/harness_context_test.go +++ b/runtime/go/prompty/model/harness_context_test.go @@ -63,6 +63,47 @@ gitRoot: /workspace/project } } +// TestHarnessContextFromJSON tests loading HarnessContext through the generated JSON helper +func TestHarnessContextFromJSON(t *testing.T) { + jsonData := ` +{ + "cwd": "/workspace/project", + "gitRoot": "/workspace/project" +} +` + + instance, err := prompty.HarnessContextFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load HarnessContext from JSON helper: %v", err) + } + if instance.Cwd == nil || *instance.Cwd != "/workspace/project" { + t.Errorf(`Expected Cwd to be "/workspace/project", got %v`, instance.Cwd) + } + if instance.GitRoot == nil || *instance.GitRoot != "/workspace/project" { + t.Errorf(`Expected GitRoot to be "/workspace/project", got %v`, instance.GitRoot) + } +} + +// TestHarnessContextFromYAML tests loading HarnessContext through the generated YAML helper +func TestHarnessContextFromYAML(t *testing.T) { + yamlData := ` +cwd: /workspace/project +gitRoot: /workspace/project + +` + + instance, err := prompty.HarnessContextFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load HarnessContext from YAML helper: %v", err) + } + if instance.Cwd == nil || *instance.Cwd != "/workspace/project" { + t.Errorf(`Expected Cwd to be "/workspace/project", got %v`, instance.Cwd) + } + if instance.GitRoot == nil || *instance.GitRoot != "/workspace/project" { + t.Errorf(`Expected GitRoot to be "/workspace/project", got %v`, instance.GitRoot) + } +} + // TestHarnessContextRoundtrip tests load -> save -> load produces equivalent data func TestHarnessContextRoundtrip(t *testing.T) { jsonData := ` @@ -123,6 +164,17 @@ func TestHarnessContextToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadHarnessContext(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Cwd == nil || *reloaded.Cwd != "/workspace/project" { + t.Errorf(`Expected Cwd to be "/workspace/project", got %v`, reloaded.Cwd) + } + if reloaded.GitRoot == nil || *reloaded.GitRoot != "/workspace/project" { + t.Errorf(`Expected GitRoot to be "/workspace/project", got %v`, reloaded.GitRoot) + } } // TestHarnessContextToYAML tests that ToYAML produces valid YAML @@ -152,4 +204,22 @@ func TestHarnessContextToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadHarnessContext(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Cwd == nil || *reloaded.Cwd != "/workspace/project" { + t.Errorf(`Expected Cwd to be "/workspace/project", got %v`, reloaded.Cwd) + } + if reloaded.GitRoot == nil || *reloaded.GitRoot != "/workspace/project" { + t.Errorf(`Expected GitRoot to be "/workspace/project", got %v`, reloaded.GitRoot) + } +} + +// TestHarnessContextFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestHarnessContextFromJSONInvalid(t *testing.T) { + if _, err := prompty.HarnessContextFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/hook_end_payload.go b/runtime/go/prompty/model/hook_end_payload.go index cd42a504..f7eee827 100644 --- a/runtime/go/prompty/model/hook_end_payload.go +++ b/runtime/go/prompty/model/hook_end_payload.go @@ -87,7 +87,7 @@ func LoadHookEndPayload(data interface{}, ctx *LoadContext) (HookEndPayload, err } // Save serializes HookEndPayload to map[string]interface{} -func (obj *HookEndPayload) Save(ctx *SaveContext) map[string]interface{} { +func (obj HookEndPayload) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["hookInvocationId"] = obj.HookInvocationId result["hookType"] = obj.HookType @@ -126,11 +126,7 @@ func (obj *HookEndPayload) ToJSON() (string, error) { func (obj *HookEndPayload) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates HookEndPayload from JSON string diff --git a/runtime/go/prompty/model/hook_end_payload_test.go b/runtime/go/prompty/model/hook_end_payload_test.go index f112a207..d3d4fa1d 100644 --- a/runtime/go/prompty/model/hook_end_payload_test.go +++ b/runtime/go/prompty/model/hook_end_payload_test.go @@ -87,6 +87,71 @@ error: hook failed } } +// TestHookEndPayloadFromJSON tests loading HookEndPayload through the generated JSON helper +func TestHookEndPayloadFromJSON(t *testing.T) { + jsonData := ` +{ + "hookInvocationId": "hook_abc123", + "hookType": "preToolUse", + "success": true, + "durationMs": 12, + "error": "hook failed" +} +` + + instance, err := prompty.HookEndPayloadFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load HookEndPayload from JSON helper: %v", err) + } + if instance.HookInvocationId != "hook_abc123" { + t.Errorf(`Expected HookInvocationId to be "hook_abc123", got %v`, instance.HookInvocationId) + } + if instance.HookType != "preToolUse" { + t.Errorf(`Expected HookType to be "preToolUse", got %v`, instance.HookType) + } + if instance.Success != true { + t.Errorf(`Expected Success to be true, got %v`, instance.Success) + } + if instance.DurationMs == nil || *instance.DurationMs != 12 { + t.Errorf(`Expected DurationMs to be 12, got %v`, instance.DurationMs) + } + if instance.Error == nil || *instance.Error != "hook failed" { + t.Errorf(`Expected Error to be "hook failed", got %v`, instance.Error) + } +} + +// TestHookEndPayloadFromYAML tests loading HookEndPayload through the generated YAML helper +func TestHookEndPayloadFromYAML(t *testing.T) { + yamlData := ` +hookInvocationId: hook_abc123 +hookType: preToolUse +success: true +durationMs: 12 +error: hook failed + +` + + instance, err := prompty.HookEndPayloadFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load HookEndPayload from YAML helper: %v", err) + } + if instance.HookInvocationId != "hook_abc123" { + t.Errorf(`Expected HookInvocationId to be "hook_abc123", got %v`, instance.HookInvocationId) + } + if instance.HookType != "preToolUse" { + t.Errorf(`Expected HookType to be "preToolUse", got %v`, instance.HookType) + } + if instance.Success != true { + t.Errorf(`Expected Success to be true, got %v`, instance.Success) + } + if instance.DurationMs == nil || *instance.DurationMs != 12 { + t.Errorf(`Expected DurationMs to be 12, got %v`, instance.DurationMs) + } + if instance.Error == nil || *instance.Error != "hook failed" { + t.Errorf(`Expected Error to be "hook failed", got %v`, instance.Error) + } +} + // TestHookEndPayloadRoundtrip tests load -> save -> load produces equivalent data func TestHookEndPayloadRoundtrip(t *testing.T) { jsonData := ` @@ -162,6 +227,26 @@ func TestHookEndPayloadToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadHookEndPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.HookInvocationId != "hook_abc123" { + t.Errorf(`Expected HookInvocationId to be "hook_abc123", got %v`, reloaded.HookInvocationId) + } + if reloaded.HookType != "preToolUse" { + t.Errorf(`Expected HookType to be "preToolUse", got %v`, reloaded.HookType) + } + if reloaded.Success != true { + t.Errorf(`Expected Success to be true, got %v`, reloaded.Success) + } + if reloaded.DurationMs == nil || *reloaded.DurationMs != 12 { + t.Errorf(`Expected DurationMs to be 12, got %v`, reloaded.DurationMs) + } + if reloaded.Error == nil || *reloaded.Error != "hook failed" { + t.Errorf(`Expected Error to be "hook failed", got %v`, reloaded.Error) + } } // TestHookEndPayloadToYAML tests that ToYAML produces valid YAML @@ -194,4 +279,31 @@ func TestHookEndPayloadToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadHookEndPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.HookInvocationId != "hook_abc123" { + t.Errorf(`Expected HookInvocationId to be "hook_abc123", got %v`, reloaded.HookInvocationId) + } + if reloaded.HookType != "preToolUse" { + t.Errorf(`Expected HookType to be "preToolUse", got %v`, reloaded.HookType) + } + if reloaded.Success != true { + t.Errorf(`Expected Success to be true, got %v`, reloaded.Success) + } + if reloaded.DurationMs == nil || *reloaded.DurationMs != 12 { + t.Errorf(`Expected DurationMs to be 12, got %v`, reloaded.DurationMs) + } + if reloaded.Error == nil || *reloaded.Error != "hook failed" { + t.Errorf(`Expected Error to be "hook failed", got %v`, reloaded.Error) + } +} + +// TestHookEndPayloadFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestHookEndPayloadFromJSONInvalid(t *testing.T) { + if _, err := prompty.HookEndPayloadFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/hook_start_payload.go b/runtime/go/prompty/model/hook_start_payload.go index 868db2cd..03559e20 100644 --- a/runtime/go/prompty/model/hook_start_payload.go +++ b/runtime/go/prompty/model/hook_start_payload.go @@ -61,7 +61,7 @@ func LoadHookStartPayload(data interface{}, ctx *LoadContext) (HookStartPayload, } // Save serializes HookStartPayload to map[string]interface{} -func (obj *HookStartPayload) Save(ctx *SaveContext) map[string]interface{} { +func (obj HookStartPayload) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["hookInvocationId"] = obj.HookInvocationId result["hookType"] = obj.HookType @@ -93,11 +93,7 @@ func (obj *HookStartPayload) ToJSON() (string, error) { func (obj *HookStartPayload) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates HookStartPayload from JSON string diff --git a/runtime/go/prompty/model/hook_start_payload_test.go b/runtime/go/prompty/model/hook_start_payload_test.go index ace58f8c..108aa7c4 100644 --- a/runtime/go/prompty/model/hook_start_payload_test.go +++ b/runtime/go/prompty/model/hook_start_payload_test.go @@ -63,6 +63,47 @@ hookType: preToolUse } } +// TestHookStartPayloadFromJSON tests loading HookStartPayload through the generated JSON helper +func TestHookStartPayloadFromJSON(t *testing.T) { + jsonData := ` +{ + "hookInvocationId": "hook_abc123", + "hookType": "preToolUse" +} +` + + instance, err := prompty.HookStartPayloadFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load HookStartPayload from JSON helper: %v", err) + } + if instance.HookInvocationId != "hook_abc123" { + t.Errorf(`Expected HookInvocationId to be "hook_abc123", got %v`, instance.HookInvocationId) + } + if instance.HookType != "preToolUse" { + t.Errorf(`Expected HookType to be "preToolUse", got %v`, instance.HookType) + } +} + +// TestHookStartPayloadFromYAML tests loading HookStartPayload through the generated YAML helper +func TestHookStartPayloadFromYAML(t *testing.T) { + yamlData := ` +hookInvocationId: hook_abc123 +hookType: preToolUse + +` + + instance, err := prompty.HookStartPayloadFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load HookStartPayload from YAML helper: %v", err) + } + if instance.HookInvocationId != "hook_abc123" { + t.Errorf(`Expected HookInvocationId to be "hook_abc123", got %v`, instance.HookInvocationId) + } + if instance.HookType != "preToolUse" { + t.Errorf(`Expected HookType to be "preToolUse", got %v`, instance.HookType) + } +} + // TestHookStartPayloadRoundtrip tests load -> save -> load produces equivalent data func TestHookStartPayloadRoundtrip(t *testing.T) { jsonData := ` @@ -123,6 +164,17 @@ func TestHookStartPayloadToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadHookStartPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.HookInvocationId != "hook_abc123" { + t.Errorf(`Expected HookInvocationId to be "hook_abc123", got %v`, reloaded.HookInvocationId) + } + if reloaded.HookType != "preToolUse" { + t.Errorf(`Expected HookType to be "preToolUse", got %v`, reloaded.HookType) + } } // TestHookStartPayloadToYAML tests that ToYAML produces valid YAML @@ -152,4 +204,22 @@ func TestHookStartPayloadToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadHookStartPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.HookInvocationId != "hook_abc123" { + t.Errorf(`Expected HookInvocationId to be "hook_abc123", got %v`, reloaded.HookInvocationId) + } + if reloaded.HookType != "preToolUse" { + t.Errorf(`Expected HookType to be "preToolUse", got %v`, reloaded.HookType) + } +} + +// TestHookStartPayloadFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestHookStartPayloadFromJSONInvalid(t *testing.T) { + if _, err := prompty.HookStartPayloadFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/host_tool_request.go b/runtime/go/prompty/model/host_tool_request.go index 1e69e5a6..6aff94ad 100644 --- a/runtime/go/prompty/model/host_tool_request.go +++ b/runtime/go/prompty/model/host_tool_request.go @@ -52,7 +52,7 @@ func LoadHostToolRequest(data interface{}, ctx *LoadContext) (HostToolRequest, e } // Save serializes HostToolRequest to map[string]interface{} -func (obj *HostToolRequest) Save(ctx *SaveContext) map[string]interface{} { +func (obj HostToolRequest) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) if obj.RequestId != nil { result["requestId"] = *obj.RequestId @@ -86,11 +86,7 @@ func (obj *HostToolRequest) ToJSON() (string, error) { func (obj *HostToolRequest) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates HostToolRequest from JSON string diff --git a/runtime/go/prompty/model/host_tool_request_test.go b/runtime/go/prompty/model/host_tool_request_test.go index 456a422e..6d246d50 100644 --- a/runtime/go/prompty/model/host_tool_request_test.go +++ b/runtime/go/prompty/model/host_tool_request_test.go @@ -79,6 +79,63 @@ workingDirectory: /workspace/project } } +// TestHostToolRequestFromJSON tests loading HostToolRequest through the generated JSON helper +func TestHostToolRequestFromJSON(t *testing.T) { + jsonData := ` +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "workingDirectory": "/workspace/project" +} +` + + instance, err := prompty.HostToolRequestFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load HostToolRequest from JSON helper: %v", err) + } + if instance.RequestId == nil || *instance.RequestId != "exec_abc123" { + t.Errorf(`Expected RequestId to be "exec_abc123", got %v`, instance.RequestId) + } + if instance.ToolCallId == nil || *instance.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, instance.ToolCallId) + } + if instance.ToolName != "powershell" { + t.Errorf(`Expected ToolName to be "powershell", got %v`, instance.ToolName) + } + if instance.WorkingDirectory == nil || *instance.WorkingDirectory != "/workspace/project" { + t.Errorf(`Expected WorkingDirectory to be "/workspace/project", got %v`, instance.WorkingDirectory) + } +} + +// TestHostToolRequestFromYAML tests loading HostToolRequest through the generated YAML helper +func TestHostToolRequestFromYAML(t *testing.T) { + yamlData := ` +requestId: exec_abc123 +toolCallId: call_abc123 +toolName: powershell +workingDirectory: /workspace/project + +` + + instance, err := prompty.HostToolRequestFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load HostToolRequest from YAML helper: %v", err) + } + if instance.RequestId == nil || *instance.RequestId != "exec_abc123" { + t.Errorf(`Expected RequestId to be "exec_abc123", got %v`, instance.RequestId) + } + if instance.ToolCallId == nil || *instance.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, instance.ToolCallId) + } + if instance.ToolName != "powershell" { + t.Errorf(`Expected ToolName to be "powershell", got %v`, instance.ToolName) + } + if instance.WorkingDirectory == nil || *instance.WorkingDirectory != "/workspace/project" { + t.Errorf(`Expected WorkingDirectory to be "/workspace/project", got %v`, instance.WorkingDirectory) + } +} + // TestHostToolRequestRoundtrip tests load -> save -> load produces equivalent data func TestHostToolRequestRoundtrip(t *testing.T) { jsonData := ` @@ -149,6 +206,23 @@ func TestHostToolRequestToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadHostToolRequest(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.RequestId == nil || *reloaded.RequestId != "exec_abc123" { + t.Errorf(`Expected RequestId to be "exec_abc123", got %v`, reloaded.RequestId) + } + if reloaded.ToolCallId == nil || *reloaded.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, reloaded.ToolCallId) + } + if reloaded.ToolName != "powershell" { + t.Errorf(`Expected ToolName to be "powershell", got %v`, reloaded.ToolName) + } + if reloaded.WorkingDirectory == nil || *reloaded.WorkingDirectory != "/workspace/project" { + t.Errorf(`Expected WorkingDirectory to be "/workspace/project", got %v`, reloaded.WorkingDirectory) + } } // TestHostToolRequestToYAML tests that ToYAML produces valid YAML @@ -180,4 +254,28 @@ func TestHostToolRequestToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadHostToolRequest(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.RequestId == nil || *reloaded.RequestId != "exec_abc123" { + t.Errorf(`Expected RequestId to be "exec_abc123", got %v`, reloaded.RequestId) + } + if reloaded.ToolCallId == nil || *reloaded.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, reloaded.ToolCallId) + } + if reloaded.ToolName != "powershell" { + t.Errorf(`Expected ToolName to be "powershell", got %v`, reloaded.ToolName) + } + if reloaded.WorkingDirectory == nil || *reloaded.WorkingDirectory != "/workspace/project" { + t.Errorf(`Expected WorkingDirectory to be "/workspace/project", got %v`, reloaded.WorkingDirectory) + } +} + +// TestHostToolRequestFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestHostToolRequestFromJSONInvalid(t *testing.T) { + if _, err := prompty.HostToolRequestFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/host_tool_result.go b/runtime/go/prompty/model/host_tool_result.go index d0200c8b..e64ee93b 100644 --- a/runtime/go/prompty/model/host_tool_result.go +++ b/runtime/go/prompty/model/host_tool_result.go @@ -92,7 +92,7 @@ func LoadHostToolResult(data interface{}, ctx *LoadContext) (HostToolResult, err } // Save serializes HostToolResult to map[string]interface{} -func (obj *HostToolResult) Save(ctx *SaveContext) map[string]interface{} { +func (obj HostToolResult) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) if obj.RequestId != nil { result["requestId"] = *obj.RequestId @@ -136,11 +136,7 @@ func (obj *HostToolResult) ToJSON() (string, error) { func (obj *HostToolResult) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates HostToolResult from JSON string diff --git a/runtime/go/prompty/model/host_tool_result_test.go b/runtime/go/prompty/model/host_tool_result_test.go index 260ab230..87370ce0 100644 --- a/runtime/go/prompty/model/host_tool_result_test.go +++ b/runtime/go/prompty/model/host_tool_result_test.go @@ -103,6 +103,87 @@ errorKind: timeout } } +// TestHostToolResultFromJSON tests loading HostToolResult through the generated JSON helper +func TestHostToolResultFromJSON(t *testing.T) { + jsonData := ` +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "success": true, + "exitCode": 0, + "durationMs": 250, + "errorKind": "timeout" +} +` + + instance, err := prompty.HostToolResultFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load HostToolResult from JSON helper: %v", err) + } + if instance.RequestId == nil || *instance.RequestId != "exec_abc123" { + t.Errorf(`Expected RequestId to be "exec_abc123", got %v`, instance.RequestId) + } + if instance.ToolCallId == nil || *instance.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, instance.ToolCallId) + } + if instance.ToolName != "powershell" { + t.Errorf(`Expected ToolName to be "powershell", got %v`, instance.ToolName) + } + if instance.Success != true { + t.Errorf(`Expected Success to be true, got %v`, instance.Success) + } + if instance.ExitCode == nil || *instance.ExitCode != 0 { + t.Errorf(`Expected ExitCode to be 0, got %v`, instance.ExitCode) + } + if instance.DurationMs == nil || *instance.DurationMs != 250 { + t.Errorf(`Expected DurationMs to be 250, got %v`, instance.DurationMs) + } + if instance.ErrorKind == nil || *instance.ErrorKind != "timeout" { + t.Errorf(`Expected ErrorKind to be "timeout", got %v`, instance.ErrorKind) + } +} + +// TestHostToolResultFromYAML tests loading HostToolResult through the generated YAML helper +func TestHostToolResultFromYAML(t *testing.T) { + yamlData := ` +requestId: exec_abc123 +toolCallId: call_abc123 +toolName: powershell +success: true +exitCode: 0 +durationMs: 250 +errorKind: timeout + +` + + instance, err := prompty.HostToolResultFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load HostToolResult from YAML helper: %v", err) + } + if instance.RequestId == nil || *instance.RequestId != "exec_abc123" { + t.Errorf(`Expected RequestId to be "exec_abc123", got %v`, instance.RequestId) + } + if instance.ToolCallId == nil || *instance.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, instance.ToolCallId) + } + if instance.ToolName != "powershell" { + t.Errorf(`Expected ToolName to be "powershell", got %v`, instance.ToolName) + } + if instance.Success != true { + t.Errorf(`Expected Success to be true, got %v`, instance.Success) + } + if instance.ExitCode == nil || *instance.ExitCode != 0 { + t.Errorf(`Expected ExitCode to be 0, got %v`, instance.ExitCode) + } + if instance.DurationMs == nil || *instance.DurationMs != 250 { + t.Errorf(`Expected DurationMs to be 250, got %v`, instance.DurationMs) + } + if instance.ErrorKind == nil || *instance.ErrorKind != "timeout" { + t.Errorf(`Expected ErrorKind to be "timeout", got %v`, instance.ErrorKind) + } +} + // TestHostToolResultRoundtrip tests load -> save -> load produces equivalent data func TestHostToolResultRoundtrip(t *testing.T) { jsonData := ` @@ -188,6 +269,32 @@ func TestHostToolResultToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadHostToolResult(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.RequestId == nil || *reloaded.RequestId != "exec_abc123" { + t.Errorf(`Expected RequestId to be "exec_abc123", got %v`, reloaded.RequestId) + } + if reloaded.ToolCallId == nil || *reloaded.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, reloaded.ToolCallId) + } + if reloaded.ToolName != "powershell" { + t.Errorf(`Expected ToolName to be "powershell", got %v`, reloaded.ToolName) + } + if reloaded.Success != true { + t.Errorf(`Expected Success to be true, got %v`, reloaded.Success) + } + if reloaded.ExitCode == nil || *reloaded.ExitCode != 0 { + t.Errorf(`Expected ExitCode to be 0, got %v`, reloaded.ExitCode) + } + if reloaded.DurationMs == nil || *reloaded.DurationMs != 250 { + t.Errorf(`Expected DurationMs to be 250, got %v`, reloaded.DurationMs) + } + if reloaded.ErrorKind == nil || *reloaded.ErrorKind != "timeout" { + t.Errorf(`Expected ErrorKind to be "timeout", got %v`, reloaded.ErrorKind) + } } // TestHostToolResultToYAML tests that ToYAML produces valid YAML @@ -222,4 +329,37 @@ func TestHostToolResultToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadHostToolResult(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.RequestId == nil || *reloaded.RequestId != "exec_abc123" { + t.Errorf(`Expected RequestId to be "exec_abc123", got %v`, reloaded.RequestId) + } + if reloaded.ToolCallId == nil || *reloaded.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, reloaded.ToolCallId) + } + if reloaded.ToolName != "powershell" { + t.Errorf(`Expected ToolName to be "powershell", got %v`, reloaded.ToolName) + } + if reloaded.Success != true { + t.Errorf(`Expected Success to be true, got %v`, reloaded.Success) + } + if reloaded.ExitCode == nil || *reloaded.ExitCode != 0 { + t.Errorf(`Expected ExitCode to be 0, got %v`, reloaded.ExitCode) + } + if reloaded.DurationMs == nil || *reloaded.DurationMs != 250 { + t.Errorf(`Expected DurationMs to be 250, got %v`, reloaded.DurationMs) + } + if reloaded.ErrorKind == nil || *reloaded.ErrorKind != "timeout" { + t.Errorf(`Expected ErrorKind to be "timeout", got %v`, reloaded.ErrorKind) + } +} + +// TestHostToolResultFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestHostToolResultFromJSONInvalid(t *testing.T) { + if _, err := prompty.HostToolResultFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/image_part_test.go b/runtime/go/prompty/model/image_part_test.go index 1d5e2beb..93bc37fb 100644 --- a/runtime/go/prompty/model/image_part_test.go +++ b/runtime/go/prompty/model/image_part_test.go @@ -71,6 +71,55 @@ mediaType: image/png } } +// TestImagePartFromJSON tests loading ImagePart through the generated JSON helper +func TestImagePartFromJSON(t *testing.T) { + jsonData := ` +{ + "source": "https://example.com/image.png", + "detail": "auto", + "mediaType": "image/png" +} +` + + instance, err := prompty.ImagePartFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load ImagePart from JSON helper: %v", err) + } + if instance.Source != "https://example.com/image.png" { + t.Errorf(`Expected Source to be "https://example.com/image.png", got %v`, instance.Source) + } + if instance.Detail == nil || *instance.Detail != "auto" { + t.Errorf(`Expected Detail to be "auto", got %v`, instance.Detail) + } + if instance.MediaType == nil || *instance.MediaType != "image/png" { + t.Errorf(`Expected MediaType to be "image/png", got %v`, instance.MediaType) + } +} + +// TestImagePartFromYAML tests loading ImagePart through the generated YAML helper +func TestImagePartFromYAML(t *testing.T) { + yamlData := ` +source: "https://example.com/image.png" +detail: auto +mediaType: image/png + +` + + instance, err := prompty.ImagePartFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load ImagePart from YAML helper: %v", err) + } + if instance.Source != "https://example.com/image.png" { + t.Errorf(`Expected Source to be "https://example.com/image.png", got %v`, instance.Source) + } + if instance.Detail == nil || *instance.Detail != "auto" { + t.Errorf(`Expected Detail to be "auto", got %v`, instance.Detail) + } + if instance.MediaType == nil || *instance.MediaType != "image/png" { + t.Errorf(`Expected MediaType to be "image/png", got %v`, instance.MediaType) + } +} + // TestImagePartRoundtrip tests load -> save -> load produces equivalent data func TestImagePartRoundtrip(t *testing.T) { jsonData := ` @@ -136,6 +185,20 @@ func TestImagePartToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadImagePart(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Source != "https://example.com/image.png" { + t.Errorf(`Expected Source to be "https://example.com/image.png", got %v`, reloaded.Source) + } + if reloaded.Detail == nil || *reloaded.Detail != "auto" { + t.Errorf(`Expected Detail to be "auto", got %v`, reloaded.Detail) + } + if reloaded.MediaType == nil || *reloaded.MediaType != "image/png" { + t.Errorf(`Expected MediaType to be "image/png", got %v`, reloaded.MediaType) + } } // TestImagePartToYAML tests that ToYAML produces valid YAML @@ -166,4 +229,25 @@ func TestImagePartToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadImagePart(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Source != "https://example.com/image.png" { + t.Errorf(`Expected Source to be "https://example.com/image.png", got %v`, reloaded.Source) + } + if reloaded.Detail == nil || *reloaded.Detail != "auto" { + t.Errorf(`Expected Detail to be "auto", got %v`, reloaded.Detail) + } + if reloaded.MediaType == nil || *reloaded.MediaType != "image/png" { + t.Errorf(`Expected MediaType to be "image/png", got %v`, reloaded.MediaType) + } +} + +// TestImagePartFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestImagePartFromJSONInvalid(t *testing.T) { + if _, err := prompty.ImagePartFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/invoker_error.go b/runtime/go/prompty/model/invoker_error.go index 002016bf..4d784afd 100644 --- a/runtime/go/prompty/model/invoker_error.go +++ b/runtime/go/prompty/model/invoker_error.go @@ -41,7 +41,7 @@ func LoadInvokerError(data interface{}, ctx *LoadContext) (InvokerError, error) } // Save serializes InvokerError to map[string]interface{} -func (obj *InvokerError) Save(ctx *SaveContext) map[string]interface{} { +func (obj InvokerError) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["message"] = obj.Message result["component"] = obj.Component @@ -65,11 +65,7 @@ func (obj *InvokerError) ToJSON() (string, error) { func (obj *InvokerError) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates InvokerError from JSON string diff --git a/runtime/go/prompty/model/invoker_error_test.go b/runtime/go/prompty/model/invoker_error_test.go index 98208aa8..7d8ae6ae 100644 --- a/runtime/go/prompty/model/invoker_error_test.go +++ b/runtime/go/prompty/model/invoker_error_test.go @@ -71,6 +71,55 @@ key: jinja2 } } +// TestInvokerErrorFromJSON tests loading InvokerError through the generated JSON helper +func TestInvokerErrorFromJSON(t *testing.T) { + jsonData := ` +{ + "message": "No renderer registered for key: jinja2", + "component": "renderer", + "key": "jinja2" +} +` + + instance, err := prompty.InvokerErrorFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load InvokerError from JSON helper: %v", err) + } + if instance.Message != "No renderer registered for key: jinja2" { + t.Errorf(`Expected Message to be "No renderer registered for key: jinja2", got %v`, instance.Message) + } + if instance.Component != "renderer" { + t.Errorf(`Expected Component to be "renderer", got %v`, instance.Component) + } + if instance.Key != "jinja2" { + t.Errorf(`Expected Key to be "jinja2", got %v`, instance.Key) + } +} + +// TestInvokerErrorFromYAML tests loading InvokerError through the generated YAML helper +func TestInvokerErrorFromYAML(t *testing.T) { + yamlData := ` +message: "No renderer registered for key: jinja2" +component: renderer +key: jinja2 + +` + + instance, err := prompty.InvokerErrorFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load InvokerError from YAML helper: %v", err) + } + if instance.Message != "No renderer registered for key: jinja2" { + t.Errorf(`Expected Message to be "No renderer registered for key: jinja2", got %v`, instance.Message) + } + if instance.Component != "renderer" { + t.Errorf(`Expected Component to be "renderer", got %v`, instance.Component) + } + if instance.Key != "jinja2" { + t.Errorf(`Expected Key to be "jinja2", got %v`, instance.Key) + } +} + // TestInvokerErrorRoundtrip tests load -> save -> load produces equivalent data func TestInvokerErrorRoundtrip(t *testing.T) { jsonData := ` @@ -136,6 +185,20 @@ func TestInvokerErrorToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadInvokerError(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Message != "No renderer registered for key: jinja2" { + t.Errorf(`Expected Message to be "No renderer registered for key: jinja2", got %v`, reloaded.Message) + } + if reloaded.Component != "renderer" { + t.Errorf(`Expected Component to be "renderer", got %v`, reloaded.Component) + } + if reloaded.Key != "jinja2" { + t.Errorf(`Expected Key to be "jinja2", got %v`, reloaded.Key) + } } // TestInvokerErrorToYAML tests that ToYAML produces valid YAML @@ -166,4 +229,25 @@ func TestInvokerErrorToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadInvokerError(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Message != "No renderer registered for key: jinja2" { + t.Errorf(`Expected Message to be "No renderer registered for key: jinja2", got %v`, reloaded.Message) + } + if reloaded.Component != "renderer" { + t.Errorf(`Expected Component to be "renderer", got %v`, reloaded.Component) + } + if reloaded.Key != "jinja2" { + t.Errorf(`Expected Key to be "jinja2", got %v`, reloaded.Key) + } +} + +// TestInvokerErrorFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestInvokerErrorFromJSONInvalid(t *testing.T) { + if _, err := prompty.InvokerErrorFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/llm_complete_payload.go b/runtime/go/prompty/model/llm_complete_payload.go index a9102200..d2079b2e 100644 --- a/runtime/go/prompty/model/llm_complete_payload.go +++ b/runtime/go/prompty/model/llm_complete_payload.go @@ -61,7 +61,7 @@ func LoadLlmCompletePayload(data interface{}, ctx *LoadContext) (LlmCompletePayl } // Save serializes LlmCompletePayload to map[string]interface{} -func (obj *LlmCompletePayload) Save(ctx *SaveContext) map[string]interface{} { +func (obj LlmCompletePayload) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) if obj.RequestId != nil { result["requestId"] = *obj.RequestId @@ -94,11 +94,7 @@ func (obj *LlmCompletePayload) ToJSON() (string, error) { func (obj *LlmCompletePayload) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates LlmCompletePayload from JSON string diff --git a/runtime/go/prompty/model/llm_complete_payload_test.go b/runtime/go/prompty/model/llm_complete_payload_test.go index 6c861e04..7836064e 100644 --- a/runtime/go/prompty/model/llm_complete_payload_test.go +++ b/runtime/go/prompty/model/llm_complete_payload_test.go @@ -71,6 +71,55 @@ durationMs: 820 } } +// TestLlmCompletePayloadFromJSON tests loading LlmCompletePayload through the generated JSON helper +func TestLlmCompletePayloadFromJSON(t *testing.T) { + jsonData := ` +{ + "requestId": "req_abc123", + "serviceRequestId": "srv_abc123", + "durationMs": 820 +} +` + + instance, err := prompty.LlmCompletePayloadFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load LlmCompletePayload from JSON helper: %v", err) + } + if instance.RequestId == nil || *instance.RequestId != "req_abc123" { + t.Errorf(`Expected RequestId to be "req_abc123", got %v`, instance.RequestId) + } + if instance.ServiceRequestId == nil || *instance.ServiceRequestId != "srv_abc123" { + t.Errorf(`Expected ServiceRequestId to be "srv_abc123", got %v`, instance.ServiceRequestId) + } + if instance.DurationMs == nil || *instance.DurationMs != 820 { + t.Errorf(`Expected DurationMs to be 820, got %v`, instance.DurationMs) + } +} + +// TestLlmCompletePayloadFromYAML tests loading LlmCompletePayload through the generated YAML helper +func TestLlmCompletePayloadFromYAML(t *testing.T) { + yamlData := ` +requestId: req_abc123 +serviceRequestId: srv_abc123 +durationMs: 820 + +` + + instance, err := prompty.LlmCompletePayloadFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load LlmCompletePayload from YAML helper: %v", err) + } + if instance.RequestId == nil || *instance.RequestId != "req_abc123" { + t.Errorf(`Expected RequestId to be "req_abc123", got %v`, instance.RequestId) + } + if instance.ServiceRequestId == nil || *instance.ServiceRequestId != "srv_abc123" { + t.Errorf(`Expected ServiceRequestId to be "srv_abc123", got %v`, instance.ServiceRequestId) + } + if instance.DurationMs == nil || *instance.DurationMs != 820 { + t.Errorf(`Expected DurationMs to be 820, got %v`, instance.DurationMs) + } +} + // TestLlmCompletePayloadRoundtrip tests load -> save -> load produces equivalent data func TestLlmCompletePayloadRoundtrip(t *testing.T) { jsonData := ` @@ -136,6 +185,20 @@ func TestLlmCompletePayloadToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadLlmCompletePayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.RequestId == nil || *reloaded.RequestId != "req_abc123" { + t.Errorf(`Expected RequestId to be "req_abc123", got %v`, reloaded.RequestId) + } + if reloaded.ServiceRequestId == nil || *reloaded.ServiceRequestId != "srv_abc123" { + t.Errorf(`Expected ServiceRequestId to be "srv_abc123", got %v`, reloaded.ServiceRequestId) + } + if reloaded.DurationMs == nil || *reloaded.DurationMs != 820 { + t.Errorf(`Expected DurationMs to be 820, got %v`, reloaded.DurationMs) + } } // TestLlmCompletePayloadToYAML tests that ToYAML produces valid YAML @@ -166,4 +229,25 @@ func TestLlmCompletePayloadToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadLlmCompletePayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.RequestId == nil || *reloaded.RequestId != "req_abc123" { + t.Errorf(`Expected RequestId to be "req_abc123", got %v`, reloaded.RequestId) + } + if reloaded.ServiceRequestId == nil || *reloaded.ServiceRequestId != "srv_abc123" { + t.Errorf(`Expected ServiceRequestId to be "srv_abc123", got %v`, reloaded.ServiceRequestId) + } + if reloaded.DurationMs == nil || *reloaded.DurationMs != 820 { + t.Errorf(`Expected DurationMs to be 820, got %v`, reloaded.DurationMs) + } +} + +// TestLlmCompletePayloadFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestLlmCompletePayloadFromJSONInvalid(t *testing.T) { + if _, err := prompty.LlmCompletePayloadFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/llm_start_payload.go b/runtime/go/prompty/model/llm_start_payload.go index 3422ecfe..5f275694 100644 --- a/runtime/go/prompty/model/llm_start_payload.go +++ b/runtime/go/prompty/model/llm_start_payload.go @@ -67,7 +67,7 @@ func LoadLlmStartPayload(data interface{}, ctx *LoadContext) (LlmStartPayload, e } // Save serializes LlmStartPayload to map[string]interface{} -func (obj *LlmStartPayload) Save(ctx *SaveContext) map[string]interface{} { +func (obj LlmStartPayload) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) if obj.Provider != nil { result["provider"] = *obj.Provider @@ -100,11 +100,7 @@ func (obj *LlmStartPayload) ToJSON() (string, error) { func (obj *LlmStartPayload) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates LlmStartPayload from JSON string diff --git a/runtime/go/prompty/model/llm_start_payload_test.go b/runtime/go/prompty/model/llm_start_payload_test.go index ab1f61b1..38cecf57 100644 --- a/runtime/go/prompty/model/llm_start_payload_test.go +++ b/runtime/go/prompty/model/llm_start_payload_test.go @@ -79,6 +79,63 @@ attempt: 0 } } +// TestLlmStartPayloadFromJSON tests loading LlmStartPayload through the generated JSON helper +func TestLlmStartPayloadFromJSON(t *testing.T) { + jsonData := ` +{ + "provider": "openai", + "modelId": "gpt-4o-mini", + "messageCount": 4, + "attempt": 0 +} +` + + instance, err := prompty.LlmStartPayloadFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load LlmStartPayload from JSON helper: %v", err) + } + if instance.Provider == nil || *instance.Provider != "openai" { + t.Errorf(`Expected Provider to be "openai", got %v`, instance.Provider) + } + if instance.ModelId == nil || *instance.ModelId != "gpt-4o-mini" { + t.Errorf(`Expected ModelId to be "gpt-4o-mini", got %v`, instance.ModelId) + } + if instance.MessageCount == nil || *instance.MessageCount != 4 { + t.Errorf(`Expected MessageCount to be 4, got %v`, instance.MessageCount) + } + if instance.Attempt == nil || *instance.Attempt != 0 { + t.Errorf(`Expected Attempt to be 0, got %v`, instance.Attempt) + } +} + +// TestLlmStartPayloadFromYAML tests loading LlmStartPayload through the generated YAML helper +func TestLlmStartPayloadFromYAML(t *testing.T) { + yamlData := ` +provider: openai +modelId: gpt-4o-mini +messageCount: 4 +attempt: 0 + +` + + instance, err := prompty.LlmStartPayloadFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load LlmStartPayload from YAML helper: %v", err) + } + if instance.Provider == nil || *instance.Provider != "openai" { + t.Errorf(`Expected Provider to be "openai", got %v`, instance.Provider) + } + if instance.ModelId == nil || *instance.ModelId != "gpt-4o-mini" { + t.Errorf(`Expected ModelId to be "gpt-4o-mini", got %v`, instance.ModelId) + } + if instance.MessageCount == nil || *instance.MessageCount != 4 { + t.Errorf(`Expected MessageCount to be 4, got %v`, instance.MessageCount) + } + if instance.Attempt == nil || *instance.Attempt != 0 { + t.Errorf(`Expected Attempt to be 0, got %v`, instance.Attempt) + } +} + // TestLlmStartPayloadRoundtrip tests load -> save -> load produces equivalent data func TestLlmStartPayloadRoundtrip(t *testing.T) { jsonData := ` @@ -149,6 +206,23 @@ func TestLlmStartPayloadToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadLlmStartPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Provider == nil || *reloaded.Provider != "openai" { + t.Errorf(`Expected Provider to be "openai", got %v`, reloaded.Provider) + } + if reloaded.ModelId == nil || *reloaded.ModelId != "gpt-4o-mini" { + t.Errorf(`Expected ModelId to be "gpt-4o-mini", got %v`, reloaded.ModelId) + } + if reloaded.MessageCount == nil || *reloaded.MessageCount != 4 { + t.Errorf(`Expected MessageCount to be 4, got %v`, reloaded.MessageCount) + } + if reloaded.Attempt == nil || *reloaded.Attempt != 0 { + t.Errorf(`Expected Attempt to be 0, got %v`, reloaded.Attempt) + } } // TestLlmStartPayloadToYAML tests that ToYAML produces valid YAML @@ -180,4 +254,28 @@ func TestLlmStartPayloadToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadLlmStartPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Provider == nil || *reloaded.Provider != "openai" { + t.Errorf(`Expected Provider to be "openai", got %v`, reloaded.Provider) + } + if reloaded.ModelId == nil || *reloaded.ModelId != "gpt-4o-mini" { + t.Errorf(`Expected ModelId to be "gpt-4o-mini", got %v`, reloaded.ModelId) + } + if reloaded.MessageCount == nil || *reloaded.MessageCount != 4 { + t.Errorf(`Expected MessageCount to be 4, got %v`, reloaded.MessageCount) + } + if reloaded.Attempt == nil || *reloaded.Attempt != 0 { + t.Errorf(`Expected Attempt to be 0, got %v`, reloaded.Attempt) + } +} + +// TestLlmStartPayloadFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestLlmStartPayloadFromJSONInvalid(t *testing.T) { + if _, err := prompty.LlmStartPayloadFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/mcp_approval_mode.go b/runtime/go/prompty/model/mcp_approval_mode.go index f08724cc..ba5e468b 100644 --- a/runtime/go/prompty/model/mcp_approval_mode.go +++ b/runtime/go/prompty/model/mcp_approval_mode.go @@ -46,19 +46,25 @@ func LoadMcpApprovalMode(data interface{}, ctx *LoadContext) (McpApprovalMode, e result.Kind = mcpApprovalModeKind(val.(string)) } if val, ok := m["alwaysRequireApprovalTools"]; ok && val != nil { - if arr, ok := val.([]interface{}); ok { + switch arr := val.(type) { + case []interface{}: result.AlwaysRequireApprovalTools = make([]string, len(arr)) for i, v := range arr { result.AlwaysRequireApprovalTools[i] = v.(string) } + case []string: + result.AlwaysRequireApprovalTools = arr } } if val, ok := m["neverRequireApprovalTools"]; ok && val != nil { - if arr, ok := val.([]interface{}); ok { + switch arr := val.(type) { + case []interface{}: result.NeverRequireApprovalTools = make([]string, len(arr)) for i, v := range arr { result.NeverRequireApprovalTools[i] = v.(string) } + case []string: + result.NeverRequireApprovalTools = arr } } } @@ -67,7 +73,7 @@ func LoadMcpApprovalMode(data interface{}, ctx *LoadContext) (McpApprovalMode, e } // Save serializes McpApprovalMode to map[string]interface{} -func (obj *McpApprovalMode) Save(ctx *SaveContext) map[string]interface{} { +func (obj McpApprovalMode) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["kind"] = string(obj.Kind) result["alwaysRequireApprovalTools"] = obj.AlwaysRequireApprovalTools @@ -91,11 +97,7 @@ func (obj *McpApprovalMode) ToJSON() (string, error) { func (obj *McpApprovalMode) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates McpApprovalMode from JSON string diff --git a/runtime/go/prompty/model/mcp_approval_mode_test.go b/runtime/go/prompty/model/mcp_approval_mode_test.go index c3318e97..7662e204 100644 --- a/runtime/go/prompty/model/mcp_approval_mode_test.go +++ b/runtime/go/prompty/model/mcp_approval_mode_test.go @@ -38,6 +38,18 @@ func TestMcpApprovalModeLoadJSON(t *testing.T) { if instance.Kind != "never" { t.Errorf(`Expected Kind to be "never", got %v`, instance.Kind) } + if len(instance.AlwaysRequireApprovalTools) != 1 { + t.Fatalf("Expected AlwaysRequireApprovalTools length to be 1, got %d", len(instance.AlwaysRequireApprovalTools)) + } + if instance.AlwaysRequireApprovalTools[0] != "operation1" { + t.Errorf(`Expected AlwaysRequireApprovalTools[0] to be "operation1", got %v`, instance.AlwaysRequireApprovalTools[0]) + } + if len(instance.NeverRequireApprovalTools) != 1 { + t.Fatalf("Expected NeverRequireApprovalTools length to be 1, got %d", len(instance.NeverRequireApprovalTools)) + } + if instance.NeverRequireApprovalTools[0] != "operation2" { + t.Errorf(`Expected NeverRequireApprovalTools[0] to be "operation2", got %v`, instance.NeverRequireApprovalTools[0]) + } } // TestMcpApprovalModeLoadYAML tests loading McpApprovalMode from YAML @@ -63,6 +75,85 @@ neverRequireApprovalTools: if instance.Kind != "never" { t.Errorf(`Expected Kind to be "never", got %v`, instance.Kind) } + if len(instance.AlwaysRequireApprovalTools) != 1 { + t.Fatalf("Expected AlwaysRequireApprovalTools length to be 1, got %d", len(instance.AlwaysRequireApprovalTools)) + } + if instance.AlwaysRequireApprovalTools[0] != "operation1" { + t.Errorf(`Expected AlwaysRequireApprovalTools[0] to be "operation1", got %v`, instance.AlwaysRequireApprovalTools[0]) + } + if len(instance.NeverRequireApprovalTools) != 1 { + t.Fatalf("Expected NeverRequireApprovalTools length to be 1, got %d", len(instance.NeverRequireApprovalTools)) + } + if instance.NeverRequireApprovalTools[0] != "operation2" { + t.Errorf(`Expected NeverRequireApprovalTools[0] to be "operation2", got %v`, instance.NeverRequireApprovalTools[0]) + } +} + +// TestMcpApprovalModeFromJSON tests loading McpApprovalMode through the generated JSON helper +func TestMcpApprovalModeFromJSON(t *testing.T) { + jsonData := ` +{ + "kind": "never", + "alwaysRequireApprovalTools": [ + "operation1" + ], + "neverRequireApprovalTools": [ + "operation2" + ] +} +` + + instance, err := prompty.McpApprovalModeFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load McpApprovalMode from JSON helper: %v", err) + } + if instance.Kind != "never" { + t.Errorf(`Expected Kind to be "never", got %v`, instance.Kind) + } + if len(instance.AlwaysRequireApprovalTools) != 1 { + t.Fatalf("Expected AlwaysRequireApprovalTools length to be 1, got %d", len(instance.AlwaysRequireApprovalTools)) + } + if instance.AlwaysRequireApprovalTools[0] != "operation1" { + t.Errorf(`Expected AlwaysRequireApprovalTools[0] to be "operation1", got %v`, instance.AlwaysRequireApprovalTools[0]) + } + if len(instance.NeverRequireApprovalTools) != 1 { + t.Fatalf("Expected NeverRequireApprovalTools length to be 1, got %d", len(instance.NeverRequireApprovalTools)) + } + if instance.NeverRequireApprovalTools[0] != "operation2" { + t.Errorf(`Expected NeverRequireApprovalTools[0] to be "operation2", got %v`, instance.NeverRequireApprovalTools[0]) + } +} + +// TestMcpApprovalModeFromYAML tests loading McpApprovalMode through the generated YAML helper +func TestMcpApprovalModeFromYAML(t *testing.T) { + yamlData := ` +kind: never +alwaysRequireApprovalTools: + - operation1 +neverRequireApprovalTools: + - operation2 + +` + + instance, err := prompty.McpApprovalModeFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load McpApprovalMode from YAML helper: %v", err) + } + if instance.Kind != "never" { + t.Errorf(`Expected Kind to be "never", got %v`, instance.Kind) + } + if len(instance.AlwaysRequireApprovalTools) != 1 { + t.Fatalf("Expected AlwaysRequireApprovalTools length to be 1, got %d", len(instance.AlwaysRequireApprovalTools)) + } + if instance.AlwaysRequireApprovalTools[0] != "operation1" { + t.Errorf(`Expected AlwaysRequireApprovalTools[0] to be "operation1", got %v`, instance.AlwaysRequireApprovalTools[0]) + } + if len(instance.NeverRequireApprovalTools) != 1 { + t.Fatalf("Expected NeverRequireApprovalTools length to be 1, got %d", len(instance.NeverRequireApprovalTools)) + } + if instance.NeverRequireApprovalTools[0] != "operation2" { + t.Errorf(`Expected NeverRequireApprovalTools[0] to be "operation2", got %v`, instance.NeverRequireApprovalTools[0]) + } } // TestMcpApprovalModeRoundtrip tests load -> save -> load produces equivalent data @@ -98,6 +189,18 @@ func TestMcpApprovalModeRoundtrip(t *testing.T) { if reloaded.Kind != "never" { t.Errorf(`Expected Kind to be "never", got %v`, reloaded.Kind) } + if len(reloaded.AlwaysRequireApprovalTools) != 1 { + t.Fatalf("Expected AlwaysRequireApprovalTools length to be 1, got %d", len(reloaded.AlwaysRequireApprovalTools)) + } + if reloaded.AlwaysRequireApprovalTools[0] != "operation1" { + t.Errorf(`Expected AlwaysRequireApprovalTools[0] to be "operation1", got %v`, reloaded.AlwaysRequireApprovalTools[0]) + } + if len(reloaded.NeverRequireApprovalTools) != 1 { + t.Fatalf("Expected NeverRequireApprovalTools length to be 1, got %d", len(reloaded.NeverRequireApprovalTools)) + } + if reloaded.NeverRequireApprovalTools[0] != "operation2" { + t.Errorf(`Expected NeverRequireApprovalTools[0] to be "operation2", got %v`, reloaded.NeverRequireApprovalTools[0]) + } } // TestMcpApprovalModeToJSON tests that ToJSON produces valid JSON @@ -132,6 +235,26 @@ func TestMcpApprovalModeToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadMcpApprovalMode(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Kind != "never" { + t.Errorf(`Expected Kind to be "never", got %v`, reloaded.Kind) + } + if len(reloaded.AlwaysRequireApprovalTools) != 1 { + t.Fatalf("Expected AlwaysRequireApprovalTools length to be 1, got %d", len(reloaded.AlwaysRequireApprovalTools)) + } + if reloaded.AlwaysRequireApprovalTools[0] != "operation1" { + t.Errorf(`Expected AlwaysRequireApprovalTools[0] to be "operation1", got %v`, reloaded.AlwaysRequireApprovalTools[0]) + } + if len(reloaded.NeverRequireApprovalTools) != 1 { + t.Fatalf("Expected NeverRequireApprovalTools length to be 1, got %d", len(reloaded.NeverRequireApprovalTools)) + } + if reloaded.NeverRequireApprovalTools[0] != "operation2" { + t.Errorf(`Expected NeverRequireApprovalTools[0] to be "operation2", got %v`, reloaded.NeverRequireApprovalTools[0]) + } } // TestMcpApprovalModeToYAML tests that ToYAML produces valid YAML @@ -166,6 +289,33 @@ func TestMcpApprovalModeToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadMcpApprovalMode(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Kind != "never" { + t.Errorf(`Expected Kind to be "never", got %v`, reloaded.Kind) + } + if len(reloaded.AlwaysRequireApprovalTools) != 1 { + t.Fatalf("Expected AlwaysRequireApprovalTools length to be 1, got %d", len(reloaded.AlwaysRequireApprovalTools)) + } + if reloaded.AlwaysRequireApprovalTools[0] != "operation1" { + t.Errorf(`Expected AlwaysRequireApprovalTools[0] to be "operation1", got %v`, reloaded.AlwaysRequireApprovalTools[0]) + } + if len(reloaded.NeverRequireApprovalTools) != 1 { + t.Fatalf("Expected NeverRequireApprovalTools length to be 1, got %d", len(reloaded.NeverRequireApprovalTools)) + } + if reloaded.NeverRequireApprovalTools[0] != "operation2" { + t.Errorf(`Expected NeverRequireApprovalTools[0] to be "operation2", got %v`, reloaded.NeverRequireApprovalTools[0]) + } +} + +// TestMcpApprovalModeFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestMcpApprovalModeFromJSONInvalid(t *testing.T) { + if _, err := prompty.McpApprovalModeFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } // TestMcpApprovalModeFromKind tests loading McpApprovalMode from string diff --git a/runtime/go/prompty/model/mcp_tool_test.go b/runtime/go/prompty/model/mcp_tool_test.go index 082ea06b..08824694 100644 --- a/runtime/go/prompty/model/mcp_tool_test.go +++ b/runtime/go/prompty/model/mcp_tool_test.go @@ -50,6 +50,18 @@ func TestMcpToolLoadJSON(t *testing.T) { if instance.ServerDescription == nil || *instance.ServerDescription != "This tool allows access to MCP services." { t.Errorf(`Expected ServerDescription to be "This tool allows access to MCP services.", got %v`, instance.ServerDescription) } + if instance.ApprovalMode.Kind != "always" { + t.Errorf(`Expected ApprovalMode.Kind to be "always", got %v`, instance.ApprovalMode.Kind) + } + if len(instance.AllowedTools) != 2 { + t.Fatalf("Expected AllowedTools length to be 2, got %d", len(instance.AllowedTools)) + } + if instance.AllowedTools[0] != "operation1" { + t.Errorf(`Expected AllowedTools[0] to be "operation1", got %v`, instance.AllowedTools[0]) + } + if instance.AllowedTools[1] != "operation2" { + t.Errorf(`Expected AllowedTools[1] to be "operation2", got %v`, instance.AllowedTools[1]) + } } // TestMcpToolLoadYAML tests loading McpTool from YAML @@ -86,6 +98,108 @@ allowedTools: if instance.ServerDescription == nil || *instance.ServerDescription != "This tool allows access to MCP services." { t.Errorf(`Expected ServerDescription to be "This tool allows access to MCP services.", got %v`, instance.ServerDescription) } + if instance.ApprovalMode.Kind != "always" { + t.Errorf(`Expected ApprovalMode.Kind to be "always", got %v`, instance.ApprovalMode.Kind) + } + if len(instance.AllowedTools) != 2 { + t.Fatalf("Expected AllowedTools length to be 2, got %d", len(instance.AllowedTools)) + } + if instance.AllowedTools[0] != "operation1" { + t.Errorf(`Expected AllowedTools[0] to be "operation1", got %v`, instance.AllowedTools[0]) + } + if instance.AllowedTools[1] != "operation2" { + t.Errorf(`Expected AllowedTools[1] to be "operation2", got %v`, instance.AllowedTools[1]) + } +} + +// TestMcpToolFromJSON tests loading McpTool through the generated JSON helper +func TestMcpToolFromJSON(t *testing.T) { + jsonData := ` +{ + "kind": "mcp", + "connection": { + "kind": "reference" + }, + "serverName": "My MCP Server", + "serverDescription": "This tool allows access to MCP services.", + "approvalMode": { + "kind": "always" + }, + "allowedTools": [ + "operation1", + "operation2" + ] +} +` + + instance, err := prompty.McpToolFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load McpTool from JSON helper: %v", err) + } + if instance.Kind != "mcp" { + t.Errorf(`Expected Kind to be "mcp", got %v`, instance.Kind) + } + if instance.ServerName != "My MCP Server" { + t.Errorf(`Expected ServerName to be "My MCP Server", got %v`, instance.ServerName) + } + if instance.ServerDescription == nil || *instance.ServerDescription != "This tool allows access to MCP services." { + t.Errorf(`Expected ServerDescription to be "This tool allows access to MCP services.", got %v`, instance.ServerDescription) + } + if instance.ApprovalMode.Kind != "always" { + t.Errorf(`Expected ApprovalMode.Kind to be "always", got %v`, instance.ApprovalMode.Kind) + } + if len(instance.AllowedTools) != 2 { + t.Fatalf("Expected AllowedTools length to be 2, got %d", len(instance.AllowedTools)) + } + if instance.AllowedTools[0] != "operation1" { + t.Errorf(`Expected AllowedTools[0] to be "operation1", got %v`, instance.AllowedTools[0]) + } + if instance.AllowedTools[1] != "operation2" { + t.Errorf(`Expected AllowedTools[1] to be "operation2", got %v`, instance.AllowedTools[1]) + } +} + +// TestMcpToolFromYAML tests loading McpTool through the generated YAML helper +func TestMcpToolFromYAML(t *testing.T) { + yamlData := ` +kind: mcp +connection: + kind: reference +serverName: My MCP Server +serverDescription: This tool allows access to MCP services. +approvalMode: + kind: always +allowedTools: + - operation1 + - operation2 + +` + + instance, err := prompty.McpToolFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load McpTool from YAML helper: %v", err) + } + if instance.Kind != "mcp" { + t.Errorf(`Expected Kind to be "mcp", got %v`, instance.Kind) + } + if instance.ServerName != "My MCP Server" { + t.Errorf(`Expected ServerName to be "My MCP Server", got %v`, instance.ServerName) + } + if instance.ServerDescription == nil || *instance.ServerDescription != "This tool allows access to MCP services." { + t.Errorf(`Expected ServerDescription to be "This tool allows access to MCP services.", got %v`, instance.ServerDescription) + } + if instance.ApprovalMode.Kind != "always" { + t.Errorf(`Expected ApprovalMode.Kind to be "always", got %v`, instance.ApprovalMode.Kind) + } + if len(instance.AllowedTools) != 2 { + t.Fatalf("Expected AllowedTools length to be 2, got %d", len(instance.AllowedTools)) + } + if instance.AllowedTools[0] != "operation1" { + t.Errorf(`Expected AllowedTools[0] to be "operation1", got %v`, instance.AllowedTools[0]) + } + if instance.AllowedTools[1] != "operation2" { + t.Errorf(`Expected AllowedTools[1] to be "operation2", got %v`, instance.AllowedTools[1]) + } } // TestMcpToolRoundtrip tests load -> save -> load produces equivalent data @@ -133,6 +247,18 @@ func TestMcpToolRoundtrip(t *testing.T) { if reloaded.ServerDescription == nil || *reloaded.ServerDescription != "This tool allows access to MCP services." { t.Errorf(`Expected ServerDescription to be "This tool allows access to MCP services.", got %v`, reloaded.ServerDescription) } + if reloaded.ApprovalMode.Kind != "always" { + t.Errorf(`Expected ApprovalMode.Kind to be "always", got %v`, reloaded.ApprovalMode.Kind) + } + if len(reloaded.AllowedTools) != 2 { + t.Fatalf("Expected AllowedTools length to be 2, got %d", len(reloaded.AllowedTools)) + } + if reloaded.AllowedTools[0] != "operation1" { + t.Errorf(`Expected AllowedTools[0] to be "operation1", got %v`, reloaded.AllowedTools[0]) + } + if reloaded.AllowedTools[1] != "operation2" { + t.Errorf(`Expected AllowedTools[1] to be "operation2", got %v`, reloaded.AllowedTools[1]) + } } // TestMcpToolToJSON tests that ToJSON produces valid JSON @@ -173,6 +299,32 @@ func TestMcpToolToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadMcpTool(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Kind != "mcp" { + t.Errorf(`Expected Kind to be "mcp", got %v`, reloaded.Kind) + } + if reloaded.ServerName != "My MCP Server" { + t.Errorf(`Expected ServerName to be "My MCP Server", got %v`, reloaded.ServerName) + } + if reloaded.ServerDescription == nil || *reloaded.ServerDescription != "This tool allows access to MCP services." { + t.Errorf(`Expected ServerDescription to be "This tool allows access to MCP services.", got %v`, reloaded.ServerDescription) + } + if reloaded.ApprovalMode.Kind != "always" { + t.Errorf(`Expected ApprovalMode.Kind to be "always", got %v`, reloaded.ApprovalMode.Kind) + } + if len(reloaded.AllowedTools) != 2 { + t.Fatalf("Expected AllowedTools length to be 2, got %d", len(reloaded.AllowedTools)) + } + if reloaded.AllowedTools[0] != "operation1" { + t.Errorf(`Expected AllowedTools[0] to be "operation1", got %v`, reloaded.AllowedTools[0]) + } + if reloaded.AllowedTools[1] != "operation2" { + t.Errorf(`Expected AllowedTools[1] to be "operation2", got %v`, reloaded.AllowedTools[1]) + } } // TestMcpToolToYAML tests that ToYAML produces valid YAML @@ -213,4 +365,37 @@ func TestMcpToolToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadMcpTool(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Kind != "mcp" { + t.Errorf(`Expected Kind to be "mcp", got %v`, reloaded.Kind) + } + if reloaded.ServerName != "My MCP Server" { + t.Errorf(`Expected ServerName to be "My MCP Server", got %v`, reloaded.ServerName) + } + if reloaded.ServerDescription == nil || *reloaded.ServerDescription != "This tool allows access to MCP services." { + t.Errorf(`Expected ServerDescription to be "This tool allows access to MCP services.", got %v`, reloaded.ServerDescription) + } + if reloaded.ApprovalMode.Kind != "always" { + t.Errorf(`Expected ApprovalMode.Kind to be "always", got %v`, reloaded.ApprovalMode.Kind) + } + if len(reloaded.AllowedTools) != 2 { + t.Fatalf("Expected AllowedTools length to be 2, got %d", len(reloaded.AllowedTools)) + } + if reloaded.AllowedTools[0] != "operation1" { + t.Errorf(`Expected AllowedTools[0] to be "operation1", got %v`, reloaded.AllowedTools[0]) + } + if reloaded.AllowedTools[1] != "operation2" { + t.Errorf(`Expected AllowedTools[1] to be "operation2", got %v`, reloaded.AllowedTools[1]) + } +} + +// TestMcpToolFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestMcpToolFromJSONInvalid(t *testing.T) { + if _, err := prompty.McpToolFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/message.go b/runtime/go/prompty/model/message.go index 7fe6c04d..cb0da922 100644 --- a/runtime/go/prompty/model/message.go +++ b/runtime/go/prompty/model/message.go @@ -62,7 +62,7 @@ func LoadMessage(data interface{}, ctx *LoadContext) (Message, error) { } // Save serializes Message to map[string]interface{} -func (obj *Message) Save(ctx *SaveContext) map[string]interface{} { +func (obj Message) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["role"] = string(obj.Role) if obj.Parts != nil { @@ -100,11 +100,7 @@ func (obj *Message) ToJSON() (string, error) { func (obj *Message) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates Message from JSON string diff --git a/runtime/go/prompty/model/message_test.go b/runtime/go/prompty/model/message_test.go index d5609a79..fd960e71 100644 --- a/runtime/go/prompty/model/message_test.go +++ b/runtime/go/prompty/model/message_test.go @@ -41,6 +41,25 @@ func TestMessageLoadJSON(t *testing.T) { if instance.Role != "user" { t.Errorf(`Expected Role to be "user", got %v`, instance.Role) } + if len(instance.Parts) != 1 { + t.Fatalf("Expected Parts length to be 1, got %d", len(instance.Parts)) + } + parts0Value, ok := instance.Parts[0].(prompty.TextPart) + if !ok { + t.Fatalf("Expected Parts[0] to be prompty.TextPart, got %T", instance.Parts[0]) + } + if parts0Value.Kind != "text" { + t.Errorf(`Expected Kind to be "text", got %v`, parts0Value.Kind) + } + if parts0Value.Value != "Hello!" { + t.Errorf(`Expected Value to be "Hello!", got %v`, parts0Value.Value) + } + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if got := instance.Metadata["source"]; got != "user-input" { + t.Errorf(`Expected Metadata["source"] to be "user-input", got %v`, got) + } } // TestMessageLoadYAML tests loading Message from YAML @@ -67,6 +86,110 @@ metadata: if instance.Role != "user" { t.Errorf(`Expected Role to be "user", got %v`, instance.Role) } + if len(instance.Parts) != 1 { + t.Fatalf("Expected Parts length to be 1, got %d", len(instance.Parts)) + } + parts0Value, ok := instance.Parts[0].(prompty.TextPart) + if !ok { + t.Fatalf("Expected Parts[0] to be prompty.TextPart, got %T", instance.Parts[0]) + } + if parts0Value.Kind != "text" { + t.Errorf(`Expected Kind to be "text", got %v`, parts0Value.Kind) + } + if parts0Value.Value != "Hello!" { + t.Errorf(`Expected Value to be "Hello!", got %v`, parts0Value.Value) + } + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if got := instance.Metadata["source"]; got != "user-input" { + t.Errorf(`Expected Metadata["source"] to be "user-input", got %v`, got) + } +} + +// TestMessageFromJSON tests loading Message through the generated JSON helper +func TestMessageFromJSON(t *testing.T) { + jsonData := ` +{ + "role": "user", + "parts": [ + { + "kind": "text", + "value": "Hello!" + } + ], + "metadata": { + "source": "user-input" + } +} +` + + instance, err := prompty.MessageFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load Message from JSON helper: %v", err) + } + if instance.Role != "user" { + t.Errorf(`Expected Role to be "user", got %v`, instance.Role) + } + if len(instance.Parts) != 1 { + t.Fatalf("Expected Parts length to be 1, got %d", len(instance.Parts)) + } + parts0Value, ok := instance.Parts[0].(prompty.TextPart) + if !ok { + t.Fatalf("Expected Parts[0] to be prompty.TextPart, got %T", instance.Parts[0]) + } + if parts0Value.Kind != "text" { + t.Errorf(`Expected Kind to be "text", got %v`, parts0Value.Kind) + } + if parts0Value.Value != "Hello!" { + t.Errorf(`Expected Value to be "Hello!", got %v`, parts0Value.Value) + } + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if got := instance.Metadata["source"]; got != "user-input" { + t.Errorf(`Expected Metadata["source"] to be "user-input", got %v`, got) + } +} + +// TestMessageFromYAML tests loading Message through the generated YAML helper +func TestMessageFromYAML(t *testing.T) { + yamlData := ` +role: user +parts: + - kind: text + value: Hello! +metadata: + source: user-input + +` + + instance, err := prompty.MessageFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load Message from YAML helper: %v", err) + } + if instance.Role != "user" { + t.Errorf(`Expected Role to be "user", got %v`, instance.Role) + } + if len(instance.Parts) != 1 { + t.Fatalf("Expected Parts length to be 1, got %d", len(instance.Parts)) + } + parts0Value, ok := instance.Parts[0].(prompty.TextPart) + if !ok { + t.Fatalf("Expected Parts[0] to be prompty.TextPart, got %T", instance.Parts[0]) + } + if parts0Value.Kind != "text" { + t.Errorf(`Expected Kind to be "text", got %v`, parts0Value.Kind) + } + if parts0Value.Value != "Hello!" { + t.Errorf(`Expected Value to be "Hello!", got %v`, parts0Value.Value) + } + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if got := instance.Metadata["source"]; got != "user-input" { + t.Errorf(`Expected Metadata["source"] to be "user-input", got %v`, got) + } } // TestMessageRoundtrip tests load -> save -> load produces equivalent data @@ -105,6 +228,25 @@ func TestMessageRoundtrip(t *testing.T) { if reloaded.Role != "user" { t.Errorf(`Expected Role to be "user", got %v`, reloaded.Role) } + if len(reloaded.Parts) != 1 { + t.Fatalf("Expected Parts length to be 1, got %d", len(reloaded.Parts)) + } + parts0Value, ok := reloaded.Parts[0].(prompty.TextPart) + if !ok { + t.Fatalf("Expected Parts[0] to be prompty.TextPart, got %T", reloaded.Parts[0]) + } + if parts0Value.Kind != "text" { + t.Errorf(`Expected Kind to be "text", got %v`, parts0Value.Kind) + } + if parts0Value.Value != "Hello!" { + t.Errorf(`Expected Value to be "Hello!", got %v`, parts0Value.Value) + } + if reloaded.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if got := reloaded.Metadata["source"]; got != "user-input" { + t.Errorf(`Expected Metadata["source"] to be "user-input", got %v`, got) + } } // TestMessageToJSON tests that ToJSON produces valid JSON @@ -142,6 +284,33 @@ func TestMessageToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadMessage(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Role != "user" { + t.Errorf(`Expected Role to be "user", got %v`, reloaded.Role) + } + if len(reloaded.Parts) != 1 { + t.Fatalf("Expected Parts length to be 1, got %d", len(reloaded.Parts)) + } + parts0Value, ok := reloaded.Parts[0].(prompty.TextPart) + if !ok { + t.Fatalf("Expected Parts[0] to be prompty.TextPart, got %T", reloaded.Parts[0]) + } + if parts0Value.Kind != "text" { + t.Errorf(`Expected Kind to be "text", got %v`, parts0Value.Kind) + } + if parts0Value.Value != "Hello!" { + t.Errorf(`Expected Value to be "Hello!", got %v`, parts0Value.Value) + } + if reloaded.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if got := reloaded.Metadata["source"]; got != "user-input" { + t.Errorf(`Expected Metadata["source"] to be "user-input", got %v`, got) + } } // TestMessageToYAML tests that ToYAML produces valid YAML @@ -179,4 +348,38 @@ func TestMessageToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadMessage(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Role != "user" { + t.Errorf(`Expected Role to be "user", got %v`, reloaded.Role) + } + if len(reloaded.Parts) != 1 { + t.Fatalf("Expected Parts length to be 1, got %d", len(reloaded.Parts)) + } + parts0Value, ok := reloaded.Parts[0].(prompty.TextPart) + if !ok { + t.Fatalf("Expected Parts[0] to be prompty.TextPart, got %T", reloaded.Parts[0]) + } + if parts0Value.Kind != "text" { + t.Errorf(`Expected Kind to be "text", got %v`, parts0Value.Kind) + } + if parts0Value.Value != "Hello!" { + t.Errorf(`Expected Value to be "Hello!", got %v`, parts0Value.Value) + } + if reloaded.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if got := reloaded.Metadata["source"]; got != "user-input" { + t.Errorf(`Expected Metadata["source"] to be "user-input", got %v`, got) + } +} + +// TestMessageFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestMessageFromJSONInvalid(t *testing.T) { + if _, err := prompty.MessageFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/messages_updated_payload.go b/runtime/go/prompty/model/messages_updated_payload.go index 17937fae..93bff1dd 100644 --- a/runtime/go/prompty/model/messages_updated_payload.go +++ b/runtime/go/prompty/model/messages_updated_payload.go @@ -71,7 +71,7 @@ func LoadMessagesUpdatedPayload(data interface{}, ctx *LoadContext) (MessagesUpd } // Save serializes MessagesUpdatedPayload to map[string]interface{} -func (obj *MessagesUpdatedPayload) Save(ctx *SaveContext) map[string]interface{} { +func (obj MessagesUpdatedPayload) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) if obj.Messages != nil { arr := make([]interface{}, len(obj.Messages)) @@ -112,11 +112,7 @@ func (obj *MessagesUpdatedPayload) ToJSON() (string, error) { func (obj *MessagesUpdatedPayload) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates MessagesUpdatedPayload from JSON string diff --git a/runtime/go/prompty/model/messages_updated_payload_test.go b/runtime/go/prompty/model/messages_updated_payload_test.go index 9550f593..df120cd5 100644 --- a/runtime/go/prompty/model/messages_updated_payload_test.go +++ b/runtime/go/prompty/model/messages_updated_payload_test.go @@ -63,6 +63,47 @@ removed: 2 } } +// TestMessagesUpdatedPayloadFromJSON tests loading MessagesUpdatedPayload through the generated JSON helper +func TestMessagesUpdatedPayloadFromJSON(t *testing.T) { + jsonData := ` +{ + "reason": "tool_results", + "removed": 2 +} +` + + instance, err := prompty.MessagesUpdatedPayloadFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load MessagesUpdatedPayload from JSON helper: %v", err) + } + if instance.Reason == nil || *instance.Reason != "tool_results" { + t.Errorf(`Expected Reason to be "tool_results", got %v`, instance.Reason) + } + if instance.Removed == nil || *instance.Removed != 2 { + t.Errorf(`Expected Removed to be 2, got %v`, instance.Removed) + } +} + +// TestMessagesUpdatedPayloadFromYAML tests loading MessagesUpdatedPayload through the generated YAML helper +func TestMessagesUpdatedPayloadFromYAML(t *testing.T) { + yamlData := ` +reason: tool_results +removed: 2 + +` + + instance, err := prompty.MessagesUpdatedPayloadFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load MessagesUpdatedPayload from YAML helper: %v", err) + } + if instance.Reason == nil || *instance.Reason != "tool_results" { + t.Errorf(`Expected Reason to be "tool_results", got %v`, instance.Reason) + } + if instance.Removed == nil || *instance.Removed != 2 { + t.Errorf(`Expected Removed to be 2, got %v`, instance.Removed) + } +} + // TestMessagesUpdatedPayloadRoundtrip tests load -> save -> load produces equivalent data func TestMessagesUpdatedPayloadRoundtrip(t *testing.T) { jsonData := ` @@ -123,6 +164,17 @@ func TestMessagesUpdatedPayloadToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadMessagesUpdatedPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Reason == nil || *reloaded.Reason != "tool_results" { + t.Errorf(`Expected Reason to be "tool_results", got %v`, reloaded.Reason) + } + if reloaded.Removed == nil || *reloaded.Removed != 2 { + t.Errorf(`Expected Removed to be 2, got %v`, reloaded.Removed) + } } // TestMessagesUpdatedPayloadToYAML tests that ToYAML produces valid YAML @@ -152,4 +204,22 @@ func TestMessagesUpdatedPayloadToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadMessagesUpdatedPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Reason == nil || *reloaded.Reason != "tool_results" { + t.Errorf(`Expected Reason to be "tool_results", got %v`, reloaded.Reason) + } + if reloaded.Removed == nil || *reloaded.Removed != 2 { + t.Errorf(`Expected Removed to be 2, got %v`, reloaded.Removed) + } +} + +// TestMessagesUpdatedPayloadFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestMessagesUpdatedPayloadFromJSONInvalid(t *testing.T) { + if _, err := prompty.MessagesUpdatedPayloadFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/model.go b/runtime/go/prompty/model/model.go index 2b823850..3b5d7289 100644 --- a/runtime/go/prompty/model/model.go +++ b/runtime/go/prompty/model/model.go @@ -75,7 +75,7 @@ func LoadModel(data interface{}, ctx *LoadContext) (Model, error) { } // Save serializes Model to map[string]interface{} -func (obj *Model) Save(ctx *SaveContext) map[string]interface{} { +func (obj Model) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["id"] = obj.Id if obj.Provider != nil { @@ -119,11 +119,7 @@ func (obj *Model) ToJSON() (string, error) { func (obj *Model) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates Model from JSON string diff --git a/runtime/go/prompty/model/model_info.go b/runtime/go/prompty/model/model_info.go index 20e4c99b..fdc2b736 100644 --- a/runtime/go/prompty/model/model_info.go +++ b/runtime/go/prompty/model/model_info.go @@ -59,19 +59,25 @@ func LoadModelInfo(data interface{}, ctx *LoadContext) (ModelInfo, error) { result.ContextWindow = &v } if val, ok := m["inputModalities"]; ok && val != nil { - if arr, ok := val.([]interface{}); ok { + switch arr := val.(type) { + case []interface{}: result.InputModalities = make([]string, len(arr)) for i, v := range arr { result.InputModalities[i] = v.(string) } + case []string: + result.InputModalities = arr } } if val, ok := m["outputModalities"]; ok && val != nil { - if arr, ok := val.([]interface{}); ok { + switch arr := val.(type) { + case []interface{}: result.OutputModalities = make([]string, len(arr)) for i, v := range arr { result.OutputModalities[i] = v.(string) } + case []string: + result.OutputModalities = arr } } if val, ok := m["additionalProperties"]; ok && val != nil { @@ -85,7 +91,7 @@ func LoadModelInfo(data interface{}, ctx *LoadContext) (ModelInfo, error) { } // Save serializes ModelInfo to map[string]interface{} -func (obj *ModelInfo) Save(ctx *SaveContext) map[string]interface{} { +func (obj ModelInfo) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["id"] = obj.Id if obj.DisplayName != nil { @@ -121,11 +127,7 @@ func (obj *ModelInfo) ToJSON() (string, error) { func (obj *ModelInfo) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates ModelInfo from JSON string diff --git a/runtime/go/prompty/model/model_info_test.go b/runtime/go/prompty/model/model_info_test.go index 63b81afe..ab0dd060 100644 --- a/runtime/go/prompty/model/model_info_test.go +++ b/runtime/go/prompty/model/model_info_test.go @@ -54,6 +54,24 @@ func TestModelInfoLoadJSON(t *testing.T) { if instance.ContextWindow == nil || *instance.ContextWindow != 128000 { t.Errorf(`Expected ContextWindow to be 128000, got %v`, instance.ContextWindow) } + if len(instance.InputModalities) != 2 { + t.Fatalf("Expected InputModalities length to be 2, got %d", len(instance.InputModalities)) + } + if instance.InputModalities[0] != "text" { + t.Errorf(`Expected InputModalities[0] to be "text", got %v`, instance.InputModalities[0]) + } + if instance.InputModalities[1] != "image" { + t.Errorf(`Expected InputModalities[1] to be "image", got %v`, instance.InputModalities[1]) + } + if len(instance.OutputModalities) != 1 { + t.Fatalf("Expected OutputModalities length to be 1, got %d", len(instance.OutputModalities)) + } + if instance.OutputModalities[0] != "text" { + t.Errorf(`Expected OutputModalities[0] to be "text", got %v`, instance.OutputModalities[0]) + } + if instance.AdditionalProperties == nil { + t.Fatalf("Expected AdditionalProperties to be populated") + } } // TestModelInfoLoadYAML tests loading ModelInfo from YAML @@ -94,6 +112,134 @@ additionalProperties: if instance.ContextWindow == nil || *instance.ContextWindow != 128000 { t.Errorf(`Expected ContextWindow to be 128000, got %v`, instance.ContextWindow) } + if len(instance.InputModalities) != 2 { + t.Fatalf("Expected InputModalities length to be 2, got %d", len(instance.InputModalities)) + } + if instance.InputModalities[0] != "text" { + t.Errorf(`Expected InputModalities[0] to be "text", got %v`, instance.InputModalities[0]) + } + if instance.InputModalities[1] != "image" { + t.Errorf(`Expected InputModalities[1] to be "image", got %v`, instance.InputModalities[1]) + } + if len(instance.OutputModalities) != 1 { + t.Fatalf("Expected OutputModalities length to be 1, got %d", len(instance.OutputModalities)) + } + if instance.OutputModalities[0] != "text" { + t.Errorf(`Expected OutputModalities[0] to be "text", got %v`, instance.OutputModalities[0]) + } + if instance.AdditionalProperties == nil { + t.Fatalf("Expected AdditionalProperties to be populated") + } +} + +// TestModelInfoFromJSON tests loading ModelInfo through the generated JSON helper +func TestModelInfoFromJSON(t *testing.T) { + jsonData := ` +{ + "id": "gpt-4o", + "displayName": "GPT-4o", + "ownedBy": "openai", + "contextWindow": 128000, + "inputModalities": [ + "text", + "image" + ], + "outputModalities": [ + "text" + ], + "additionalProperties": { + "supportsStreaming": true + } +} +` + + instance, err := prompty.ModelInfoFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load ModelInfo from JSON helper: %v", err) + } + if instance.Id != "gpt-4o" { + t.Errorf(`Expected Id to be "gpt-4o", got %v`, instance.Id) + } + if instance.DisplayName == nil || *instance.DisplayName != "GPT-4o" { + t.Errorf(`Expected DisplayName to be "GPT-4o", got %v`, instance.DisplayName) + } + if instance.OwnedBy == nil || *instance.OwnedBy != "openai" { + t.Errorf(`Expected OwnedBy to be "openai", got %v`, instance.OwnedBy) + } + if instance.ContextWindow == nil || *instance.ContextWindow != 128000 { + t.Errorf(`Expected ContextWindow to be 128000, got %v`, instance.ContextWindow) + } + if len(instance.InputModalities) != 2 { + t.Fatalf("Expected InputModalities length to be 2, got %d", len(instance.InputModalities)) + } + if instance.InputModalities[0] != "text" { + t.Errorf(`Expected InputModalities[0] to be "text", got %v`, instance.InputModalities[0]) + } + if instance.InputModalities[1] != "image" { + t.Errorf(`Expected InputModalities[1] to be "image", got %v`, instance.InputModalities[1]) + } + if len(instance.OutputModalities) != 1 { + t.Fatalf("Expected OutputModalities length to be 1, got %d", len(instance.OutputModalities)) + } + if instance.OutputModalities[0] != "text" { + t.Errorf(`Expected OutputModalities[0] to be "text", got %v`, instance.OutputModalities[0]) + } + if instance.AdditionalProperties == nil { + t.Fatalf("Expected AdditionalProperties to be populated") + } +} + +// TestModelInfoFromYAML tests loading ModelInfo through the generated YAML helper +func TestModelInfoFromYAML(t *testing.T) { + yamlData := ` +id: gpt-4o +displayName: GPT-4o +ownedBy: openai +contextWindow: 128000 +inputModalities: + - text + - image +outputModalities: + - text +additionalProperties: + supportsStreaming: true + +` + + instance, err := prompty.ModelInfoFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load ModelInfo from YAML helper: %v", err) + } + if instance.Id != "gpt-4o" { + t.Errorf(`Expected Id to be "gpt-4o", got %v`, instance.Id) + } + if instance.DisplayName == nil || *instance.DisplayName != "GPT-4o" { + t.Errorf(`Expected DisplayName to be "GPT-4o", got %v`, instance.DisplayName) + } + if instance.OwnedBy == nil || *instance.OwnedBy != "openai" { + t.Errorf(`Expected OwnedBy to be "openai", got %v`, instance.OwnedBy) + } + if instance.ContextWindow == nil || *instance.ContextWindow != 128000 { + t.Errorf(`Expected ContextWindow to be 128000, got %v`, instance.ContextWindow) + } + if len(instance.InputModalities) != 2 { + t.Fatalf("Expected InputModalities length to be 2, got %d", len(instance.InputModalities)) + } + if instance.InputModalities[0] != "text" { + t.Errorf(`Expected InputModalities[0] to be "text", got %v`, instance.InputModalities[0]) + } + if instance.InputModalities[1] != "image" { + t.Errorf(`Expected InputModalities[1] to be "image", got %v`, instance.InputModalities[1]) + } + if len(instance.OutputModalities) != 1 { + t.Fatalf("Expected OutputModalities length to be 1, got %d", len(instance.OutputModalities)) + } + if instance.OutputModalities[0] != "text" { + t.Errorf(`Expected OutputModalities[0] to be "text", got %v`, instance.OutputModalities[0]) + } + if instance.AdditionalProperties == nil { + t.Fatalf("Expected AdditionalProperties to be populated") + } } // TestModelInfoRoundtrip tests load -> save -> load produces equivalent data @@ -145,6 +291,24 @@ func TestModelInfoRoundtrip(t *testing.T) { if reloaded.ContextWindow == nil || *reloaded.ContextWindow != 128000 { t.Errorf(`Expected ContextWindow to be 128000, got %v`, reloaded.ContextWindow) } + if len(reloaded.InputModalities) != 2 { + t.Fatalf("Expected InputModalities length to be 2, got %d", len(reloaded.InputModalities)) + } + if reloaded.InputModalities[0] != "text" { + t.Errorf(`Expected InputModalities[0] to be "text", got %v`, reloaded.InputModalities[0]) + } + if reloaded.InputModalities[1] != "image" { + t.Errorf(`Expected InputModalities[1] to be "image", got %v`, reloaded.InputModalities[1]) + } + if len(reloaded.OutputModalities) != 1 { + t.Fatalf("Expected OutputModalities length to be 1, got %d", len(reloaded.OutputModalities)) + } + if reloaded.OutputModalities[0] != "text" { + t.Errorf(`Expected OutputModalities[0] to be "text", got %v`, reloaded.OutputModalities[0]) + } + if reloaded.AdditionalProperties == nil { + t.Fatalf("Expected AdditionalProperties to be populated") + } } // TestModelInfoToJSON tests that ToJSON produces valid JSON @@ -186,6 +350,41 @@ func TestModelInfoToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadModelInfo(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Id != "gpt-4o" { + t.Errorf(`Expected Id to be "gpt-4o", got %v`, reloaded.Id) + } + if reloaded.DisplayName == nil || *reloaded.DisplayName != "GPT-4o" { + t.Errorf(`Expected DisplayName to be "GPT-4o", got %v`, reloaded.DisplayName) + } + if reloaded.OwnedBy == nil || *reloaded.OwnedBy != "openai" { + t.Errorf(`Expected OwnedBy to be "openai", got %v`, reloaded.OwnedBy) + } + if reloaded.ContextWindow == nil || *reloaded.ContextWindow != 128000 { + t.Errorf(`Expected ContextWindow to be 128000, got %v`, reloaded.ContextWindow) + } + if len(reloaded.InputModalities) != 2 { + t.Fatalf("Expected InputModalities length to be 2, got %d", len(reloaded.InputModalities)) + } + if reloaded.InputModalities[0] != "text" { + t.Errorf(`Expected InputModalities[0] to be "text", got %v`, reloaded.InputModalities[0]) + } + if reloaded.InputModalities[1] != "image" { + t.Errorf(`Expected InputModalities[1] to be "image", got %v`, reloaded.InputModalities[1]) + } + if len(reloaded.OutputModalities) != 1 { + t.Fatalf("Expected OutputModalities length to be 1, got %d", len(reloaded.OutputModalities)) + } + if reloaded.OutputModalities[0] != "text" { + t.Errorf(`Expected OutputModalities[0] to be "text", got %v`, reloaded.OutputModalities[0]) + } + if reloaded.AdditionalProperties == nil { + t.Fatalf("Expected AdditionalProperties to be populated") + } } // TestModelInfoToYAML tests that ToYAML produces valid YAML @@ -227,4 +426,46 @@ func TestModelInfoToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadModelInfo(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Id != "gpt-4o" { + t.Errorf(`Expected Id to be "gpt-4o", got %v`, reloaded.Id) + } + if reloaded.DisplayName == nil || *reloaded.DisplayName != "GPT-4o" { + t.Errorf(`Expected DisplayName to be "GPT-4o", got %v`, reloaded.DisplayName) + } + if reloaded.OwnedBy == nil || *reloaded.OwnedBy != "openai" { + t.Errorf(`Expected OwnedBy to be "openai", got %v`, reloaded.OwnedBy) + } + if reloaded.ContextWindow == nil || *reloaded.ContextWindow != 128000 { + t.Errorf(`Expected ContextWindow to be 128000, got %v`, reloaded.ContextWindow) + } + if len(reloaded.InputModalities) != 2 { + t.Fatalf("Expected InputModalities length to be 2, got %d", len(reloaded.InputModalities)) + } + if reloaded.InputModalities[0] != "text" { + t.Errorf(`Expected InputModalities[0] to be "text", got %v`, reloaded.InputModalities[0]) + } + if reloaded.InputModalities[1] != "image" { + t.Errorf(`Expected InputModalities[1] to be "image", got %v`, reloaded.InputModalities[1]) + } + if len(reloaded.OutputModalities) != 1 { + t.Fatalf("Expected OutputModalities length to be 1, got %d", len(reloaded.OutputModalities)) + } + if reloaded.OutputModalities[0] != "text" { + t.Errorf(`Expected OutputModalities[0] to be "text", got %v`, reloaded.OutputModalities[0]) + } + if reloaded.AdditionalProperties == nil { + t.Fatalf("Expected AdditionalProperties to be populated") + } +} + +// TestModelInfoFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestModelInfoFromJSONInvalid(t *testing.T) { + if _, err := prompty.ModelInfoFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/model_options.go b/runtime/go/prompty/model/model_options.go index aed0a2fa..d416e9e5 100644 --- a/runtime/go/prompty/model/model_options.go +++ b/runtime/go/prompty/model/model_options.go @@ -138,11 +138,14 @@ func LoadModelOptions(data interface{}, ctx *LoadContext) (ModelOptions, error) result.TopP = &v } if val, ok := m["stopSequences"]; ok && val != nil { - if arr, ok := val.([]interface{}); ok { + switch arr := val.(type) { + case []interface{}: result.StopSequences = make([]string, len(arr)) for i, v := range arr { result.StopSequences[i] = v.(string) } + case []string: + result.StopSequences = arr } } if val, ok := m["allowMultipleToolCalls"]; ok && val != nil { @@ -160,7 +163,7 @@ func LoadModelOptions(data interface{}, ctx *LoadContext) (ModelOptions, error) } // Save serializes ModelOptions to map[string]interface{} -func (obj *ModelOptions) Save(ctx *SaveContext) map[string]interface{} { +func (obj ModelOptions) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) if obj.FrequencyPenalty != nil { result["frequencyPenalty"] = *obj.FrequencyPenalty @@ -234,11 +237,7 @@ func (obj *ModelOptions) ToJSON() (string, error) { func (obj *ModelOptions) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates ModelOptions from JSON string diff --git a/runtime/go/prompty/model/model_options_test.go b/runtime/go/prompty/model/model_options_test.go index 9cc41ce5..01c2cac9 100644 --- a/runtime/go/prompty/model/model_options_test.go +++ b/runtime/go/prompty/model/model_options_test.go @@ -68,6 +68,24 @@ func TestModelOptionsLoadJSON(t *testing.T) { if instance.AllowMultipleToolCalls == nil || *instance.AllowMultipleToolCalls != true { t.Errorf(`Expected AllowMultipleToolCalls to be true, got %v`, instance.AllowMultipleToolCalls) } + if len(instance.StopSequences) != 2 { + t.Fatalf("Expected StopSequences length to be 2, got %d", len(instance.StopSequences)) + } + if instance.StopSequences[0] != "\n" { + t.Errorf(`Expected StopSequences[0] to be "\n", got %v`, instance.StopSequences[0]) + } + if instance.StopSequences[1] != "###" { + t.Errorf(`Expected StopSequences[1] to be "###", got %v`, instance.StopSequences[1]) + } + if instance.AdditionalProperties == nil { + t.Fatalf("Expected AdditionalProperties to be populated") + } + if got := instance.AdditionalProperties["customProperty"]; got != "value" { + t.Errorf(`Expected AdditionalProperties["customProperty"] to be "value", got %v`, got) + } + if got := instance.AdditionalProperties["anotherProperty"]; got != "anotherValue" { + t.Errorf(`Expected AdditionalProperties["anotherProperty"] to be "anotherValue", got %v`, got) + } } // TestModelOptionsLoadYAML tests loading ModelOptions from YAML @@ -123,6 +141,163 @@ additionalProperties: if instance.AllowMultipleToolCalls == nil || *instance.AllowMultipleToolCalls != true { t.Errorf(`Expected AllowMultipleToolCalls to be true, got %v`, instance.AllowMultipleToolCalls) } + if len(instance.StopSequences) != 2 { + t.Fatalf("Expected StopSequences length to be 2, got %d", len(instance.StopSequences)) + } + if instance.StopSequences[0] != "\n" { + t.Errorf(`Expected StopSequences[0] to be "\n", got %v`, instance.StopSequences[0]) + } + if instance.StopSequences[1] != "###" { + t.Errorf(`Expected StopSequences[1] to be "###", got %v`, instance.StopSequences[1]) + } + if instance.AdditionalProperties == nil { + t.Fatalf("Expected AdditionalProperties to be populated") + } + if got := instance.AdditionalProperties["customProperty"]; got != "value" { + t.Errorf(`Expected AdditionalProperties["customProperty"] to be "value", got %v`, got) + } + if got := instance.AdditionalProperties["anotherProperty"]; got != "anotherValue" { + t.Errorf(`Expected AdditionalProperties["anotherProperty"] to be "anotherValue", got %v`, got) + } +} + +// TestModelOptionsFromJSON tests loading ModelOptions through the generated JSON helper +func TestModelOptionsFromJSON(t *testing.T) { + jsonData := ` +{ + "frequencyPenalty": 0.5, + "maxOutputTokens": 2048, + "presencePenalty": 0.3, + "seed": 42, + "temperature": 0.7, + "topK": 40, + "topP": 0.9, + "stopSequences": [ + "\n", + "###" + ], + "allowMultipleToolCalls": true, + "additionalProperties": { + "customProperty": "value", + "anotherProperty": "anotherValue" + } +} +` + + instance, err := prompty.ModelOptionsFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load ModelOptions from JSON helper: %v", err) + } + if instance.FrequencyPenalty == nil || *instance.FrequencyPenalty != 0.5 { + t.Errorf(`Expected FrequencyPenalty to be 0.5, got %v`, instance.FrequencyPenalty) + } + if instance.MaxOutputTokens == nil || *instance.MaxOutputTokens != 2048 { + t.Errorf(`Expected MaxOutputTokens to be 2048, got %v`, instance.MaxOutputTokens) + } + if instance.PresencePenalty == nil || *instance.PresencePenalty != 0.3 { + t.Errorf(`Expected PresencePenalty to be 0.3, got %v`, instance.PresencePenalty) + } + if instance.Seed == nil || *instance.Seed != 42 { + t.Errorf(`Expected Seed to be 42, got %v`, instance.Seed) + } + if instance.Temperature == nil || *instance.Temperature != 0.7 { + t.Errorf(`Expected Temperature to be 0.7, got %v`, instance.Temperature) + } + if instance.TopK == nil || *instance.TopK != 40 { + t.Errorf(`Expected TopK to be 40, got %v`, instance.TopK) + } + if instance.TopP == nil || *instance.TopP != 0.9 { + t.Errorf(`Expected TopP to be 0.9, got %v`, instance.TopP) + } + if instance.AllowMultipleToolCalls == nil || *instance.AllowMultipleToolCalls != true { + t.Errorf(`Expected AllowMultipleToolCalls to be true, got %v`, instance.AllowMultipleToolCalls) + } + if len(instance.StopSequences) != 2 { + t.Fatalf("Expected StopSequences length to be 2, got %d", len(instance.StopSequences)) + } + if instance.StopSequences[0] != "\n" { + t.Errorf(`Expected StopSequences[0] to be "\n", got %v`, instance.StopSequences[0]) + } + if instance.StopSequences[1] != "###" { + t.Errorf(`Expected StopSequences[1] to be "###", got %v`, instance.StopSequences[1]) + } + if instance.AdditionalProperties == nil { + t.Fatalf("Expected AdditionalProperties to be populated") + } + if got := instance.AdditionalProperties["customProperty"]; got != "value" { + t.Errorf(`Expected AdditionalProperties["customProperty"] to be "value", got %v`, got) + } + if got := instance.AdditionalProperties["anotherProperty"]; got != "anotherValue" { + t.Errorf(`Expected AdditionalProperties["anotherProperty"] to be "anotherValue", got %v`, got) + } +} + +// TestModelOptionsFromYAML tests loading ModelOptions through the generated YAML helper +func TestModelOptionsFromYAML(t *testing.T) { + yamlData := ` +frequencyPenalty: 0.5 +maxOutputTokens: 2048 +presencePenalty: 0.3 +seed: 42 +temperature: 0.7 +topK: 40 +topP: 0.9 +stopSequences: + - "\n" + - "###" +allowMultipleToolCalls: true +additionalProperties: + customProperty: value + anotherProperty: anotherValue + +` + + instance, err := prompty.ModelOptionsFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load ModelOptions from YAML helper: %v", err) + } + if instance.FrequencyPenalty == nil || *instance.FrequencyPenalty != 0.5 { + t.Errorf(`Expected FrequencyPenalty to be 0.5, got %v`, instance.FrequencyPenalty) + } + if instance.MaxOutputTokens == nil || *instance.MaxOutputTokens != 2048 { + t.Errorf(`Expected MaxOutputTokens to be 2048, got %v`, instance.MaxOutputTokens) + } + if instance.PresencePenalty == nil || *instance.PresencePenalty != 0.3 { + t.Errorf(`Expected PresencePenalty to be 0.3, got %v`, instance.PresencePenalty) + } + if instance.Seed == nil || *instance.Seed != 42 { + t.Errorf(`Expected Seed to be 42, got %v`, instance.Seed) + } + if instance.Temperature == nil || *instance.Temperature != 0.7 { + t.Errorf(`Expected Temperature to be 0.7, got %v`, instance.Temperature) + } + if instance.TopK == nil || *instance.TopK != 40 { + t.Errorf(`Expected TopK to be 40, got %v`, instance.TopK) + } + if instance.TopP == nil || *instance.TopP != 0.9 { + t.Errorf(`Expected TopP to be 0.9, got %v`, instance.TopP) + } + if instance.AllowMultipleToolCalls == nil || *instance.AllowMultipleToolCalls != true { + t.Errorf(`Expected AllowMultipleToolCalls to be true, got %v`, instance.AllowMultipleToolCalls) + } + if len(instance.StopSequences) != 2 { + t.Fatalf("Expected StopSequences length to be 2, got %d", len(instance.StopSequences)) + } + if instance.StopSequences[0] != "\n" { + t.Errorf(`Expected StopSequences[0] to be "\n", got %v`, instance.StopSequences[0]) + } + if instance.StopSequences[1] != "###" { + t.Errorf(`Expected StopSequences[1] to be "###", got %v`, instance.StopSequences[1]) + } + if instance.AdditionalProperties == nil { + t.Fatalf("Expected AdditionalProperties to be populated") + } + if got := instance.AdditionalProperties["customProperty"]; got != "value" { + t.Errorf(`Expected AdditionalProperties["customProperty"] to be "value", got %v`, got) + } + if got := instance.AdditionalProperties["anotherProperty"]; got != "anotherValue" { + t.Errorf(`Expected AdditionalProperties["anotherProperty"] to be "anotherValue", got %v`, got) + } } // TestModelOptionsRoundtrip tests load -> save -> load produces equivalent data @@ -188,6 +363,24 @@ func TestModelOptionsRoundtrip(t *testing.T) { if reloaded.AllowMultipleToolCalls == nil || *reloaded.AllowMultipleToolCalls != true { t.Errorf(`Expected AllowMultipleToolCalls to be true, got %v`, reloaded.AllowMultipleToolCalls) } + if len(reloaded.StopSequences) != 2 { + t.Fatalf("Expected StopSequences length to be 2, got %d", len(reloaded.StopSequences)) + } + if reloaded.StopSequences[0] != "\n" { + t.Errorf(`Expected StopSequences[0] to be "\n", got %v`, reloaded.StopSequences[0]) + } + if reloaded.StopSequences[1] != "###" { + t.Errorf(`Expected StopSequences[1] to be "###", got %v`, reloaded.StopSequences[1]) + } + if reloaded.AdditionalProperties == nil { + t.Fatalf("Expected AdditionalProperties to be populated") + } + if got := reloaded.AdditionalProperties["customProperty"]; got != "value" { + t.Errorf(`Expected AdditionalProperties["customProperty"] to be "value", got %v`, got) + } + if got := reloaded.AdditionalProperties["anotherProperty"]; got != "anotherValue" { + t.Errorf(`Expected AdditionalProperties["anotherProperty"] to be "anotherValue", got %v`, got) + } } // TestModelOptionsToJSON tests that ToJSON produces valid JSON @@ -231,6 +424,53 @@ func TestModelOptionsToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadModelOptions(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.FrequencyPenalty == nil || *reloaded.FrequencyPenalty != 0.5 { + t.Errorf(`Expected FrequencyPenalty to be 0.5, got %v`, reloaded.FrequencyPenalty) + } + if reloaded.MaxOutputTokens == nil || *reloaded.MaxOutputTokens != 2048 { + t.Errorf(`Expected MaxOutputTokens to be 2048, got %v`, reloaded.MaxOutputTokens) + } + if reloaded.PresencePenalty == nil || *reloaded.PresencePenalty != 0.3 { + t.Errorf(`Expected PresencePenalty to be 0.3, got %v`, reloaded.PresencePenalty) + } + if reloaded.Seed == nil || *reloaded.Seed != 42 { + t.Errorf(`Expected Seed to be 42, got %v`, reloaded.Seed) + } + if reloaded.Temperature == nil || *reloaded.Temperature != 0.7 { + t.Errorf(`Expected Temperature to be 0.7, got %v`, reloaded.Temperature) + } + if reloaded.TopK == nil || *reloaded.TopK != 40 { + t.Errorf(`Expected TopK to be 40, got %v`, reloaded.TopK) + } + if reloaded.TopP == nil || *reloaded.TopP != 0.9 { + t.Errorf(`Expected TopP to be 0.9, got %v`, reloaded.TopP) + } + if reloaded.AllowMultipleToolCalls == nil || *reloaded.AllowMultipleToolCalls != true { + t.Errorf(`Expected AllowMultipleToolCalls to be true, got %v`, reloaded.AllowMultipleToolCalls) + } + if len(reloaded.StopSequences) != 2 { + t.Fatalf("Expected StopSequences length to be 2, got %d", len(reloaded.StopSequences)) + } + if reloaded.StopSequences[0] != "\n" { + t.Errorf(`Expected StopSequences[0] to be "\n", got %v`, reloaded.StopSequences[0]) + } + if reloaded.StopSequences[1] != "###" { + t.Errorf(`Expected StopSequences[1] to be "###", got %v`, reloaded.StopSequences[1]) + } + if reloaded.AdditionalProperties == nil { + t.Fatalf("Expected AdditionalProperties to be populated") + } + if got := reloaded.AdditionalProperties["customProperty"]; got != "value" { + t.Errorf(`Expected AdditionalProperties["customProperty"] to be "value", got %v`, got) + } + if got := reloaded.AdditionalProperties["anotherProperty"]; got != "anotherValue" { + t.Errorf(`Expected AdditionalProperties["anotherProperty"] to be "anotherValue", got %v`, got) + } } // TestModelOptionsToYAML tests that ToYAML produces valid YAML @@ -274,4 +514,188 @@ func TestModelOptionsToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadModelOptions(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.FrequencyPenalty == nil || *reloaded.FrequencyPenalty != 0.5 { + t.Errorf(`Expected FrequencyPenalty to be 0.5, got %v`, reloaded.FrequencyPenalty) + } + if reloaded.MaxOutputTokens == nil || *reloaded.MaxOutputTokens != 2048 { + t.Errorf(`Expected MaxOutputTokens to be 2048, got %v`, reloaded.MaxOutputTokens) + } + if reloaded.PresencePenalty == nil || *reloaded.PresencePenalty != 0.3 { + t.Errorf(`Expected PresencePenalty to be 0.3, got %v`, reloaded.PresencePenalty) + } + if reloaded.Seed == nil || *reloaded.Seed != 42 { + t.Errorf(`Expected Seed to be 42, got %v`, reloaded.Seed) + } + if reloaded.Temperature == nil || *reloaded.Temperature != 0.7 { + t.Errorf(`Expected Temperature to be 0.7, got %v`, reloaded.Temperature) + } + if reloaded.TopK == nil || *reloaded.TopK != 40 { + t.Errorf(`Expected TopK to be 40, got %v`, reloaded.TopK) + } + if reloaded.TopP == nil || *reloaded.TopP != 0.9 { + t.Errorf(`Expected TopP to be 0.9, got %v`, reloaded.TopP) + } + if reloaded.AllowMultipleToolCalls == nil || *reloaded.AllowMultipleToolCalls != true { + t.Errorf(`Expected AllowMultipleToolCalls to be true, got %v`, reloaded.AllowMultipleToolCalls) + } + if len(reloaded.StopSequences) != 2 { + t.Fatalf("Expected StopSequences length to be 2, got %d", len(reloaded.StopSequences)) + } + if reloaded.StopSequences[0] != "\n" { + t.Errorf(`Expected StopSequences[0] to be "\n", got %v`, reloaded.StopSequences[0]) + } + if reloaded.StopSequences[1] != "###" { + t.Errorf(`Expected StopSequences[1] to be "###", got %v`, reloaded.StopSequences[1]) + } + if reloaded.AdditionalProperties == nil { + t.Fatalf("Expected AdditionalProperties to be populated") + } + if got := reloaded.AdditionalProperties["customProperty"]; got != "value" { + t.Errorf(`Expected AdditionalProperties["customProperty"] to be "value", got %v`, got) + } + if got := reloaded.AdditionalProperties["anotherProperty"]; got != "anotherValue" { + t.Errorf(`Expected AdditionalProperties["anotherProperty"] to be "anotherValue", got %v`, got) + } +} + +// TestModelOptionsFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestModelOptionsFromJSONInvalid(t *testing.T) { + if _, err := prompty.ModelOptionsFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } +} + +// TestModelOptionsToWire tests provider-specific wire field names +func TestModelOptionsToWire(t *testing.T) { + jsonData := ` +{ + "frequencyPenalty": 0.5, + "maxOutputTokens": 2048, + "presencePenalty": 0.3, + "seed": 42, + "temperature": 0.7, + "topK": 40, + "topP": 0.9, + "stopSequences": [ + "\n", + "###" + ], + "allowMultipleToolCalls": true, + "additionalProperties": { + "customProperty": "value", + "anotherProperty": "anotherValue" + } +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadModelOptions(data, ctx) + if err != nil { + t.Fatalf("Failed to load ModelOptions: %v", err) + } + + openaiWire := instance.ToWire("openai") + if _, ok := openaiWire["frequency_penalty"]; !ok { + t.Errorf("Expected openai wire output to include frequency_penalty") + } + if _, ok := openaiWire["frequencyPenalty"]; ok { + t.Errorf("Expected openai wire output to omit source field frequencyPenalty") + } + if _, ok := openaiWire["max_completion_tokens"]; !ok { + t.Errorf("Expected openai wire output to include max_completion_tokens") + } + if _, ok := openaiWire["maxOutputTokens"]; ok { + t.Errorf("Expected openai wire output to omit source field maxOutputTokens") + } + if _, ok := openaiWire["presence_penalty"]; !ok { + t.Errorf("Expected openai wire output to include presence_penalty") + } + if _, ok := openaiWire["presencePenalty"]; ok { + t.Errorf("Expected openai wire output to omit source field presencePenalty") + } + if _, ok := openaiWire["seed"]; !ok { + t.Errorf("Expected openai wire output to include seed") + } + if _, ok := openaiWire["temperature"]; !ok { + t.Errorf("Expected openai wire output to include temperature") + } + if _, ok := openaiWire["top_k"]; !ok { + t.Errorf("Expected openai wire output to include top_k") + } + if _, ok := openaiWire["topK"]; ok { + t.Errorf("Expected openai wire output to omit source field topK") + } + if _, ok := openaiWire["top_p"]; !ok { + t.Errorf("Expected openai wire output to include top_p") + } + if _, ok := openaiWire["topP"]; ok { + t.Errorf("Expected openai wire output to omit source field topP") + } + if _, ok := openaiWire["stop"]; !ok { + t.Errorf("Expected openai wire output to include stop") + } + if _, ok := openaiWire["stopSequences"]; ok { + t.Errorf("Expected openai wire output to omit source field stopSequences") + } + if _, ok := openaiWire["parallel_tool_calls"]; !ok { + t.Errorf("Expected openai wire output to include parallel_tool_calls") + } + if _, ok := openaiWire["allowMultipleToolCalls"]; ok { + t.Errorf("Expected openai wire output to omit source field allowMultipleToolCalls") + } + + responsesWire := instance.ToWire("responses") + if _, ok := responsesWire["max_output_tokens"]; !ok { + t.Errorf("Expected responses wire output to include max_output_tokens") + } + if _, ok := responsesWire["maxOutputTokens"]; ok { + t.Errorf("Expected responses wire output to omit source field maxOutputTokens") + } + if _, ok := responsesWire["temperature"]; !ok { + t.Errorf("Expected responses wire output to include temperature") + } + if _, ok := responsesWire["top_p"]; !ok { + t.Errorf("Expected responses wire output to include top_p") + } + if _, ok := responsesWire["topP"]; ok { + t.Errorf("Expected responses wire output to omit source field topP") + } + + anthropicWire := instance.ToWire("anthropic") + if _, ok := anthropicWire["max_tokens"]; !ok { + t.Errorf("Expected anthropic wire output to include max_tokens") + } + if _, ok := anthropicWire["maxOutputTokens"]; ok { + t.Errorf("Expected anthropic wire output to omit source field maxOutputTokens") + } + if _, ok := anthropicWire["temperature"]; !ok { + t.Errorf("Expected anthropic wire output to include temperature") + } + if _, ok := anthropicWire["top_k"]; !ok { + t.Errorf("Expected anthropic wire output to include top_k") + } + if _, ok := anthropicWire["topK"]; ok { + t.Errorf("Expected anthropic wire output to omit source field topK") + } + if _, ok := anthropicWire["top_p"]; !ok { + t.Errorf("Expected anthropic wire output to include top_p") + } + if _, ok := anthropicWire["topP"]; ok { + t.Errorf("Expected anthropic wire output to omit source field topP") + } + if _, ok := anthropicWire["stop_sequences"]; !ok { + t.Errorf("Expected anthropic wire output to include stop_sequences") + } + if _, ok := anthropicWire["stopSequences"]; ok { + t.Errorf("Expected anthropic wire output to omit source field stopSequences") + } } diff --git a/runtime/go/prompty/model/model_test.go b/runtime/go/prompty/model/model_test.go index b2833d4d..1c530237 100644 --- a/runtime/go/prompty/model/model_test.go +++ b/runtime/go/prompty/model/model_test.go @@ -50,6 +50,16 @@ func TestModelLoadJSON(t *testing.T) { if instance.ApiType == nil || *instance.ApiType != "chat" { t.Errorf(`Expected ApiType to be "chat", got %v`, instance.ApiType) } + connectionValue, ok := instance.Connection.(prompty.ApiKeyConnection) + if !ok { + t.Fatalf("Expected Connection to be prompty.ApiKeyConnection, got %T", instance.Connection) + } + if connectionValue.Kind != "key" { + t.Errorf(`Expected Kind to be "key", got %v`, connectionValue.Kind) + } + if connectionValue.Endpoint != "https://{your-custom-endpoint}.openai.azure.com/" { + t.Errorf(`Expected Endpoint to be "https://{your-custom-endpoint}.openai.azure.com/", got %v`, connectionValue.Endpoint) + } } // TestModelLoadYAML tests loading Model from YAML @@ -87,6 +97,103 @@ options: if instance.ApiType == nil || *instance.ApiType != "chat" { t.Errorf(`Expected ApiType to be "chat", got %v`, instance.ApiType) } + connectionValue, ok := instance.Connection.(prompty.ApiKeyConnection) + if !ok { + t.Fatalf("Expected Connection to be prompty.ApiKeyConnection, got %T", instance.Connection) + } + if connectionValue.Kind != "key" { + t.Errorf(`Expected Kind to be "key", got %v`, connectionValue.Kind) + } + if connectionValue.Endpoint != "https://{your-custom-endpoint}.openai.azure.com/" { + t.Errorf(`Expected Endpoint to be "https://{your-custom-endpoint}.openai.azure.com/", got %v`, connectionValue.Endpoint) + } +} + +// TestModelFromJSON tests loading Model through the generated JSON helper +func TestModelFromJSON(t *testing.T) { + jsonData := ` +{ + "id": "gpt-35-turbo", + "provider": "foundry", + "apiType": "chat", + "connection": { + "kind": "key", + "endpoint": "https://{your-custom-endpoint}.openai.azure.com/", + "key": "{your-api-key}" + }, + "options": { + "type": "chat", + "temperature": 0.7, + "maxOutputTokens": 1000 + } +} +` + + instance, err := prompty.ModelFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load Model from JSON helper: %v", err) + } + if instance.Id != "gpt-35-turbo" { + t.Errorf(`Expected Id to be "gpt-35-turbo", got %v`, instance.Id) + } + if instance.Provider == nil || *instance.Provider != "foundry" { + t.Errorf(`Expected Provider to be "foundry", got %v`, instance.Provider) + } + if instance.ApiType == nil || *instance.ApiType != "chat" { + t.Errorf(`Expected ApiType to be "chat", got %v`, instance.ApiType) + } + connectionValue, ok := instance.Connection.(prompty.ApiKeyConnection) + if !ok { + t.Fatalf("Expected Connection to be prompty.ApiKeyConnection, got %T", instance.Connection) + } + if connectionValue.Kind != "key" { + t.Errorf(`Expected Kind to be "key", got %v`, connectionValue.Kind) + } + if connectionValue.Endpoint != "https://{your-custom-endpoint}.openai.azure.com/" { + t.Errorf(`Expected Endpoint to be "https://{your-custom-endpoint}.openai.azure.com/", got %v`, connectionValue.Endpoint) + } +} + +// TestModelFromYAML tests loading Model through the generated YAML helper +func TestModelFromYAML(t *testing.T) { + yamlData := ` +id: gpt-35-turbo +provider: foundry +apiType: chat +connection: + kind: key + endpoint: "https://{your-custom-endpoint}.openai.azure.com/" + key: "{your-api-key}" +options: + type: chat + temperature: 0.7 + maxOutputTokens: 1000 + +` + + instance, err := prompty.ModelFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load Model from YAML helper: %v", err) + } + if instance.Id != "gpt-35-turbo" { + t.Errorf(`Expected Id to be "gpt-35-turbo", got %v`, instance.Id) + } + if instance.Provider == nil || *instance.Provider != "foundry" { + t.Errorf(`Expected Provider to be "foundry", got %v`, instance.Provider) + } + if instance.ApiType == nil || *instance.ApiType != "chat" { + t.Errorf(`Expected ApiType to be "chat", got %v`, instance.ApiType) + } + connectionValue, ok := instance.Connection.(prompty.ApiKeyConnection) + if !ok { + t.Fatalf("Expected Connection to be prompty.ApiKeyConnection, got %T", instance.Connection) + } + if connectionValue.Kind != "key" { + t.Errorf(`Expected Kind to be "key", got %v`, connectionValue.Kind) + } + if connectionValue.Endpoint != "https://{your-custom-endpoint}.openai.azure.com/" { + t.Errorf(`Expected Endpoint to be "https://{your-custom-endpoint}.openai.azure.com/", got %v`, connectionValue.Endpoint) + } } // TestModelRoundtrip tests load -> save -> load produces equivalent data @@ -134,6 +241,16 @@ func TestModelRoundtrip(t *testing.T) { if reloaded.ApiType == nil || *reloaded.ApiType != "chat" { t.Errorf(`Expected ApiType to be "chat", got %v`, reloaded.ApiType) } + connectionValue, ok := reloaded.Connection.(prompty.ApiKeyConnection) + if !ok { + t.Fatalf("Expected Connection to be prompty.ApiKeyConnection, got %T", reloaded.Connection) + } + if connectionValue.Kind != "key" { + t.Errorf(`Expected Kind to be "key", got %v`, connectionValue.Kind) + } + if connectionValue.Endpoint != "https://{your-custom-endpoint}.openai.azure.com/" { + t.Errorf(`Expected Endpoint to be "https://{your-custom-endpoint}.openai.azure.com/", got %v`, connectionValue.Endpoint) + } } // TestModelToJSON tests that ToJSON produces valid JSON @@ -174,6 +291,30 @@ func TestModelToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadModel(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Id != "gpt-35-turbo" { + t.Errorf(`Expected Id to be "gpt-35-turbo", got %v`, reloaded.Id) + } + if reloaded.Provider == nil || *reloaded.Provider != "foundry" { + t.Errorf(`Expected Provider to be "foundry", got %v`, reloaded.Provider) + } + if reloaded.ApiType == nil || *reloaded.ApiType != "chat" { + t.Errorf(`Expected ApiType to be "chat", got %v`, reloaded.ApiType) + } + connectionValue, ok := reloaded.Connection.(prompty.ApiKeyConnection) + if !ok { + t.Fatalf("Expected Connection to be prompty.ApiKeyConnection, got %T", reloaded.Connection) + } + if connectionValue.Kind != "key" { + t.Errorf(`Expected Kind to be "key", got %v`, connectionValue.Kind) + } + if connectionValue.Endpoint != "https://{your-custom-endpoint}.openai.azure.com/" { + t.Errorf(`Expected Endpoint to be "https://{your-custom-endpoint}.openai.azure.com/", got %v`, connectionValue.Endpoint) + } } // TestModelToYAML tests that ToYAML produces valid YAML @@ -214,6 +355,37 @@ func TestModelToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadModel(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Id != "gpt-35-turbo" { + t.Errorf(`Expected Id to be "gpt-35-turbo", got %v`, reloaded.Id) + } + if reloaded.Provider == nil || *reloaded.Provider != "foundry" { + t.Errorf(`Expected Provider to be "foundry", got %v`, reloaded.Provider) + } + if reloaded.ApiType == nil || *reloaded.ApiType != "chat" { + t.Errorf(`Expected ApiType to be "chat", got %v`, reloaded.ApiType) + } + connectionValue, ok := reloaded.Connection.(prompty.ApiKeyConnection) + if !ok { + t.Fatalf("Expected Connection to be prompty.ApiKeyConnection, got %T", reloaded.Connection) + } + if connectionValue.Kind != "key" { + t.Errorf(`Expected Kind to be "key", got %v`, connectionValue.Kind) + } + if connectionValue.Endpoint != "https://{your-custom-endpoint}.openai.azure.com/" { + t.Errorf(`Expected Endpoint to be "https://{your-custom-endpoint}.openai.azure.com/", got %v`, connectionValue.Endpoint) + } +} + +// TestModelFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestModelFromJSONInvalid(t *testing.T) { + if _, err := prompty.ModelFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } // TestModelFromModel tests loading Model from string diff --git a/runtime/go/prompty/model/o_auth_connection_test.go b/runtime/go/prompty/model/o_auth_connection_test.go index 2319b8c2..09b5ff15 100644 --- a/runtime/go/prompty/model/o_auth_connection_test.go +++ b/runtime/go/prompty/model/o_auth_connection_test.go @@ -51,6 +51,12 @@ func TestOAuthConnectionLoadJSON(t *testing.T) { if instance.TokenUrl != "https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token" { t.Errorf(`Expected TokenUrl to be "https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token", got %v`, instance.TokenUrl) } + if len(instance.Scopes) != 1 { + t.Fatalf("Expected Scopes length to be 1, got %d", len(instance.Scopes)) + } + if instance.Scopes[0] != "https://cognitiveservices.azure.com/.default" { + t.Errorf(`Expected Scopes[0] to be "https://cognitiveservices.azure.com/.default", got %v`, instance.Scopes[0]) + } } // TestOAuthConnectionLoadYAML tests loading OAuthConnection from YAML @@ -90,6 +96,94 @@ scopes: if instance.TokenUrl != "https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token" { t.Errorf(`Expected TokenUrl to be "https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token", got %v`, instance.TokenUrl) } + if len(instance.Scopes) != 1 { + t.Fatalf("Expected Scopes length to be 1, got %d", len(instance.Scopes)) + } + if instance.Scopes[0] != "https://cognitiveservices.azure.com/.default" { + t.Errorf(`Expected Scopes[0] to be "https://cognitiveservices.azure.com/.default", got %v`, instance.Scopes[0]) + } +} + +// TestOAuthConnectionFromJSON tests loading OAuthConnection through the generated JSON helper +func TestOAuthConnectionFromJSON(t *testing.T) { + jsonData := ` +{ + "kind": "oauth", + "endpoint": "https://api.example.com", + "clientId": "your-client-id", + "clientSecret": "your-client-secret", + "tokenUrl": "https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token", + "scopes": [ + "https://cognitiveservices.azure.com/.default" + ] +} +` + + instance, err := prompty.OAuthConnectionFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load OAuthConnection from JSON helper: %v", err) + } + if instance.Kind != "oauth" { + t.Errorf(`Expected Kind to be "oauth", got %v`, instance.Kind) + } + if instance.Endpoint != "https://api.example.com" { + t.Errorf(`Expected Endpoint to be "https://api.example.com", got %v`, instance.Endpoint) + } + if instance.ClientId != "your-client-id" { + t.Errorf(`Expected ClientId to be "your-client-id", got %v`, instance.ClientId) + } + if instance.ClientSecret != "your-client-secret" { + t.Errorf(`Expected ClientSecret to be "your-client-secret", got %v`, instance.ClientSecret) + } + if instance.TokenUrl != "https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token" { + t.Errorf(`Expected TokenUrl to be "https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token", got %v`, instance.TokenUrl) + } + if len(instance.Scopes) != 1 { + t.Fatalf("Expected Scopes length to be 1, got %d", len(instance.Scopes)) + } + if instance.Scopes[0] != "https://cognitiveservices.azure.com/.default" { + t.Errorf(`Expected Scopes[0] to be "https://cognitiveservices.azure.com/.default", got %v`, instance.Scopes[0]) + } +} + +// TestOAuthConnectionFromYAML tests loading OAuthConnection through the generated YAML helper +func TestOAuthConnectionFromYAML(t *testing.T) { + yamlData := ` +kind: oauth +endpoint: "https://api.example.com" +clientId: your-client-id +clientSecret: your-client-secret +tokenUrl: "https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token" +scopes: + - "https://cognitiveservices.azure.com/.default" + +` + + instance, err := prompty.OAuthConnectionFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load OAuthConnection from YAML helper: %v", err) + } + if instance.Kind != "oauth" { + t.Errorf(`Expected Kind to be "oauth", got %v`, instance.Kind) + } + if instance.Endpoint != "https://api.example.com" { + t.Errorf(`Expected Endpoint to be "https://api.example.com", got %v`, instance.Endpoint) + } + if instance.ClientId != "your-client-id" { + t.Errorf(`Expected ClientId to be "your-client-id", got %v`, instance.ClientId) + } + if instance.ClientSecret != "your-client-secret" { + t.Errorf(`Expected ClientSecret to be "your-client-secret", got %v`, instance.ClientSecret) + } + if instance.TokenUrl != "https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token" { + t.Errorf(`Expected TokenUrl to be "https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token", got %v`, instance.TokenUrl) + } + if len(instance.Scopes) != 1 { + t.Fatalf("Expected Scopes length to be 1, got %d", len(instance.Scopes)) + } + if instance.Scopes[0] != "https://cognitiveservices.azure.com/.default" { + t.Errorf(`Expected Scopes[0] to be "https://cognitiveservices.azure.com/.default", got %v`, instance.Scopes[0]) + } } // TestOAuthConnectionRoundtrip tests load -> save -> load produces equivalent data @@ -138,6 +232,12 @@ func TestOAuthConnectionRoundtrip(t *testing.T) { if reloaded.TokenUrl != "https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token" { t.Errorf(`Expected TokenUrl to be "https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token", got %v`, reloaded.TokenUrl) } + if len(reloaded.Scopes) != 1 { + t.Fatalf("Expected Scopes length to be 1, got %d", len(reloaded.Scopes)) + } + if reloaded.Scopes[0] != "https://cognitiveservices.azure.com/.default" { + t.Errorf(`Expected Scopes[0] to be "https://cognitiveservices.azure.com/.default", got %v`, reloaded.Scopes[0]) + } } // TestOAuthConnectionToJSON tests that ToJSON produces valid JSON @@ -173,6 +273,32 @@ func TestOAuthConnectionToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadOAuthConnection(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Kind != "oauth" { + t.Errorf(`Expected Kind to be "oauth", got %v`, reloaded.Kind) + } + if reloaded.Endpoint != "https://api.example.com" { + t.Errorf(`Expected Endpoint to be "https://api.example.com", got %v`, reloaded.Endpoint) + } + if reloaded.ClientId != "your-client-id" { + t.Errorf(`Expected ClientId to be "your-client-id", got %v`, reloaded.ClientId) + } + if reloaded.ClientSecret != "your-client-secret" { + t.Errorf(`Expected ClientSecret to be "your-client-secret", got %v`, reloaded.ClientSecret) + } + if reloaded.TokenUrl != "https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token" { + t.Errorf(`Expected TokenUrl to be "https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token", got %v`, reloaded.TokenUrl) + } + if len(reloaded.Scopes) != 1 { + t.Fatalf("Expected Scopes length to be 1, got %d", len(reloaded.Scopes)) + } + if reloaded.Scopes[0] != "https://cognitiveservices.azure.com/.default" { + t.Errorf(`Expected Scopes[0] to be "https://cognitiveservices.azure.com/.default", got %v`, reloaded.Scopes[0]) + } } // TestOAuthConnectionToYAML tests that ToYAML produces valid YAML @@ -208,4 +334,37 @@ func TestOAuthConnectionToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadOAuthConnection(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Kind != "oauth" { + t.Errorf(`Expected Kind to be "oauth", got %v`, reloaded.Kind) + } + if reloaded.Endpoint != "https://api.example.com" { + t.Errorf(`Expected Endpoint to be "https://api.example.com", got %v`, reloaded.Endpoint) + } + if reloaded.ClientId != "your-client-id" { + t.Errorf(`Expected ClientId to be "your-client-id", got %v`, reloaded.ClientId) + } + if reloaded.ClientSecret != "your-client-secret" { + t.Errorf(`Expected ClientSecret to be "your-client-secret", got %v`, reloaded.ClientSecret) + } + if reloaded.TokenUrl != "https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token" { + t.Errorf(`Expected TokenUrl to be "https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token", got %v`, reloaded.TokenUrl) + } + if len(reloaded.Scopes) != 1 { + t.Fatalf("Expected Scopes length to be 1, got %d", len(reloaded.Scopes)) + } + if reloaded.Scopes[0] != "https://cognitiveservices.azure.com/.default" { + t.Errorf(`Expected Scopes[0] to be "https://cognitiveservices.azure.com/.default", got %v`, reloaded.Scopes[0]) + } +} + +// TestOAuthConnectionFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestOAuthConnectionFromJSONInvalid(t *testing.T) { + if _, err := prompty.OAuthConnectionFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/object_property_test.go b/runtime/go/prompty/model/object_property_test.go index 6f61ef6f..16f8c975 100644 --- a/runtime/go/prompty/model/object_property_test.go +++ b/runtime/go/prompty/model/object_property_test.go @@ -62,6 +62,46 @@ properties: _ = instance // No scalar properties to validate } +// TestObjectPropertyFromJSON tests loading ObjectProperty through the generated JSON helper +func TestObjectPropertyFromJSON(t *testing.T) { + jsonData := ` +{ + "properties": { + "property1": { + "kind": "string" + }, + "property2": { + "kind": "number" + } + } +} +` + + instance, err := prompty.ObjectPropertyFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load ObjectProperty from JSON helper: %v", err) + } + _ = instance // No scalar properties to validate +} + +// TestObjectPropertyFromYAML tests loading ObjectProperty through the generated YAML helper +func TestObjectPropertyFromYAML(t *testing.T) { + yamlData := ` +properties: + property1: + kind: string + property2: + kind: number + +` + + instance, err := prompty.ObjectPropertyFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load ObjectProperty from YAML helper: %v", err) + } + _ = instance // No scalar properties to validate +} + // TestObjectPropertyRoundtrip tests load -> save -> load produces equivalent data func TestObjectPropertyRoundtrip(t *testing.T) { jsonData := ` @@ -129,6 +169,12 @@ func TestObjectPropertyToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadObjectProperty(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + _ = reloaded // No scalar properties to validate } // TestObjectPropertyToYAML tests that ToYAML produces valid YAML @@ -164,4 +210,17 @@ func TestObjectPropertyToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadObjectProperty(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + _ = reloaded // No scalar properties to validate +} + +// TestObjectPropertyFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestObjectPropertyFromJSONInvalid(t *testing.T) { + if _, err := prompty.ObjectPropertyFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/open_api_tool_test.go b/runtime/go/prompty/model/open_api_tool_test.go index d1fdf749..25dfc691 100644 --- a/runtime/go/prompty/model/open_api_tool_test.go +++ b/runtime/go/prompty/model/open_api_tool_test.go @@ -68,6 +68,52 @@ specification: ./openapi.json } } +// TestOpenApiToolFromJSON tests loading OpenApiTool through the generated JSON helper +func TestOpenApiToolFromJSON(t *testing.T) { + jsonData := ` +{ + "kind": "openapi", + "connection": { + "kind": "reference" + }, + "specification": "./openapi.json" +} +` + + instance, err := prompty.OpenApiToolFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load OpenApiTool from JSON helper: %v", err) + } + if instance.Kind != "openapi" { + t.Errorf(`Expected Kind to be "openapi", got %v`, instance.Kind) + } + if instance.Specification != "./openapi.json" { + t.Errorf(`Expected Specification to be "./openapi.json", got %v`, instance.Specification) + } +} + +// TestOpenApiToolFromYAML tests loading OpenApiTool through the generated YAML helper +func TestOpenApiToolFromYAML(t *testing.T) { + yamlData := ` +kind: openapi +connection: + kind: reference +specification: ./openapi.json + +` + + instance, err := prompty.OpenApiToolFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load OpenApiTool from YAML helper: %v", err) + } + if instance.Kind != "openapi" { + t.Errorf(`Expected Kind to be "openapi", got %v`, instance.Kind) + } + if instance.Specification != "./openapi.json" { + t.Errorf(`Expected Specification to be "./openapi.json", got %v`, instance.Specification) + } +} + // TestOpenApiToolRoundtrip tests load -> save -> load produces equivalent data func TestOpenApiToolRoundtrip(t *testing.T) { jsonData := ` @@ -134,6 +180,17 @@ func TestOpenApiToolToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadOpenApiTool(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Kind != "openapi" { + t.Errorf(`Expected Kind to be "openapi", got %v`, reloaded.Kind) + } + if reloaded.Specification != "./openapi.json" { + t.Errorf(`Expected Specification to be "./openapi.json", got %v`, reloaded.Specification) + } } // TestOpenApiToolToYAML tests that ToYAML produces valid YAML @@ -166,4 +223,22 @@ func TestOpenApiToolToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadOpenApiTool(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Kind != "openapi" { + t.Errorf(`Expected Kind to be "openapi", got %v`, reloaded.Kind) + } + if reloaded.Specification != "./openapi.json" { + t.Errorf(`Expected Specification to be "./openapi.json", got %v`, reloaded.Specification) + } +} + +// TestOpenApiToolFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestOpenApiToolFromJSONInvalid(t *testing.T) { + if _, err := prompty.OpenApiToolFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/parser_config.go b/runtime/go/prompty/model/parser_config.go index b6f30c57..d100d23e 100644 --- a/runtime/go/prompty/model/parser_config.go +++ b/runtime/go/prompty/model/parser_config.go @@ -44,7 +44,7 @@ func LoadParserConfig(data interface{}, ctx *LoadContext) (ParserConfig, error) } // Save serializes ParserConfig to map[string]interface{} -func (obj *ParserConfig) Save(ctx *SaveContext) map[string]interface{} { +func (obj ParserConfig) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["kind"] = obj.Kind if obj.Options != nil { @@ -69,11 +69,7 @@ func (obj *ParserConfig) ToJSON() (string, error) { func (obj *ParserConfig) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates ParserConfig from JSON string diff --git a/runtime/go/prompty/model/parser_config_test.go b/runtime/go/prompty/model/parser_config_test.go index 9cb689b2..763a0184 100644 --- a/runtime/go/prompty/model/parser_config_test.go +++ b/runtime/go/prompty/model/parser_config_test.go @@ -60,6 +60,44 @@ options: // Note: Validation skipped for polymorphic base types - test child types directly } +// TestParserConfigFromJSON tests loading ParserConfig through the generated JSON helper +func TestParserConfigFromJSON(t *testing.T) { + jsonData := ` +{ + "kind": "prompty", + "options": { + "key": "value" + } +} +` + + instance, err := prompty.ParserConfigFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load ParserConfig from JSON helper: %v", err) + } + // Polymorphic types return interface{}, extract common fields via reflection or type-specific access + _ = instance // Load succeeded, exact type depends on discriminator + // Note: Validation skipped for polymorphic base types - test child types directly +} + +// TestParserConfigFromYAML tests loading ParserConfig through the generated YAML helper +func TestParserConfigFromYAML(t *testing.T) { + yamlData := ` +kind: prompty +options: + key: value + +` + + instance, err := prompty.ParserConfigFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load ParserConfig from YAML helper: %v", err) + } + // Polymorphic types return interface{}, extract common fields via reflection or type-specific access + _ = instance // Load succeeded, exact type depends on discriminator + // Note: Validation skipped for polymorphic base types - test child types directly +} + // TestParserConfigRoundtrip tests load -> save -> load produces equivalent data func TestParserConfigRoundtrip(t *testing.T) { jsonData := ` @@ -135,6 +173,13 @@ func TestParserConfigToYAML(t *testing.T) { // Note: ToYAML test skipped for polymorphic base types - test child types directly } +// TestParserConfigFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestParserConfigFromJSONInvalid(t *testing.T) { + if _, err := prompty.ParserConfigFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } +} + // TestParserConfigFromParser tests loading ParserConfig from string func TestParserConfigFromParser(t *testing.T) { ctx := prompty.NewLoadContext() diff --git a/runtime/go/prompty/model/permission_completed_payload.go b/runtime/go/prompty/model/permission_completed_payload.go index feb1fb9f..ea08ce44 100644 --- a/runtime/go/prompty/model/permission_completed_payload.go +++ b/runtime/go/prompty/model/permission_completed_payload.go @@ -63,7 +63,7 @@ func LoadPermissionCompletedPayload(data interface{}, ctx *LoadContext) (Permiss } // Save serializes PermissionCompletedPayload to map[string]interface{} -func (obj *PermissionCompletedPayload) Save(ctx *SaveContext) map[string]interface{} { +func (obj PermissionCompletedPayload) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) if obj.RequestId != nil { result["requestId"] = *obj.RequestId @@ -101,11 +101,7 @@ func (obj *PermissionCompletedPayload) ToJSON() (string, error) { func (obj *PermissionCompletedPayload) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates PermissionCompletedPayload from JSON string diff --git a/runtime/go/prompty/model/permission_completed_payload_test.go b/runtime/go/prompty/model/permission_completed_payload_test.go index 182067e3..7aee727b 100644 --- a/runtime/go/prompty/model/permission_completed_payload_test.go +++ b/runtime/go/prompty/model/permission_completed_payload_test.go @@ -87,6 +87,71 @@ reason: user_approved } } +// TestPermissionCompletedPayloadFromJSON tests loading PermissionCompletedPayload through the generated JSON helper +func TestPermissionCompletedPayloadFromJSON(t *testing.T) { + jsonData := ` +{ + "requestId": "perm_abc123", + "toolCallId": "call_abc123", + "permission": "tool.execute", + "approved": true, + "reason": "user_approved" +} +` + + instance, err := prompty.PermissionCompletedPayloadFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load PermissionCompletedPayload from JSON helper: %v", err) + } + if instance.RequestId == nil || *instance.RequestId != "perm_abc123" { + t.Errorf(`Expected RequestId to be "perm_abc123", got %v`, instance.RequestId) + } + if instance.ToolCallId == nil || *instance.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, instance.ToolCallId) + } + if instance.Permission != "tool.execute" { + t.Errorf(`Expected Permission to be "tool.execute", got %v`, instance.Permission) + } + if instance.Approved != true { + t.Errorf(`Expected Approved to be true, got %v`, instance.Approved) + } + if instance.Reason == nil || *instance.Reason != "user_approved" { + t.Errorf(`Expected Reason to be "user_approved", got %v`, instance.Reason) + } +} + +// TestPermissionCompletedPayloadFromYAML tests loading PermissionCompletedPayload through the generated YAML helper +func TestPermissionCompletedPayloadFromYAML(t *testing.T) { + yamlData := ` +requestId: perm_abc123 +toolCallId: call_abc123 +permission: tool.execute +approved: true +reason: user_approved + +` + + instance, err := prompty.PermissionCompletedPayloadFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load PermissionCompletedPayload from YAML helper: %v", err) + } + if instance.RequestId == nil || *instance.RequestId != "perm_abc123" { + t.Errorf(`Expected RequestId to be "perm_abc123", got %v`, instance.RequestId) + } + if instance.ToolCallId == nil || *instance.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, instance.ToolCallId) + } + if instance.Permission != "tool.execute" { + t.Errorf(`Expected Permission to be "tool.execute", got %v`, instance.Permission) + } + if instance.Approved != true { + t.Errorf(`Expected Approved to be true, got %v`, instance.Approved) + } + if instance.Reason == nil || *instance.Reason != "user_approved" { + t.Errorf(`Expected Reason to be "user_approved", got %v`, instance.Reason) + } +} + // TestPermissionCompletedPayloadRoundtrip tests load -> save -> load produces equivalent data func TestPermissionCompletedPayloadRoundtrip(t *testing.T) { jsonData := ` @@ -162,6 +227,26 @@ func TestPermissionCompletedPayloadToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadPermissionCompletedPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.RequestId == nil || *reloaded.RequestId != "perm_abc123" { + t.Errorf(`Expected RequestId to be "perm_abc123", got %v`, reloaded.RequestId) + } + if reloaded.ToolCallId == nil || *reloaded.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, reloaded.ToolCallId) + } + if reloaded.Permission != "tool.execute" { + t.Errorf(`Expected Permission to be "tool.execute", got %v`, reloaded.Permission) + } + if reloaded.Approved != true { + t.Errorf(`Expected Approved to be true, got %v`, reloaded.Approved) + } + if reloaded.Reason == nil || *reloaded.Reason != "user_approved" { + t.Errorf(`Expected Reason to be "user_approved", got %v`, reloaded.Reason) + } } // TestPermissionCompletedPayloadToYAML tests that ToYAML produces valid YAML @@ -194,4 +279,31 @@ func TestPermissionCompletedPayloadToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadPermissionCompletedPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.RequestId == nil || *reloaded.RequestId != "perm_abc123" { + t.Errorf(`Expected RequestId to be "perm_abc123", got %v`, reloaded.RequestId) + } + if reloaded.ToolCallId == nil || *reloaded.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, reloaded.ToolCallId) + } + if reloaded.Permission != "tool.execute" { + t.Errorf(`Expected Permission to be "tool.execute", got %v`, reloaded.Permission) + } + if reloaded.Approved != true { + t.Errorf(`Expected Approved to be true, got %v`, reloaded.Approved) + } + if reloaded.Reason == nil || *reloaded.Reason != "user_approved" { + t.Errorf(`Expected Reason to be "user_approved", got %v`, reloaded.Reason) + } +} + +// TestPermissionCompletedPayloadFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestPermissionCompletedPayloadFromJSONInvalid(t *testing.T) { + if _, err := prompty.PermissionCompletedPayloadFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/permission_decision.go b/runtime/go/prompty/model/permission_decision.go index e7776100..ef20fbf9 100644 --- a/runtime/go/prompty/model/permission_decision.go +++ b/runtime/go/prompty/model/permission_decision.go @@ -56,7 +56,7 @@ func LoadPermissionDecision(data interface{}, ctx *LoadContext) (PermissionDecis } // Save serializes PermissionDecision to map[string]interface{} -func (obj *PermissionDecision) Save(ctx *SaveContext) map[string]interface{} { +func (obj PermissionDecision) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) if obj.RequestId != nil { result["requestId"] = *obj.RequestId @@ -91,11 +91,7 @@ func (obj *PermissionDecision) ToJSON() (string, error) { func (obj *PermissionDecision) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates PermissionDecision from JSON string diff --git a/runtime/go/prompty/model/permission_decision_test.go b/runtime/go/prompty/model/permission_decision_test.go index ed5ccea9..d786da6d 100644 --- a/runtime/go/prompty/model/permission_decision_test.go +++ b/runtime/go/prompty/model/permission_decision_test.go @@ -87,6 +87,71 @@ reason: user_approved } } +// TestPermissionDecisionFromJSON tests loading PermissionDecision through the generated JSON helper +func TestPermissionDecisionFromJSON(t *testing.T) { + jsonData := ` +{ + "requestId": "perm_abc123", + "toolCallId": "call_abc123", + "permission": "tool.execute", + "approved": true, + "reason": "user_approved" +} +` + + instance, err := prompty.PermissionDecisionFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load PermissionDecision from JSON helper: %v", err) + } + if instance.RequestId == nil || *instance.RequestId != "perm_abc123" { + t.Errorf(`Expected RequestId to be "perm_abc123", got %v`, instance.RequestId) + } + if instance.ToolCallId == nil || *instance.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, instance.ToolCallId) + } + if instance.Permission != "tool.execute" { + t.Errorf(`Expected Permission to be "tool.execute", got %v`, instance.Permission) + } + if instance.Approved != true { + t.Errorf(`Expected Approved to be true, got %v`, instance.Approved) + } + if instance.Reason == nil || *instance.Reason != "user_approved" { + t.Errorf(`Expected Reason to be "user_approved", got %v`, instance.Reason) + } +} + +// TestPermissionDecisionFromYAML tests loading PermissionDecision through the generated YAML helper +func TestPermissionDecisionFromYAML(t *testing.T) { + yamlData := ` +requestId: perm_abc123 +toolCallId: call_abc123 +permission: tool.execute +approved: true +reason: user_approved + +` + + instance, err := prompty.PermissionDecisionFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load PermissionDecision from YAML helper: %v", err) + } + if instance.RequestId == nil || *instance.RequestId != "perm_abc123" { + t.Errorf(`Expected RequestId to be "perm_abc123", got %v`, instance.RequestId) + } + if instance.ToolCallId == nil || *instance.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, instance.ToolCallId) + } + if instance.Permission != "tool.execute" { + t.Errorf(`Expected Permission to be "tool.execute", got %v`, instance.Permission) + } + if instance.Approved != true { + t.Errorf(`Expected Approved to be true, got %v`, instance.Approved) + } + if instance.Reason == nil || *instance.Reason != "user_approved" { + t.Errorf(`Expected Reason to be "user_approved", got %v`, instance.Reason) + } +} + // TestPermissionDecisionRoundtrip tests load -> save -> load produces equivalent data func TestPermissionDecisionRoundtrip(t *testing.T) { jsonData := ` @@ -162,6 +227,26 @@ func TestPermissionDecisionToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadPermissionDecision(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.RequestId == nil || *reloaded.RequestId != "perm_abc123" { + t.Errorf(`Expected RequestId to be "perm_abc123", got %v`, reloaded.RequestId) + } + if reloaded.ToolCallId == nil || *reloaded.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, reloaded.ToolCallId) + } + if reloaded.Permission != "tool.execute" { + t.Errorf(`Expected Permission to be "tool.execute", got %v`, reloaded.Permission) + } + if reloaded.Approved != true { + t.Errorf(`Expected Approved to be true, got %v`, reloaded.Approved) + } + if reloaded.Reason == nil || *reloaded.Reason != "user_approved" { + t.Errorf(`Expected Reason to be "user_approved", got %v`, reloaded.Reason) + } } // TestPermissionDecisionToYAML tests that ToYAML produces valid YAML @@ -194,4 +279,31 @@ func TestPermissionDecisionToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadPermissionDecision(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.RequestId == nil || *reloaded.RequestId != "perm_abc123" { + t.Errorf(`Expected RequestId to be "perm_abc123", got %v`, reloaded.RequestId) + } + if reloaded.ToolCallId == nil || *reloaded.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, reloaded.ToolCallId) + } + if reloaded.Permission != "tool.execute" { + t.Errorf(`Expected Permission to be "tool.execute", got %v`, reloaded.Permission) + } + if reloaded.Approved != true { + t.Errorf(`Expected Approved to be true, got %v`, reloaded.Approved) + } + if reloaded.Reason == nil || *reloaded.Reason != "user_approved" { + t.Errorf(`Expected Reason to be "user_approved", got %v`, reloaded.Reason) + } +} + +// TestPermissionDecisionFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestPermissionDecisionFromJSONInvalid(t *testing.T) { + if _, err := prompty.PermissionDecisionFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/permission_request.go b/runtime/go/prompty/model/permission_request.go index 2e6e90de..414e95ff 100644 --- a/runtime/go/prompty/model/permission_request.go +++ b/runtime/go/prompty/model/permission_request.go @@ -64,7 +64,7 @@ func LoadPermissionRequest(data interface{}, ctx *LoadContext) (PermissionReques } // Save serializes PermissionRequest to map[string]interface{} -func (obj *PermissionRequest) Save(ctx *SaveContext) map[string]interface{} { +func (obj PermissionRequest) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) if obj.RequestId != nil { result["requestId"] = *obj.RequestId @@ -104,11 +104,7 @@ func (obj *PermissionRequest) ToJSON() (string, error) { func (obj *PermissionRequest) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates PermissionRequest from JSON string diff --git a/runtime/go/prompty/model/permission_request_test.go b/runtime/go/prompty/model/permission_request_test.go index 5f3574ea..091d046c 100644 --- a/runtime/go/prompty/model/permission_request_test.go +++ b/runtime/go/prompty/model/permission_request_test.go @@ -87,6 +87,71 @@ promptRequest: Allow shell to run tests? } } +// TestPermissionRequestFromJSON tests loading PermissionRequest through the generated JSON helper +func TestPermissionRequestFromJSON(t *testing.T) { + jsonData := ` +{ + "requestId": "perm_abc123", + "toolCallId": "call_abc123", + "permission": "tool.execute", + "target": "shell", + "promptRequest": "Allow shell to run tests?" +} +` + + instance, err := prompty.PermissionRequestFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load PermissionRequest from JSON helper: %v", err) + } + if instance.RequestId == nil || *instance.RequestId != "perm_abc123" { + t.Errorf(`Expected RequestId to be "perm_abc123", got %v`, instance.RequestId) + } + if instance.ToolCallId == nil || *instance.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, instance.ToolCallId) + } + if instance.Permission != "tool.execute" { + t.Errorf(`Expected Permission to be "tool.execute", got %v`, instance.Permission) + } + if instance.Target == nil || *instance.Target != "shell" { + t.Errorf(`Expected Target to be "shell", got %v`, instance.Target) + } + if instance.PromptRequest == nil || *instance.PromptRequest != "Allow shell to run tests?" { + t.Errorf(`Expected PromptRequest to be "Allow shell to run tests?", got %v`, instance.PromptRequest) + } +} + +// TestPermissionRequestFromYAML tests loading PermissionRequest through the generated YAML helper +func TestPermissionRequestFromYAML(t *testing.T) { + yamlData := ` +requestId: perm_abc123 +toolCallId: call_abc123 +permission: tool.execute +target: shell +promptRequest: Allow shell to run tests? + +` + + instance, err := prompty.PermissionRequestFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load PermissionRequest from YAML helper: %v", err) + } + if instance.RequestId == nil || *instance.RequestId != "perm_abc123" { + t.Errorf(`Expected RequestId to be "perm_abc123", got %v`, instance.RequestId) + } + if instance.ToolCallId == nil || *instance.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, instance.ToolCallId) + } + if instance.Permission != "tool.execute" { + t.Errorf(`Expected Permission to be "tool.execute", got %v`, instance.Permission) + } + if instance.Target == nil || *instance.Target != "shell" { + t.Errorf(`Expected Target to be "shell", got %v`, instance.Target) + } + if instance.PromptRequest == nil || *instance.PromptRequest != "Allow shell to run tests?" { + t.Errorf(`Expected PromptRequest to be "Allow shell to run tests?", got %v`, instance.PromptRequest) + } +} + // TestPermissionRequestRoundtrip tests load -> save -> load produces equivalent data func TestPermissionRequestRoundtrip(t *testing.T) { jsonData := ` @@ -162,6 +227,26 @@ func TestPermissionRequestToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadPermissionRequest(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.RequestId == nil || *reloaded.RequestId != "perm_abc123" { + t.Errorf(`Expected RequestId to be "perm_abc123", got %v`, reloaded.RequestId) + } + if reloaded.ToolCallId == nil || *reloaded.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, reloaded.ToolCallId) + } + if reloaded.Permission != "tool.execute" { + t.Errorf(`Expected Permission to be "tool.execute", got %v`, reloaded.Permission) + } + if reloaded.Target == nil || *reloaded.Target != "shell" { + t.Errorf(`Expected Target to be "shell", got %v`, reloaded.Target) + } + if reloaded.PromptRequest == nil || *reloaded.PromptRequest != "Allow shell to run tests?" { + t.Errorf(`Expected PromptRequest to be "Allow shell to run tests?", got %v`, reloaded.PromptRequest) + } } // TestPermissionRequestToYAML tests that ToYAML produces valid YAML @@ -194,4 +279,31 @@ func TestPermissionRequestToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadPermissionRequest(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.RequestId == nil || *reloaded.RequestId != "perm_abc123" { + t.Errorf(`Expected RequestId to be "perm_abc123", got %v`, reloaded.RequestId) + } + if reloaded.ToolCallId == nil || *reloaded.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, reloaded.ToolCallId) + } + if reloaded.Permission != "tool.execute" { + t.Errorf(`Expected Permission to be "tool.execute", got %v`, reloaded.Permission) + } + if reloaded.Target == nil || *reloaded.Target != "shell" { + t.Errorf(`Expected Target to be "shell", got %v`, reloaded.Target) + } + if reloaded.PromptRequest == nil || *reloaded.PromptRequest != "Allow shell to run tests?" { + t.Errorf(`Expected PromptRequest to be "Allow shell to run tests?", got %v`, reloaded.PromptRequest) + } +} + +// TestPermissionRequestFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestPermissionRequestFromJSONInvalid(t *testing.T) { + if _, err := prompty.PermissionRequestFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/permission_requested_payload.go b/runtime/go/prompty/model/permission_requested_payload.go index 2ecd64ea..81969518 100644 --- a/runtime/go/prompty/model/permission_requested_payload.go +++ b/runtime/go/prompty/model/permission_requested_payload.go @@ -70,7 +70,7 @@ func LoadPermissionRequestedPayload(data interface{}, ctx *LoadContext) (Permiss } // Save serializes PermissionRequestedPayload to map[string]interface{} -func (obj *PermissionRequestedPayload) Save(ctx *SaveContext) map[string]interface{} { +func (obj PermissionRequestedPayload) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) if obj.RequestId != nil { result["requestId"] = *obj.RequestId @@ -113,11 +113,7 @@ func (obj *PermissionRequestedPayload) ToJSON() (string, error) { func (obj *PermissionRequestedPayload) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates PermissionRequestedPayload from JSON string diff --git a/runtime/go/prompty/model/permission_requested_payload_test.go b/runtime/go/prompty/model/permission_requested_payload_test.go index 0c0de7b6..9e6dfa35 100644 --- a/runtime/go/prompty/model/permission_requested_payload_test.go +++ b/runtime/go/prompty/model/permission_requested_payload_test.go @@ -87,6 +87,71 @@ promptRequest: Allow shell to run tests? } } +// TestPermissionRequestedPayloadFromJSON tests loading PermissionRequestedPayload through the generated JSON helper +func TestPermissionRequestedPayloadFromJSON(t *testing.T) { + jsonData := ` +{ + "requestId": "perm_abc123", + "toolCallId": "call_abc123", + "permission": "tool.execute", + "target": "shell", + "promptRequest": "Allow shell to run tests?" +} +` + + instance, err := prompty.PermissionRequestedPayloadFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load PermissionRequestedPayload from JSON helper: %v", err) + } + if instance.RequestId == nil || *instance.RequestId != "perm_abc123" { + t.Errorf(`Expected RequestId to be "perm_abc123", got %v`, instance.RequestId) + } + if instance.ToolCallId == nil || *instance.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, instance.ToolCallId) + } + if instance.Permission != "tool.execute" { + t.Errorf(`Expected Permission to be "tool.execute", got %v`, instance.Permission) + } + if instance.Target == nil || *instance.Target != "shell" { + t.Errorf(`Expected Target to be "shell", got %v`, instance.Target) + } + if instance.PromptRequest == nil || *instance.PromptRequest != "Allow shell to run tests?" { + t.Errorf(`Expected PromptRequest to be "Allow shell to run tests?", got %v`, instance.PromptRequest) + } +} + +// TestPermissionRequestedPayloadFromYAML tests loading PermissionRequestedPayload through the generated YAML helper +func TestPermissionRequestedPayloadFromYAML(t *testing.T) { + yamlData := ` +requestId: perm_abc123 +toolCallId: call_abc123 +permission: tool.execute +target: shell +promptRequest: Allow shell to run tests? + +` + + instance, err := prompty.PermissionRequestedPayloadFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load PermissionRequestedPayload from YAML helper: %v", err) + } + if instance.RequestId == nil || *instance.RequestId != "perm_abc123" { + t.Errorf(`Expected RequestId to be "perm_abc123", got %v`, instance.RequestId) + } + if instance.ToolCallId == nil || *instance.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, instance.ToolCallId) + } + if instance.Permission != "tool.execute" { + t.Errorf(`Expected Permission to be "tool.execute", got %v`, instance.Permission) + } + if instance.Target == nil || *instance.Target != "shell" { + t.Errorf(`Expected Target to be "shell", got %v`, instance.Target) + } + if instance.PromptRequest == nil || *instance.PromptRequest != "Allow shell to run tests?" { + t.Errorf(`Expected PromptRequest to be "Allow shell to run tests?", got %v`, instance.PromptRequest) + } +} + // TestPermissionRequestedPayloadRoundtrip tests load -> save -> load produces equivalent data func TestPermissionRequestedPayloadRoundtrip(t *testing.T) { jsonData := ` @@ -162,6 +227,26 @@ func TestPermissionRequestedPayloadToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadPermissionRequestedPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.RequestId == nil || *reloaded.RequestId != "perm_abc123" { + t.Errorf(`Expected RequestId to be "perm_abc123", got %v`, reloaded.RequestId) + } + if reloaded.ToolCallId == nil || *reloaded.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, reloaded.ToolCallId) + } + if reloaded.Permission != "tool.execute" { + t.Errorf(`Expected Permission to be "tool.execute", got %v`, reloaded.Permission) + } + if reloaded.Target == nil || *reloaded.Target != "shell" { + t.Errorf(`Expected Target to be "shell", got %v`, reloaded.Target) + } + if reloaded.PromptRequest == nil || *reloaded.PromptRequest != "Allow shell to run tests?" { + t.Errorf(`Expected PromptRequest to be "Allow shell to run tests?", got %v`, reloaded.PromptRequest) + } } // TestPermissionRequestedPayloadToYAML tests that ToYAML produces valid YAML @@ -194,4 +279,31 @@ func TestPermissionRequestedPayloadToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadPermissionRequestedPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.RequestId == nil || *reloaded.RequestId != "perm_abc123" { + t.Errorf(`Expected RequestId to be "perm_abc123", got %v`, reloaded.RequestId) + } + if reloaded.ToolCallId == nil || *reloaded.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, reloaded.ToolCallId) + } + if reloaded.Permission != "tool.execute" { + t.Errorf(`Expected Permission to be "tool.execute", got %v`, reloaded.Permission) + } + if reloaded.Target == nil || *reloaded.Target != "shell" { + t.Errorf(`Expected Target to be "shell", got %v`, reloaded.Target) + } + if reloaded.PromptRequest == nil || *reloaded.PromptRequest != "Allow shell to run tests?" { + t.Errorf(`Expected PromptRequest to be "Allow shell to run tests?", got %v`, reloaded.PromptRequest) + } +} + +// TestPermissionRequestedPayloadFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestPermissionRequestedPayloadFromJSONInvalid(t *testing.T) { + if _, err := prompty.PermissionRequestedPayloadFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/prompty.go b/runtime/go/prompty/model/prompty.go index 1b499432..82ae8e98 100644 --- a/runtime/go/prompty/model/prompty.go +++ b/runtime/go/prompty/model/prompty.go @@ -86,6 +86,9 @@ func LoadPrompty(data interface{}, ctx *LoadContext) (Prompty, error) { if m, ok := val.(map[string]interface{}); ok { loaded, _ := LoadModel(m, ctx) result.Model = loaded + } else { + loaded, _ := LoadModel(val, ctx) + result.Model = loaded } } if val, ok := m["tools"]; ok && val != nil { @@ -116,7 +119,7 @@ func LoadPrompty(data interface{}, ctx *LoadContext) (Prompty, error) { } // Save serializes Prompty to map[string]interface{} -func (obj *Prompty) Save(ctx *SaveContext) map[string]interface{} { +func (obj Prompty) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["name"] = obj.Name if obj.DisplayName != nil { @@ -200,11 +203,7 @@ func (obj *Prompty) ToJSON() (string, error) { func (obj *Prompty) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates Prompty from JSON string diff --git a/runtime/go/prompty/model/prompty_test.go b/runtime/go/prompty/model/prompty_test.go index 6378da70..9feddcbe 100644 --- a/runtime/go/prompty/model/prompty_test.go +++ b/runtime/go/prompty/model/prompty_test.go @@ -5,6 +5,7 @@ package prompty_test import ( "encoding/json" + "reflect" "testing" "gopkg.in/yaml.v3" @@ -103,6 +104,28 @@ func TestPromptyLoadJSON(t *testing.T) { if instance.Instructions == nil || *instance.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, instance.Instructions) } + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if instance.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, instance.Model.Id) + } + if len(instance.Tools) != 1 { + t.Fatalf("Expected Tools length to be 1, got %d", len(instance.Tools)) + } + tools0Value, ok := instance.Tools[0].(prompty.FunctionTool) + if !ok { + t.Fatalf("Expected Tools[0] to be prompty.FunctionTool, got %T", instance.Tools[0]) + } + if tools0Value.Kind != "function" { + t.Errorf(`Expected Kind to be "function", got %v`, tools0Value.Kind) + } + if instance.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, instance.Template.Format.Kind) + } + if instance.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, instance.Template.Parser.Kind) + } } // TestPromptyLoadYAML tests loading Prompty from YAML @@ -196,6 +219,248 @@ instructions: "system: if instance.Instructions == nil || *instance.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, instance.Instructions) } + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if instance.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, instance.Model.Id) + } + if len(instance.Tools) != 1 { + t.Fatalf("Expected Tools length to be 1, got %d", len(instance.Tools)) + } + tools0Value, ok := instance.Tools[0].(prompty.FunctionTool) + if !ok { + t.Fatalf("Expected Tools[0] to be prompty.FunctionTool, got %T", instance.Tools[0]) + } + if tools0Value.Kind != "function" { + t.Errorf(`Expected Kind to be "function", got %v`, tools0Value.Kind) + } + if instance.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, instance.Template.Format.Kind) + } + if instance.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, instance.Template.Parser.Kind) + } +} + +// TestPromptyFromJSON tests loading Prompty through the generated JSON helper +func TestPromptyFromJSON(t *testing.T) { + jsonData := ` +{ + "name": "basic-prompt", + "displayName": "Basic Prompt", + "description": "A basic prompt that uses the GPT-3 chat API to answer questions", + "metadata": { + "authors": [ + "sethjuarez", + "jietong" + ], + "tags": [ + "example", + "prompt" + ] + }, + "inputs": { + "firstName": { + "kind": "string", + "default": "Jane" + }, + "lastName": { + "kind": "string", + "default": "Doe" + }, + "question": { + "kind": "string", + "default": "What is the meaning of life?" + } + }, + "outputs": { + "answer": { + "kind": "string", + "description": "The answer to the user's question." + } + }, + "model": { + "id": "gpt-35-turbo", + "connection": { + "kind": "key", + "endpoint": "https://{your-custom-endpoint}.openai.azure.com/", + "apiKey": "{your-api-key}" + } + }, + "tools": [ + { + "name": "getCurrentWeather", + "kind": "function", + "description": "Get the current weather in a given location", + "parameters": { + "location": { + "kind": "string", + "description": "The city and state, e.g. San Francisco, CA" + }, + "unit": { + "kind": "string", + "description": "The unit of temperature, e.g. Celsius or Fahrenheit" + } + } + } + ], + "template": { + "format": "mustache", + "parser": "prompty" + }, + "instructions": "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" +} +` + + instance, err := prompty.PromptyFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load Prompty from JSON helper: %v", err) + } + if instance.Name != "basic-prompt" { + t.Errorf(`Expected Name to be "basic-prompt", got %v`, instance.Name) + } + if instance.DisplayName == nil || *instance.DisplayName != "Basic Prompt" { + t.Errorf(`Expected DisplayName to be "Basic Prompt", got %v`, instance.DisplayName) + } + if instance.Description == nil || *instance.Description != "A basic prompt that uses the GPT-3 chat API to answer questions" { + t.Errorf(`Expected Description to be "A basic prompt that uses the GPT-3 chat API to answer questions", got %v`, instance.Description) + } + if instance.Instructions == nil || *instance.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { + t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, instance.Instructions) + } + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if instance.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, instance.Model.Id) + } + if len(instance.Tools) != 1 { + t.Fatalf("Expected Tools length to be 1, got %d", len(instance.Tools)) + } + tools0Value, ok := instance.Tools[0].(prompty.FunctionTool) + if !ok { + t.Fatalf("Expected Tools[0] to be prompty.FunctionTool, got %T", instance.Tools[0]) + } + if tools0Value.Kind != "function" { + t.Errorf(`Expected Kind to be "function", got %v`, tools0Value.Kind) + } + if instance.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, instance.Template.Format.Kind) + } + if instance.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, instance.Template.Parser.Kind) + } +} + +// TestPromptyFromYAML tests loading Prompty through the generated YAML helper +func TestPromptyFromYAML(t *testing.T) { + yamlData := ` +name: basic-prompt +displayName: Basic Prompt +description: A basic prompt that uses the GPT-3 chat API to answer questions +metadata: + authors: + - sethjuarez + - jietong + tags: + - example + - prompt +inputs: + firstName: + kind: string + default: Jane + lastName: + kind: string + default: Doe + question: + kind: string + default: What is the meaning of life? +outputs: + answer: + kind: string + description: The answer to the user's question. +model: + id: gpt-35-turbo + connection: + kind: key + endpoint: "https://{your-custom-endpoint}.openai.azure.com/" + apiKey: "{your-api-key}" +tools: + - name: getCurrentWeather + kind: function + description: Get the current weather in a given location + parameters: + location: + kind: string + description: The city and state, e.g. San Francisco, CA + unit: + kind: string + description: The unit of temperature, e.g. Celsius or Fahrenheit +template: + format: mustache + parser: prompty +instructions: "system: + + You are an AI assistant who helps people find information. + + As the assistant, you answer questions briefly, succinctly, + + and in a personable manner using markdown and even add some\ + + personal flair with appropriate emojis. + + + # Customer + + You are helping {{firstName}} {{lastName}} to find answers to\ + + their questions. Use their name to address them in your responses. + + user: + + {{question}}" + +` + + instance, err := prompty.PromptyFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load Prompty from YAML helper: %v", err) + } + if instance.Name != "basic-prompt" { + t.Errorf(`Expected Name to be "basic-prompt", got %v`, instance.Name) + } + if instance.DisplayName == nil || *instance.DisplayName != "Basic Prompt" { + t.Errorf(`Expected DisplayName to be "Basic Prompt", got %v`, instance.DisplayName) + } + if instance.Description == nil || *instance.Description != "A basic prompt that uses the GPT-3 chat API to answer questions" { + t.Errorf(`Expected Description to be "A basic prompt that uses the GPT-3 chat API to answer questions", got %v`, instance.Description) + } + if instance.Instructions == nil || *instance.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { + t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, instance.Instructions) + } + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if instance.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, instance.Model.Id) + } + if len(instance.Tools) != 1 { + t.Fatalf("Expected Tools length to be 1, got %d", len(instance.Tools)) + } + tools0Value, ok := instance.Tools[0].(prompty.FunctionTool) + if !ok { + t.Fatalf("Expected Tools[0] to be prompty.FunctionTool, got %T", instance.Tools[0]) + } + if tools0Value.Kind != "function" { + t.Errorf(`Expected Kind to be "function", got %v`, tools0Value.Kind) + } + if instance.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, instance.Template.Format.Kind) + } + if instance.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, instance.Template.Parser.Kind) + } } // TestPromptyRoundtrip tests load -> save -> load produces equivalent data @@ -296,6 +561,28 @@ func TestPromptyRoundtrip(t *testing.T) { if reloaded.Instructions == nil || *reloaded.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, reloaded.Instructions) } + if reloaded.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if reloaded.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, reloaded.Model.Id) + } + if len(reloaded.Tools) != 1 { + t.Fatalf("Expected Tools length to be 1, got %d", len(reloaded.Tools)) + } + tools0Value, ok := reloaded.Tools[0].(prompty.FunctionTool) + if !ok { + t.Fatalf("Expected Tools[0] to be prompty.FunctionTool, got %T", reloaded.Tools[0]) + } + if tools0Value.Kind != "function" { + t.Errorf(`Expected Kind to be "function", got %v`, tools0Value.Kind) + } + if reloaded.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, reloaded.Template.Format.Kind) + } + if reloaded.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, reloaded.Template.Parser.Kind) + } } // TestPromptyToJSON tests that ToJSON produces valid JSON @@ -386,6 +673,45 @@ func TestPromptyToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadPrompty(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Name != "basic-prompt" { + t.Errorf(`Expected Name to be "basic-prompt", got %v`, reloaded.Name) + } + if reloaded.DisplayName == nil || *reloaded.DisplayName != "Basic Prompt" { + t.Errorf(`Expected DisplayName to be "Basic Prompt", got %v`, reloaded.DisplayName) + } + if reloaded.Description == nil || *reloaded.Description != "A basic prompt that uses the GPT-3 chat API to answer questions" { + t.Errorf(`Expected Description to be "A basic prompt that uses the GPT-3 chat API to answer questions", got %v`, reloaded.Description) + } + if reloaded.Instructions == nil || *reloaded.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { + t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, reloaded.Instructions) + } + if reloaded.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if reloaded.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, reloaded.Model.Id) + } + if len(reloaded.Tools) != 1 { + t.Fatalf("Expected Tools length to be 1, got %d", len(reloaded.Tools)) + } + tools0Value, ok := reloaded.Tools[0].(prompty.FunctionTool) + if !ok { + t.Fatalf("Expected Tools[0] to be prompty.FunctionTool, got %T", reloaded.Tools[0]) + } + if tools0Value.Kind != "function" { + t.Errorf(`Expected Kind to be "function", got %v`, tools0Value.Kind) + } + if reloaded.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, reloaded.Template.Format.Kind) + } + if reloaded.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, reloaded.Template.Parser.Kind) + } } // TestPromptyToYAML tests that ToYAML produces valid YAML @@ -476,6 +802,45 @@ func TestPromptyToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadPrompty(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Name != "basic-prompt" { + t.Errorf(`Expected Name to be "basic-prompt", got %v`, reloaded.Name) + } + if reloaded.DisplayName == nil || *reloaded.DisplayName != "Basic Prompt" { + t.Errorf(`Expected DisplayName to be "Basic Prompt", got %v`, reloaded.DisplayName) + } + if reloaded.Description == nil || *reloaded.Description != "A basic prompt that uses the GPT-3 chat API to answer questions" { + t.Errorf(`Expected Description to be "A basic prompt that uses the GPT-3 chat API to answer questions", got %v`, reloaded.Description) + } + if reloaded.Instructions == nil || *reloaded.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { + t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, reloaded.Instructions) + } + if reloaded.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if reloaded.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, reloaded.Model.Id) + } + if len(reloaded.Tools) != 1 { + t.Fatalf("Expected Tools length to be 1, got %d", len(reloaded.Tools)) + } + tools0Value, ok := reloaded.Tools[0].(prompty.FunctionTool) + if !ok { + t.Fatalf("Expected Tools[0] to be prompty.FunctionTool, got %T", reloaded.Tools[0]) + } + if tools0Value.Kind != "function" { + t.Errorf(`Expected Kind to be "function", got %v`, tools0Value.Kind) + } + if reloaded.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, reloaded.Template.Format.Kind) + } + if reloaded.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, reloaded.Template.Parser.Kind) + } } // TestPromptyLoadJSON1 tests loading Prompty from JSON @@ -568,6 +933,18 @@ func TestPromptyLoadJSON1(t *testing.T) { if instance.Instructions == nil || *instance.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, instance.Instructions) } + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if instance.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, instance.Model.Id) + } + if instance.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, instance.Template.Format.Kind) + } + if instance.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, instance.Template.Parser.Kind) + } } // TestPromptyLoadYAML1 tests loading Prompty from YAML @@ -661,9 +1038,220 @@ instructions: "system: if instance.Instructions == nil || *instance.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, instance.Instructions) } + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if instance.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, instance.Model.Id) + } + if instance.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, instance.Template.Format.Kind) + } + if instance.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, instance.Template.Parser.Kind) + } } -// TestPromptyRoundtrip1 tests load -> save -> load produces equivalent data +// TestPromptyFromJSON1 tests loading Prompty through the generated JSON helper +func TestPromptyFromJSON1(t *testing.T) { + jsonData := ` +{ + "name": "basic-prompt", + "displayName": "Basic Prompt", + "description": "A basic prompt that uses the GPT-3 chat API to answer questions", + "metadata": { + "authors": [ + "sethjuarez", + "jietong" + ], + "tags": [ + "example", + "prompt" + ] + }, + "inputs": { + "firstName": { + "kind": "string", + "default": "Jane" + }, + "lastName": { + "kind": "string", + "default": "Doe" + }, + "question": { + "kind": "string", + "default": "What is the meaning of life?" + } + }, + "outputs": { + "answer": { + "kind": "string", + "description": "The answer to the user's question." + } + }, + "model": { + "id": "gpt-35-turbo", + "connection": { + "kind": "key", + "endpoint": "https://{your-custom-endpoint}.openai.azure.com/", + "apiKey": "{your-api-key}" + } + }, + "tools": { + "getCurrentWeather": { + "kind": "function", + "description": "Get the current weather in a given location", + "parameters": { + "location": { + "kind": "string", + "description": "The city and state, e.g. San Francisco, CA" + }, + "unit": { + "kind": "string", + "description": "The unit of temperature, e.g. Celsius or Fahrenheit" + } + } + } + }, + "template": { + "format": "mustache", + "parser": "prompty" + }, + "instructions": "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" +} +` + + instance, err := prompty.PromptyFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load Prompty from JSON helper: %v", err) + } + if instance.Name != "basic-prompt" { + t.Errorf(`Expected Name to be "basic-prompt", got %v`, instance.Name) + } + if instance.DisplayName == nil || *instance.DisplayName != "Basic Prompt" { + t.Errorf(`Expected DisplayName to be "Basic Prompt", got %v`, instance.DisplayName) + } + if instance.Description == nil || *instance.Description != "A basic prompt that uses the GPT-3 chat API to answer questions" { + t.Errorf(`Expected Description to be "A basic prompt that uses the GPT-3 chat API to answer questions", got %v`, instance.Description) + } + if instance.Instructions == nil || *instance.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { + t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, instance.Instructions) + } + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if instance.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, instance.Model.Id) + } + if instance.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, instance.Template.Format.Kind) + } + if instance.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, instance.Template.Parser.Kind) + } +} + +// TestPromptyFromYAML1 tests loading Prompty through the generated YAML helper +func TestPromptyFromYAML1(t *testing.T) { + yamlData := ` +name: basic-prompt +displayName: Basic Prompt +description: A basic prompt that uses the GPT-3 chat API to answer questions +metadata: + authors: + - sethjuarez + - jietong + tags: + - example + - prompt +inputs: + firstName: + kind: string + default: Jane + lastName: + kind: string + default: Doe + question: + kind: string + default: What is the meaning of life? +outputs: + answer: + kind: string + description: The answer to the user's question. +model: + id: gpt-35-turbo + connection: + kind: key + endpoint: "https://{your-custom-endpoint}.openai.azure.com/" + apiKey: "{your-api-key}" +tools: + getCurrentWeather: + kind: function + description: Get the current weather in a given location + parameters: + location: + kind: string + description: The city and state, e.g. San Francisco, CA + unit: + kind: string + description: The unit of temperature, e.g. Celsius or Fahrenheit +template: + format: mustache + parser: prompty +instructions: "system: + + You are an AI assistant who helps people find information. + + As the assistant, you answer questions briefly, succinctly, + + and in a personable manner using markdown and even add some\ + + personal flair with appropriate emojis. + + + # Customer + + You are helping {{firstName}} {{lastName}} to find answers to\ + + their questions. Use their name to address them in your responses. + + user: + + {{question}}" + +` + + instance, err := prompty.PromptyFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load Prompty from YAML helper: %v", err) + } + if instance.Name != "basic-prompt" { + t.Errorf(`Expected Name to be "basic-prompt", got %v`, instance.Name) + } + if instance.DisplayName == nil || *instance.DisplayName != "Basic Prompt" { + t.Errorf(`Expected DisplayName to be "Basic Prompt", got %v`, instance.DisplayName) + } + if instance.Description == nil || *instance.Description != "A basic prompt that uses the GPT-3 chat API to answer questions" { + t.Errorf(`Expected Description to be "A basic prompt that uses the GPT-3 chat API to answer questions", got %v`, instance.Description) + } + if instance.Instructions == nil || *instance.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { + t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, instance.Instructions) + } + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if instance.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, instance.Model.Id) + } + if instance.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, instance.Template.Format.Kind) + } + if instance.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, instance.Template.Parser.Kind) + } +} + +// TestPromptyRoundtrip1 tests load -> save -> load produces equivalent data func TestPromptyRoundtrip1(t *testing.T) { jsonData := ` { @@ -760,6 +1348,18 @@ func TestPromptyRoundtrip1(t *testing.T) { if reloaded.Instructions == nil || *reloaded.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, reloaded.Instructions) } + if reloaded.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if reloaded.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, reloaded.Model.Id) + } + if reloaded.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, reloaded.Template.Format.Kind) + } + if reloaded.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, reloaded.Template.Parser.Kind) + } } // TestPromptyToJSON1 tests that ToJSON produces valid JSON @@ -849,6 +1449,35 @@ func TestPromptyToJSON1(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadPrompty(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Name != "basic-prompt" { + t.Errorf(`Expected Name to be "basic-prompt", got %v`, reloaded.Name) + } + if reloaded.DisplayName == nil || *reloaded.DisplayName != "Basic Prompt" { + t.Errorf(`Expected DisplayName to be "Basic Prompt", got %v`, reloaded.DisplayName) + } + if reloaded.Description == nil || *reloaded.Description != "A basic prompt that uses the GPT-3 chat API to answer questions" { + t.Errorf(`Expected Description to be "A basic prompt that uses the GPT-3 chat API to answer questions", got %v`, reloaded.Description) + } + if reloaded.Instructions == nil || *reloaded.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { + t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, reloaded.Instructions) + } + if reloaded.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if reloaded.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, reloaded.Model.Id) + } + if reloaded.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, reloaded.Template.Format.Kind) + } + if reloaded.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, reloaded.Template.Parser.Kind) + } } // TestPromptyToYAML1 tests that ToYAML produces valid YAML @@ -938,6 +1567,35 @@ func TestPromptyToYAML1(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadPrompty(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Name != "basic-prompt" { + t.Errorf(`Expected Name to be "basic-prompt", got %v`, reloaded.Name) + } + if reloaded.DisplayName == nil || *reloaded.DisplayName != "Basic Prompt" { + t.Errorf(`Expected DisplayName to be "Basic Prompt", got %v`, reloaded.DisplayName) + } + if reloaded.Description == nil || *reloaded.Description != "A basic prompt that uses the GPT-3 chat API to answer questions" { + t.Errorf(`Expected Description to be "A basic prompt that uses the GPT-3 chat API to answer questions", got %v`, reloaded.Description) + } + if reloaded.Instructions == nil || *reloaded.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { + t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, reloaded.Instructions) + } + if reloaded.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if reloaded.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, reloaded.Model.Id) + } + if reloaded.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, reloaded.Template.Format.Kind) + } + if reloaded.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, reloaded.Template.Parser.Kind) + } } // TestPromptyLoadJSON2 tests loading Prompty from JSON @@ -1032,6 +1690,31 @@ func TestPromptyLoadJSON2(t *testing.T) { if instance.Instructions == nil || *instance.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, instance.Instructions) } + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(instance.Outputs) != 1 { + t.Fatalf("Expected Outputs length to be 1, got %d", len(instance.Outputs)) + } + if instance.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, instance.Model.Id) + } + if len(instance.Tools) != 1 { + t.Fatalf("Expected Tools length to be 1, got %d", len(instance.Tools)) + } + tools0Value, ok := instance.Tools[0].(prompty.FunctionTool) + if !ok { + t.Fatalf("Expected Tools[0] to be prompty.FunctionTool, got %T", instance.Tools[0]) + } + if tools0Value.Kind != "function" { + t.Errorf(`Expected Kind to be "function", got %v`, tools0Value.Kind) + } + if instance.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, instance.Template.Format.Kind) + } + if instance.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, instance.Template.Parser.Kind) + } } // TestPromptyLoadYAML2 tests loading Prompty from YAML @@ -1125,10 +1808,35 @@ instructions: "system: if instance.Instructions == nil || *instance.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, instance.Instructions) } + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(instance.Outputs) != 1 { + t.Fatalf("Expected Outputs length to be 1, got %d", len(instance.Outputs)) + } + if instance.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, instance.Model.Id) + } + if len(instance.Tools) != 1 { + t.Fatalf("Expected Tools length to be 1, got %d", len(instance.Tools)) + } + tools0Value, ok := instance.Tools[0].(prompty.FunctionTool) + if !ok { + t.Fatalf("Expected Tools[0] to be prompty.FunctionTool, got %T", instance.Tools[0]) + } + if tools0Value.Kind != "function" { + t.Errorf(`Expected Kind to be "function", got %v`, tools0Value.Kind) + } + if instance.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, instance.Template.Format.Kind) + } + if instance.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, instance.Template.Parser.Kind) + } } -// TestPromptyRoundtrip2 tests load -> save -> load produces equivalent data -func TestPromptyRoundtrip2(t *testing.T) { +// TestPromptyFromJSON2 tests loading Prompty through the generated JSON helper +func TestPromptyFromJSON2(t *testing.T) { jsonData := ` { "name": "basic-prompt", @@ -1197,27 +1905,254 @@ func TestPromptyRoundtrip2(t *testing.T) { "instructions": "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" } ` - var data map[string]interface{} - if err := json.Unmarshal([]byte(jsonData), &data); err != nil { - t.Fatalf("Failed to parse JSON: %v", err) - } - loadCtx := prompty.NewLoadContext() - instance, err := prompty.LoadPrompty(data, loadCtx) + instance, err := prompty.PromptyFromJSON(jsonData) if err != nil { - t.Fatalf("Failed to load Prompty: %v", err) + t.Fatalf("Failed to load Prompty from JSON helper: %v", err) } - saveCtx := prompty.NewSaveContext() - savedData := instance.Save(saveCtx) - - reloaded, err := prompty.LoadPrompty(savedData, loadCtx) - if err != nil { - t.Fatalf("Failed to reload Prompty: %v", err) + if instance.Name != "basic-prompt" { + t.Errorf(`Expected Name to be "basic-prompt", got %v`, instance.Name) } - if reloaded.Name != "basic-prompt" { - t.Errorf(`Expected Name to be "basic-prompt", got %v`, reloaded.Name) + if instance.DisplayName == nil || *instance.DisplayName != "Basic Prompt" { + t.Errorf(`Expected DisplayName to be "Basic Prompt", got %v`, instance.DisplayName) } - if reloaded.DisplayName == nil || *reloaded.DisplayName != "Basic Prompt" { + if instance.Description == nil || *instance.Description != "A basic prompt that uses the GPT-3 chat API to answer questions" { + t.Errorf(`Expected Description to be "A basic prompt that uses the GPT-3 chat API to answer questions", got %v`, instance.Description) + } + if instance.Instructions == nil || *instance.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { + t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, instance.Instructions) + } + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(instance.Outputs) != 1 { + t.Fatalf("Expected Outputs length to be 1, got %d", len(instance.Outputs)) + } + if instance.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, instance.Model.Id) + } + if len(instance.Tools) != 1 { + t.Fatalf("Expected Tools length to be 1, got %d", len(instance.Tools)) + } + tools0Value, ok := instance.Tools[0].(prompty.FunctionTool) + if !ok { + t.Fatalf("Expected Tools[0] to be prompty.FunctionTool, got %T", instance.Tools[0]) + } + if tools0Value.Kind != "function" { + t.Errorf(`Expected Kind to be "function", got %v`, tools0Value.Kind) + } + if instance.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, instance.Template.Format.Kind) + } + if instance.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, instance.Template.Parser.Kind) + } +} + +// TestPromptyFromYAML2 tests loading Prompty through the generated YAML helper +func TestPromptyFromYAML2(t *testing.T) { + yamlData := ` +name: basic-prompt +displayName: Basic Prompt +description: A basic prompt that uses the GPT-3 chat API to answer questions +metadata: + authors: + - sethjuarez + - jietong + tags: + - example + - prompt +inputs: + firstName: + kind: string + default: Jane + lastName: + kind: string + default: Doe + question: + kind: string + default: What is the meaning of life? +outputs: + - name: answer + kind: string + description: The answer to the user's question. +model: + id: gpt-35-turbo + connection: + kind: key + endpoint: "https://{your-custom-endpoint}.openai.azure.com/" + apiKey: "{your-api-key}" +tools: + - name: getCurrentWeather + kind: function + description: Get the current weather in a given location + parameters: + location: + kind: string + description: The city and state, e.g. San Francisco, CA + unit: + kind: string + description: The unit of temperature, e.g. Celsius or Fahrenheit +template: + format: mustache + parser: prompty +instructions: "system: + + You are an AI assistant who helps people find information. + + As the assistant, you answer questions briefly, succinctly, + + and in a personable manner using markdown and even add some\ + + personal flair with appropriate emojis. + + + # Customer + + You are helping {{firstName}} {{lastName}} to find answers to\ + + their questions. Use their name to address them in your responses. + + user: + + {{question}}" + +` + + instance, err := prompty.PromptyFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load Prompty from YAML helper: %v", err) + } + if instance.Name != "basic-prompt" { + t.Errorf(`Expected Name to be "basic-prompt", got %v`, instance.Name) + } + if instance.DisplayName == nil || *instance.DisplayName != "Basic Prompt" { + t.Errorf(`Expected DisplayName to be "Basic Prompt", got %v`, instance.DisplayName) + } + if instance.Description == nil || *instance.Description != "A basic prompt that uses the GPT-3 chat API to answer questions" { + t.Errorf(`Expected Description to be "A basic prompt that uses the GPT-3 chat API to answer questions", got %v`, instance.Description) + } + if instance.Instructions == nil || *instance.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { + t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, instance.Instructions) + } + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(instance.Outputs) != 1 { + t.Fatalf("Expected Outputs length to be 1, got %d", len(instance.Outputs)) + } + if instance.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, instance.Model.Id) + } + if len(instance.Tools) != 1 { + t.Fatalf("Expected Tools length to be 1, got %d", len(instance.Tools)) + } + tools0Value, ok := instance.Tools[0].(prompty.FunctionTool) + if !ok { + t.Fatalf("Expected Tools[0] to be prompty.FunctionTool, got %T", instance.Tools[0]) + } + if tools0Value.Kind != "function" { + t.Errorf(`Expected Kind to be "function", got %v`, tools0Value.Kind) + } + if instance.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, instance.Template.Format.Kind) + } + if instance.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, instance.Template.Parser.Kind) + } +} + +// TestPromptyRoundtrip2 tests load -> save -> load produces equivalent data +func TestPromptyRoundtrip2(t *testing.T) { + jsonData := ` +{ + "name": "basic-prompt", + "displayName": "Basic Prompt", + "description": "A basic prompt that uses the GPT-3 chat API to answer questions", + "metadata": { + "authors": [ + "sethjuarez", + "jietong" + ], + "tags": [ + "example", + "prompt" + ] + }, + "inputs": { + "firstName": { + "kind": "string", + "default": "Jane" + }, + "lastName": { + "kind": "string", + "default": "Doe" + }, + "question": { + "kind": "string", + "default": "What is the meaning of life?" + } + }, + "outputs": [ + { + "name": "answer", + "kind": "string", + "description": "The answer to the user's question." + } + ], + "model": { + "id": "gpt-35-turbo", + "connection": { + "kind": "key", + "endpoint": "https://{your-custom-endpoint}.openai.azure.com/", + "apiKey": "{your-api-key}" + } + }, + "tools": [ + { + "name": "getCurrentWeather", + "kind": "function", + "description": "Get the current weather in a given location", + "parameters": { + "location": { + "kind": "string", + "description": "The city and state, e.g. San Francisco, CA" + }, + "unit": { + "kind": "string", + "description": "The unit of temperature, e.g. Celsius or Fahrenheit" + } + } + } + ], + "template": { + "format": "mustache", + "parser": "prompty" + }, + "instructions": "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + loadCtx := prompty.NewLoadContext() + instance, err := prompty.LoadPrompty(data, loadCtx) + if err != nil { + t.Fatalf("Failed to load Prompty: %v", err) + } + saveCtx := prompty.NewSaveContext() + savedData := instance.Save(saveCtx) + + reloaded, err := prompty.LoadPrompty(savedData, loadCtx) + if err != nil { + t.Fatalf("Failed to reload Prompty: %v", err) + } + if reloaded.Name != "basic-prompt" { + t.Errorf(`Expected Name to be "basic-prompt", got %v`, reloaded.Name) + } + if reloaded.DisplayName == nil || *reloaded.DisplayName != "Basic Prompt" { t.Errorf(`Expected DisplayName to be "Basic Prompt", got %v`, reloaded.DisplayName) } if reloaded.Description == nil || *reloaded.Description != "A basic prompt that uses the GPT-3 chat API to answer questions" { @@ -1226,6 +2161,31 @@ func TestPromptyRoundtrip2(t *testing.T) { if reloaded.Instructions == nil || *reloaded.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, reloaded.Instructions) } + if reloaded.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(reloaded.Outputs) != 1 { + t.Fatalf("Expected Outputs length to be 1, got %d", len(reloaded.Outputs)) + } + if reloaded.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, reloaded.Model.Id) + } + if len(reloaded.Tools) != 1 { + t.Fatalf("Expected Tools length to be 1, got %d", len(reloaded.Tools)) + } + tools0Value, ok := reloaded.Tools[0].(prompty.FunctionTool) + if !ok { + t.Fatalf("Expected Tools[0] to be prompty.FunctionTool, got %T", reloaded.Tools[0]) + } + if tools0Value.Kind != "function" { + t.Errorf(`Expected Kind to be "function", got %v`, tools0Value.Kind) + } + if reloaded.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, reloaded.Template.Format.Kind) + } + if reloaded.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, reloaded.Template.Parser.Kind) + } } // TestPromptyToJSON2 tests that ToJSON produces valid JSON @@ -1317,6 +2277,48 @@ func TestPromptyToJSON2(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadPrompty(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Name != "basic-prompt" { + t.Errorf(`Expected Name to be "basic-prompt", got %v`, reloaded.Name) + } + if reloaded.DisplayName == nil || *reloaded.DisplayName != "Basic Prompt" { + t.Errorf(`Expected DisplayName to be "Basic Prompt", got %v`, reloaded.DisplayName) + } + if reloaded.Description == nil || *reloaded.Description != "A basic prompt that uses the GPT-3 chat API to answer questions" { + t.Errorf(`Expected Description to be "A basic prompt that uses the GPT-3 chat API to answer questions", got %v`, reloaded.Description) + } + if reloaded.Instructions == nil || *reloaded.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { + t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, reloaded.Instructions) + } + if reloaded.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(reloaded.Outputs) != 1 { + t.Fatalf("Expected Outputs length to be 1, got %d", len(reloaded.Outputs)) + } + if reloaded.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, reloaded.Model.Id) + } + if len(reloaded.Tools) != 1 { + t.Fatalf("Expected Tools length to be 1, got %d", len(reloaded.Tools)) + } + tools0Value, ok := reloaded.Tools[0].(prompty.FunctionTool) + if !ok { + t.Fatalf("Expected Tools[0] to be prompty.FunctionTool, got %T", reloaded.Tools[0]) + } + if tools0Value.Kind != "function" { + t.Errorf(`Expected Kind to be "function", got %v`, tools0Value.Kind) + } + if reloaded.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, reloaded.Template.Format.Kind) + } + if reloaded.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, reloaded.Template.Parser.Kind) + } } // TestPromptyToYAML2 tests that ToYAML produces valid YAML @@ -1408,6 +2410,48 @@ func TestPromptyToYAML2(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadPrompty(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Name != "basic-prompt" { + t.Errorf(`Expected Name to be "basic-prompt", got %v`, reloaded.Name) + } + if reloaded.DisplayName == nil || *reloaded.DisplayName != "Basic Prompt" { + t.Errorf(`Expected DisplayName to be "Basic Prompt", got %v`, reloaded.DisplayName) + } + if reloaded.Description == nil || *reloaded.Description != "A basic prompt that uses the GPT-3 chat API to answer questions" { + t.Errorf(`Expected Description to be "A basic prompt that uses the GPT-3 chat API to answer questions", got %v`, reloaded.Description) + } + if reloaded.Instructions == nil || *reloaded.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { + t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, reloaded.Instructions) + } + if reloaded.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(reloaded.Outputs) != 1 { + t.Fatalf("Expected Outputs length to be 1, got %d", len(reloaded.Outputs)) + } + if reloaded.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, reloaded.Model.Id) + } + if len(reloaded.Tools) != 1 { + t.Fatalf("Expected Tools length to be 1, got %d", len(reloaded.Tools)) + } + tools0Value, ok := reloaded.Tools[0].(prompty.FunctionTool) + if !ok { + t.Fatalf("Expected Tools[0] to be prompty.FunctionTool, got %T", reloaded.Tools[0]) + } + if tools0Value.Kind != "function" { + t.Errorf(`Expected Kind to be "function", got %v`, tools0Value.Kind) + } + if reloaded.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, reloaded.Template.Format.Kind) + } + if reloaded.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, reloaded.Template.Parser.Kind) + } } // TestPromptyLoadJSON3 tests loading Prompty from JSON @@ -1501,9 +2545,24 @@ func TestPromptyLoadJSON3(t *testing.T) { if instance.Instructions == nil || *instance.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, instance.Instructions) } -} - -// TestPromptyLoadYAML3 tests loading Prompty from YAML + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(instance.Outputs) != 1 { + t.Fatalf("Expected Outputs length to be 1, got %d", len(instance.Outputs)) + } + if instance.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, instance.Model.Id) + } + if instance.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, instance.Template.Format.Kind) + } + if instance.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, instance.Template.Parser.Kind) + } +} + +// TestPromptyLoadYAML3 tests loading Prompty from YAML func TestPromptyLoadYAML3(t *testing.T) { yamlData := ` name: basic-prompt @@ -1594,6 +2653,227 @@ instructions: "system: if instance.Instructions == nil || *instance.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, instance.Instructions) } + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(instance.Outputs) != 1 { + t.Fatalf("Expected Outputs length to be 1, got %d", len(instance.Outputs)) + } + if instance.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, instance.Model.Id) + } + if instance.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, instance.Template.Format.Kind) + } + if instance.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, instance.Template.Parser.Kind) + } +} + +// TestPromptyFromJSON3 tests loading Prompty through the generated JSON helper +func TestPromptyFromJSON3(t *testing.T) { + jsonData := ` +{ + "name": "basic-prompt", + "displayName": "Basic Prompt", + "description": "A basic prompt that uses the GPT-3 chat API to answer questions", + "metadata": { + "authors": [ + "sethjuarez", + "jietong" + ], + "tags": [ + "example", + "prompt" + ] + }, + "inputs": { + "firstName": { + "kind": "string", + "default": "Jane" + }, + "lastName": { + "kind": "string", + "default": "Doe" + }, + "question": { + "kind": "string", + "default": "What is the meaning of life?" + } + }, + "outputs": [ + { + "name": "answer", + "kind": "string", + "description": "The answer to the user's question." + } + ], + "model": { + "id": "gpt-35-turbo", + "connection": { + "kind": "key", + "endpoint": "https://{your-custom-endpoint}.openai.azure.com/", + "apiKey": "{your-api-key}" + } + }, + "tools": { + "getCurrentWeather": { + "kind": "function", + "description": "Get the current weather in a given location", + "parameters": { + "location": { + "kind": "string", + "description": "The city and state, e.g. San Francisco, CA" + }, + "unit": { + "kind": "string", + "description": "The unit of temperature, e.g. Celsius or Fahrenheit" + } + } + } + }, + "template": { + "format": "mustache", + "parser": "prompty" + }, + "instructions": "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" +} +` + + instance, err := prompty.PromptyFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load Prompty from JSON helper: %v", err) + } + if instance.Name != "basic-prompt" { + t.Errorf(`Expected Name to be "basic-prompt", got %v`, instance.Name) + } + if instance.DisplayName == nil || *instance.DisplayName != "Basic Prompt" { + t.Errorf(`Expected DisplayName to be "Basic Prompt", got %v`, instance.DisplayName) + } + if instance.Description == nil || *instance.Description != "A basic prompt that uses the GPT-3 chat API to answer questions" { + t.Errorf(`Expected Description to be "A basic prompt that uses the GPT-3 chat API to answer questions", got %v`, instance.Description) + } + if instance.Instructions == nil || *instance.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { + t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, instance.Instructions) + } + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(instance.Outputs) != 1 { + t.Fatalf("Expected Outputs length to be 1, got %d", len(instance.Outputs)) + } + if instance.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, instance.Model.Id) + } + if instance.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, instance.Template.Format.Kind) + } + if instance.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, instance.Template.Parser.Kind) + } +} + +// TestPromptyFromYAML3 tests loading Prompty through the generated YAML helper +func TestPromptyFromYAML3(t *testing.T) { + yamlData := ` +name: basic-prompt +displayName: Basic Prompt +description: A basic prompt that uses the GPT-3 chat API to answer questions +metadata: + authors: + - sethjuarez + - jietong + tags: + - example + - prompt +inputs: + firstName: + kind: string + default: Jane + lastName: + kind: string + default: Doe + question: + kind: string + default: What is the meaning of life? +outputs: + - name: answer + kind: string + description: The answer to the user's question. +model: + id: gpt-35-turbo + connection: + kind: key + endpoint: "https://{your-custom-endpoint}.openai.azure.com/" + apiKey: "{your-api-key}" +tools: + getCurrentWeather: + kind: function + description: Get the current weather in a given location + parameters: + location: + kind: string + description: The city and state, e.g. San Francisco, CA + unit: + kind: string + description: The unit of temperature, e.g. Celsius or Fahrenheit +template: + format: mustache + parser: prompty +instructions: "system: + + You are an AI assistant who helps people find information. + + As the assistant, you answer questions briefly, succinctly, + + and in a personable manner using markdown and even add some\ + + personal flair with appropriate emojis. + + + # Customer + + You are helping {{firstName}} {{lastName}} to find answers to\ + + their questions. Use their name to address them in your responses. + + user: + + {{question}}" + +` + + instance, err := prompty.PromptyFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load Prompty from YAML helper: %v", err) + } + if instance.Name != "basic-prompt" { + t.Errorf(`Expected Name to be "basic-prompt", got %v`, instance.Name) + } + if instance.DisplayName == nil || *instance.DisplayName != "Basic Prompt" { + t.Errorf(`Expected DisplayName to be "Basic Prompt", got %v`, instance.DisplayName) + } + if instance.Description == nil || *instance.Description != "A basic prompt that uses the GPT-3 chat API to answer questions" { + t.Errorf(`Expected Description to be "A basic prompt that uses the GPT-3 chat API to answer questions", got %v`, instance.Description) + } + if instance.Instructions == nil || *instance.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { + t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, instance.Instructions) + } + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(instance.Outputs) != 1 { + t.Fatalf("Expected Outputs length to be 1, got %d", len(instance.Outputs)) + } + if instance.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, instance.Model.Id) + } + if instance.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, instance.Template.Format.Kind) + } + if instance.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, instance.Template.Parser.Kind) + } } // TestPromptyRoundtrip3 tests load -> save -> load produces equivalent data @@ -1694,6 +2974,21 @@ func TestPromptyRoundtrip3(t *testing.T) { if reloaded.Instructions == nil || *reloaded.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, reloaded.Instructions) } + if reloaded.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(reloaded.Outputs) != 1 { + t.Fatalf("Expected Outputs length to be 1, got %d", len(reloaded.Outputs)) + } + if reloaded.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, reloaded.Model.Id) + } + if reloaded.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, reloaded.Template.Format.Kind) + } + if reloaded.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, reloaded.Template.Parser.Kind) + } } // TestPromptyToJSON3 tests that ToJSON produces valid JSON @@ -1784,6 +3079,38 @@ func TestPromptyToJSON3(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadPrompty(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Name != "basic-prompt" { + t.Errorf(`Expected Name to be "basic-prompt", got %v`, reloaded.Name) + } + if reloaded.DisplayName == nil || *reloaded.DisplayName != "Basic Prompt" { + t.Errorf(`Expected DisplayName to be "Basic Prompt", got %v`, reloaded.DisplayName) + } + if reloaded.Description == nil || *reloaded.Description != "A basic prompt that uses the GPT-3 chat API to answer questions" { + t.Errorf(`Expected Description to be "A basic prompt that uses the GPT-3 chat API to answer questions", got %v`, reloaded.Description) + } + if reloaded.Instructions == nil || *reloaded.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { + t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, reloaded.Instructions) + } + if reloaded.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(reloaded.Outputs) != 1 { + t.Fatalf("Expected Outputs length to be 1, got %d", len(reloaded.Outputs)) + } + if reloaded.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, reloaded.Model.Id) + } + if reloaded.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, reloaded.Template.Format.Kind) + } + if reloaded.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, reloaded.Template.Parser.Kind) + } } // TestPromptyToYAML3 tests that ToYAML produces valid YAML @@ -1874,6 +3201,38 @@ func TestPromptyToYAML3(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadPrompty(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Name != "basic-prompt" { + t.Errorf(`Expected Name to be "basic-prompt", got %v`, reloaded.Name) + } + if reloaded.DisplayName == nil || *reloaded.DisplayName != "Basic Prompt" { + t.Errorf(`Expected DisplayName to be "Basic Prompt", got %v`, reloaded.DisplayName) + } + if reloaded.Description == nil || *reloaded.Description != "A basic prompt that uses the GPT-3 chat API to answer questions" { + t.Errorf(`Expected Description to be "A basic prompt that uses the GPT-3 chat API to answer questions", got %v`, reloaded.Description) + } + if reloaded.Instructions == nil || *reloaded.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { + t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, reloaded.Instructions) + } + if reloaded.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(reloaded.Outputs) != 1 { + t.Fatalf("Expected Outputs length to be 1, got %d", len(reloaded.Outputs)) + } + if reloaded.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, reloaded.Model.Id) + } + if reloaded.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, reloaded.Template.Format.Kind) + } + if reloaded.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, reloaded.Template.Parser.Kind) + } } // TestPromptyLoadJSON4 tests loading Prompty from JSON @@ -1970,6 +3329,40 @@ func TestPromptyLoadJSON4(t *testing.T) { if instance.Instructions == nil || *instance.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, instance.Instructions) } + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(instance.Inputs) != 3 { + t.Fatalf("Expected Inputs length to be 3, got %d", len(instance.Inputs)) + } + assertPromptyStringField(t, instance.Inputs[0], "Name", "firstName", "Inputs[0].Name") + assertPromptyStringField(t, instance.Inputs[0], "Kind", "string", "Inputs[0].Kind") + assertPromptyStringField(t, instance.Inputs[0], "Default", "Jane", "Inputs[0].Default") + assertPromptyStringField(t, instance.Inputs[1], "Name", "lastName", "Inputs[1].Name") + assertPromptyStringField(t, instance.Inputs[1], "Kind", "string", "Inputs[1].Kind") + assertPromptyStringField(t, instance.Inputs[1], "Default", "Doe", "Inputs[1].Default") + assertPromptyStringField(t, instance.Inputs[2], "Name", "question", "Inputs[2].Name") + assertPromptyStringField(t, instance.Inputs[2], "Kind", "string", "Inputs[2].Kind") + assertPromptyStringField(t, instance.Inputs[2], "Default", "What is the meaning of life?", "Inputs[2].Default") + if instance.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, instance.Model.Id) + } + if len(instance.Tools) != 1 { + t.Fatalf("Expected Tools length to be 1, got %d", len(instance.Tools)) + } + tools0Value, ok := instance.Tools[0].(prompty.FunctionTool) + if !ok { + t.Fatalf("Expected Tools[0] to be prompty.FunctionTool, got %T", instance.Tools[0]) + } + if tools0Value.Kind != "function" { + t.Errorf(`Expected Kind to be "function", got %v`, tools0Value.Kind) + } + if instance.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, instance.Template.Format.Kind) + } + if instance.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, instance.Template.Parser.Kind) + } } // TestPromptyLoadYAML4 tests loading Prompty from YAML @@ -2063,10 +3456,44 @@ instructions: "system: if instance.Instructions == nil || *instance.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, instance.Instructions) } + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(instance.Inputs) != 3 { + t.Fatalf("Expected Inputs length to be 3, got %d", len(instance.Inputs)) + } + assertPromptyStringField(t, instance.Inputs[0], "Name", "firstName", "Inputs[0].Name") + assertPromptyStringField(t, instance.Inputs[0], "Kind", "string", "Inputs[0].Kind") + assertPromptyStringField(t, instance.Inputs[0], "Default", "Jane", "Inputs[0].Default") + assertPromptyStringField(t, instance.Inputs[1], "Name", "lastName", "Inputs[1].Name") + assertPromptyStringField(t, instance.Inputs[1], "Kind", "string", "Inputs[1].Kind") + assertPromptyStringField(t, instance.Inputs[1], "Default", "Doe", "Inputs[1].Default") + assertPromptyStringField(t, instance.Inputs[2], "Name", "question", "Inputs[2].Name") + assertPromptyStringField(t, instance.Inputs[2], "Kind", "string", "Inputs[2].Kind") + assertPromptyStringField(t, instance.Inputs[2], "Default", "What is the meaning of life?", "Inputs[2].Default") + if instance.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, instance.Model.Id) + } + if len(instance.Tools) != 1 { + t.Fatalf("Expected Tools length to be 1, got %d", len(instance.Tools)) + } + tools0Value, ok := instance.Tools[0].(prompty.FunctionTool) + if !ok { + t.Fatalf("Expected Tools[0] to be prompty.FunctionTool, got %T", instance.Tools[0]) + } + if tools0Value.Kind != "function" { + t.Errorf(`Expected Kind to be "function", got %v`, tools0Value.Kind) + } + if instance.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, instance.Template.Format.Kind) + } + if instance.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, instance.Template.Parser.Kind) + } } -// TestPromptyRoundtrip4 tests load -> save -> load produces equivalent data -func TestPromptyRoundtrip4(t *testing.T) { +// TestPromptyFromJSON4 tests loading Prompty through the generated JSON helper +func TestPromptyFromJSON4(t *testing.T) { jsonData := ` { "name": "basic-prompt", @@ -2137,8 +3564,255 @@ func TestPromptyRoundtrip4(t *testing.T) { "instructions": "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" } ` - var data map[string]interface{} - if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + + instance, err := prompty.PromptyFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load Prompty from JSON helper: %v", err) + } + if instance.Name != "basic-prompt" { + t.Errorf(`Expected Name to be "basic-prompt", got %v`, instance.Name) + } + if instance.DisplayName == nil || *instance.DisplayName != "Basic Prompt" { + t.Errorf(`Expected DisplayName to be "Basic Prompt", got %v`, instance.DisplayName) + } + if instance.Description == nil || *instance.Description != "A basic prompt that uses the GPT-3 chat API to answer questions" { + t.Errorf(`Expected Description to be "A basic prompt that uses the GPT-3 chat API to answer questions", got %v`, instance.Description) + } + if instance.Instructions == nil || *instance.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { + t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, instance.Instructions) + } + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(instance.Inputs) != 3 { + t.Fatalf("Expected Inputs length to be 3, got %d", len(instance.Inputs)) + } + assertPromptyStringField(t, instance.Inputs[0], "Name", "firstName", "Inputs[0].Name") + assertPromptyStringField(t, instance.Inputs[0], "Kind", "string", "Inputs[0].Kind") + assertPromptyStringField(t, instance.Inputs[0], "Default", "Jane", "Inputs[0].Default") + assertPromptyStringField(t, instance.Inputs[1], "Name", "lastName", "Inputs[1].Name") + assertPromptyStringField(t, instance.Inputs[1], "Kind", "string", "Inputs[1].Kind") + assertPromptyStringField(t, instance.Inputs[1], "Default", "Doe", "Inputs[1].Default") + assertPromptyStringField(t, instance.Inputs[2], "Name", "question", "Inputs[2].Name") + assertPromptyStringField(t, instance.Inputs[2], "Kind", "string", "Inputs[2].Kind") + assertPromptyStringField(t, instance.Inputs[2], "Default", "What is the meaning of life?", "Inputs[2].Default") + if instance.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, instance.Model.Id) + } + if len(instance.Tools) != 1 { + t.Fatalf("Expected Tools length to be 1, got %d", len(instance.Tools)) + } + tools0Value, ok := instance.Tools[0].(prompty.FunctionTool) + if !ok { + t.Fatalf("Expected Tools[0] to be prompty.FunctionTool, got %T", instance.Tools[0]) + } + if tools0Value.Kind != "function" { + t.Errorf(`Expected Kind to be "function", got %v`, tools0Value.Kind) + } + if instance.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, instance.Template.Format.Kind) + } + if instance.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, instance.Template.Parser.Kind) + } +} + +// TestPromptyFromYAML4 tests loading Prompty through the generated YAML helper +func TestPromptyFromYAML4(t *testing.T) { + yamlData := ` +name: basic-prompt +displayName: Basic Prompt +description: A basic prompt that uses the GPT-3 chat API to answer questions +metadata: + authors: + - sethjuarez + - jietong + tags: + - example + - prompt +inputs: + - name: firstName + kind: string + default: Jane + - name: lastName + kind: string + default: Doe + - name: question + kind: string + default: What is the meaning of life? +outputs: + answer: + kind: string + description: The answer to the user's question. +model: + id: gpt-35-turbo + connection: + kind: key + endpoint: "https://{your-custom-endpoint}.openai.azure.com/" + apiKey: "{your-api-key}" +tools: + - name: getCurrentWeather + kind: function + description: Get the current weather in a given location + parameters: + location: + kind: string + description: The city and state, e.g. San Francisco, CA + unit: + kind: string + description: The unit of temperature, e.g. Celsius or Fahrenheit +template: + format: mustache + parser: prompty +instructions: "system: + + You are an AI assistant who helps people find information. + + As the assistant, you answer questions briefly, succinctly, + + and in a personable manner using markdown and even add some\ + + personal flair with appropriate emojis. + + + # Customer + + You are helping {{firstName}} {{lastName}} to find answers to\ + + their questions. Use their name to address them in your responses. + + user: + + {{question}}" + +` + + instance, err := prompty.PromptyFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load Prompty from YAML helper: %v", err) + } + if instance.Name != "basic-prompt" { + t.Errorf(`Expected Name to be "basic-prompt", got %v`, instance.Name) + } + if instance.DisplayName == nil || *instance.DisplayName != "Basic Prompt" { + t.Errorf(`Expected DisplayName to be "Basic Prompt", got %v`, instance.DisplayName) + } + if instance.Description == nil || *instance.Description != "A basic prompt that uses the GPT-3 chat API to answer questions" { + t.Errorf(`Expected Description to be "A basic prompt that uses the GPT-3 chat API to answer questions", got %v`, instance.Description) + } + if instance.Instructions == nil || *instance.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { + t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, instance.Instructions) + } + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(instance.Inputs) != 3 { + t.Fatalf("Expected Inputs length to be 3, got %d", len(instance.Inputs)) + } + assertPromptyStringField(t, instance.Inputs[0], "Name", "firstName", "Inputs[0].Name") + assertPromptyStringField(t, instance.Inputs[0], "Kind", "string", "Inputs[0].Kind") + assertPromptyStringField(t, instance.Inputs[0], "Default", "Jane", "Inputs[0].Default") + assertPromptyStringField(t, instance.Inputs[1], "Name", "lastName", "Inputs[1].Name") + assertPromptyStringField(t, instance.Inputs[1], "Kind", "string", "Inputs[1].Kind") + assertPromptyStringField(t, instance.Inputs[1], "Default", "Doe", "Inputs[1].Default") + assertPromptyStringField(t, instance.Inputs[2], "Name", "question", "Inputs[2].Name") + assertPromptyStringField(t, instance.Inputs[2], "Kind", "string", "Inputs[2].Kind") + assertPromptyStringField(t, instance.Inputs[2], "Default", "What is the meaning of life?", "Inputs[2].Default") + if instance.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, instance.Model.Id) + } + if len(instance.Tools) != 1 { + t.Fatalf("Expected Tools length to be 1, got %d", len(instance.Tools)) + } + tools0Value, ok := instance.Tools[0].(prompty.FunctionTool) + if !ok { + t.Fatalf("Expected Tools[0] to be prompty.FunctionTool, got %T", instance.Tools[0]) + } + if tools0Value.Kind != "function" { + t.Errorf(`Expected Kind to be "function", got %v`, tools0Value.Kind) + } + if instance.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, instance.Template.Format.Kind) + } + if instance.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, instance.Template.Parser.Kind) + } +} + +// TestPromptyRoundtrip4 tests load -> save -> load produces equivalent data +func TestPromptyRoundtrip4(t *testing.T) { + jsonData := ` +{ + "name": "basic-prompt", + "displayName": "Basic Prompt", + "description": "A basic prompt that uses the GPT-3 chat API to answer questions", + "metadata": { + "authors": [ + "sethjuarez", + "jietong" + ], + "tags": [ + "example", + "prompt" + ] + }, + "inputs": [ + { + "name": "firstName", + "kind": "string", + "default": "Jane" + }, + { + "name": "lastName", + "kind": "string", + "default": "Doe" + }, + { + "name": "question", + "kind": "string", + "default": "What is the meaning of life?" + } + ], + "outputs": { + "answer": { + "kind": "string", + "description": "The answer to the user's question." + } + }, + "model": { + "id": "gpt-35-turbo", + "connection": { + "kind": "key", + "endpoint": "https://{your-custom-endpoint}.openai.azure.com/", + "apiKey": "{your-api-key}" + } + }, + "tools": [ + { + "name": "getCurrentWeather", + "kind": "function", + "description": "Get the current weather in a given location", + "parameters": { + "location": { + "kind": "string", + "description": "The city and state, e.g. San Francisco, CA" + }, + "unit": { + "kind": "string", + "description": "The unit of temperature, e.g. Celsius or Fahrenheit" + } + } + } + ], + "template": { + "format": "mustache", + "parser": "prompty" + }, + "instructions": "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { t.Fatalf("Failed to parse JSON: %v", err) } @@ -2166,6 +3840,40 @@ func TestPromptyRoundtrip4(t *testing.T) { if reloaded.Instructions == nil || *reloaded.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, reloaded.Instructions) } + if reloaded.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(reloaded.Inputs) != 3 { + t.Fatalf("Expected Inputs length to be 3, got %d", len(reloaded.Inputs)) + } + assertPromptyStringField(t, reloaded.Inputs[0], "Name", "firstName", "Inputs[0].Name") + assertPromptyStringField(t, reloaded.Inputs[0], "Kind", "string", "Inputs[0].Kind") + assertPromptyStringField(t, reloaded.Inputs[0], "Default", "Jane", "Inputs[0].Default") + assertPromptyStringField(t, reloaded.Inputs[1], "Name", "lastName", "Inputs[1].Name") + assertPromptyStringField(t, reloaded.Inputs[1], "Kind", "string", "Inputs[1].Kind") + assertPromptyStringField(t, reloaded.Inputs[1], "Default", "Doe", "Inputs[1].Default") + assertPromptyStringField(t, reloaded.Inputs[2], "Name", "question", "Inputs[2].Name") + assertPromptyStringField(t, reloaded.Inputs[2], "Kind", "string", "Inputs[2].Kind") + assertPromptyStringField(t, reloaded.Inputs[2], "Default", "What is the meaning of life?", "Inputs[2].Default") + if reloaded.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, reloaded.Model.Id) + } + if len(reloaded.Tools) != 1 { + t.Fatalf("Expected Tools length to be 1, got %d", len(reloaded.Tools)) + } + tools0Value, ok := reloaded.Tools[0].(prompty.FunctionTool) + if !ok { + t.Fatalf("Expected Tools[0] to be prompty.FunctionTool, got %T", reloaded.Tools[0]) + } + if tools0Value.Kind != "function" { + t.Errorf(`Expected Kind to be "function", got %v`, tools0Value.Kind) + } + if reloaded.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, reloaded.Template.Format.Kind) + } + if reloaded.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, reloaded.Template.Parser.Kind) + } } // TestPromptyToJSON4 tests that ToJSON produces valid JSON @@ -2259,6 +3967,57 @@ func TestPromptyToJSON4(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadPrompty(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Name != "basic-prompt" { + t.Errorf(`Expected Name to be "basic-prompt", got %v`, reloaded.Name) + } + if reloaded.DisplayName == nil || *reloaded.DisplayName != "Basic Prompt" { + t.Errorf(`Expected DisplayName to be "Basic Prompt", got %v`, reloaded.DisplayName) + } + if reloaded.Description == nil || *reloaded.Description != "A basic prompt that uses the GPT-3 chat API to answer questions" { + t.Errorf(`Expected Description to be "A basic prompt that uses the GPT-3 chat API to answer questions", got %v`, reloaded.Description) + } + if reloaded.Instructions == nil || *reloaded.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { + t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, reloaded.Instructions) + } + if reloaded.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(reloaded.Inputs) != 3 { + t.Fatalf("Expected Inputs length to be 3, got %d", len(reloaded.Inputs)) + } + assertPromptyStringField(t, reloaded.Inputs[0], "Name", "firstName", "Inputs[0].Name") + assertPromptyStringField(t, reloaded.Inputs[0], "Kind", "string", "Inputs[0].Kind") + assertPromptyStringField(t, reloaded.Inputs[0], "Default", "Jane", "Inputs[0].Default") + assertPromptyStringField(t, reloaded.Inputs[1], "Name", "lastName", "Inputs[1].Name") + assertPromptyStringField(t, reloaded.Inputs[1], "Kind", "string", "Inputs[1].Kind") + assertPromptyStringField(t, reloaded.Inputs[1], "Default", "Doe", "Inputs[1].Default") + assertPromptyStringField(t, reloaded.Inputs[2], "Name", "question", "Inputs[2].Name") + assertPromptyStringField(t, reloaded.Inputs[2], "Kind", "string", "Inputs[2].Kind") + assertPromptyStringField(t, reloaded.Inputs[2], "Default", "What is the meaning of life?", "Inputs[2].Default") + if reloaded.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, reloaded.Model.Id) + } + if len(reloaded.Tools) != 1 { + t.Fatalf("Expected Tools length to be 1, got %d", len(reloaded.Tools)) + } + tools0Value, ok := reloaded.Tools[0].(prompty.FunctionTool) + if !ok { + t.Fatalf("Expected Tools[0] to be prompty.FunctionTool, got %T", reloaded.Tools[0]) + } + if tools0Value.Kind != "function" { + t.Errorf(`Expected Kind to be "function", got %v`, tools0Value.Kind) + } + if reloaded.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, reloaded.Template.Format.Kind) + } + if reloaded.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, reloaded.Template.Parser.Kind) + } } // TestPromptyToYAML4 tests that ToYAML produces valid YAML @@ -2352,6 +4111,57 @@ func TestPromptyToYAML4(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadPrompty(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Name != "basic-prompt" { + t.Errorf(`Expected Name to be "basic-prompt", got %v`, reloaded.Name) + } + if reloaded.DisplayName == nil || *reloaded.DisplayName != "Basic Prompt" { + t.Errorf(`Expected DisplayName to be "Basic Prompt", got %v`, reloaded.DisplayName) + } + if reloaded.Description == nil || *reloaded.Description != "A basic prompt that uses the GPT-3 chat API to answer questions" { + t.Errorf(`Expected Description to be "A basic prompt that uses the GPT-3 chat API to answer questions", got %v`, reloaded.Description) + } + if reloaded.Instructions == nil || *reloaded.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { + t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, reloaded.Instructions) + } + if reloaded.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(reloaded.Inputs) != 3 { + t.Fatalf("Expected Inputs length to be 3, got %d", len(reloaded.Inputs)) + } + assertPromptyStringField(t, reloaded.Inputs[0], "Name", "firstName", "Inputs[0].Name") + assertPromptyStringField(t, reloaded.Inputs[0], "Kind", "string", "Inputs[0].Kind") + assertPromptyStringField(t, reloaded.Inputs[0], "Default", "Jane", "Inputs[0].Default") + assertPromptyStringField(t, reloaded.Inputs[1], "Name", "lastName", "Inputs[1].Name") + assertPromptyStringField(t, reloaded.Inputs[1], "Kind", "string", "Inputs[1].Kind") + assertPromptyStringField(t, reloaded.Inputs[1], "Default", "Doe", "Inputs[1].Default") + assertPromptyStringField(t, reloaded.Inputs[2], "Name", "question", "Inputs[2].Name") + assertPromptyStringField(t, reloaded.Inputs[2], "Kind", "string", "Inputs[2].Kind") + assertPromptyStringField(t, reloaded.Inputs[2], "Default", "What is the meaning of life?", "Inputs[2].Default") + if reloaded.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, reloaded.Model.Id) + } + if len(reloaded.Tools) != 1 { + t.Fatalf("Expected Tools length to be 1, got %d", len(reloaded.Tools)) + } + tools0Value, ok := reloaded.Tools[0].(prompty.FunctionTool) + if !ok { + t.Fatalf("Expected Tools[0] to be prompty.FunctionTool, got %T", reloaded.Tools[0]) + } + if tools0Value.Kind != "function" { + t.Errorf(`Expected Kind to be "function", got %v`, tools0Value.Kind) + } + if reloaded.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, reloaded.Template.Format.Kind) + } + if reloaded.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, reloaded.Template.Parser.Kind) + } } // TestPromptyLoadJSON5 tests loading Prompty from JSON @@ -2447,6 +4257,30 @@ func TestPromptyLoadJSON5(t *testing.T) { if instance.Instructions == nil || *instance.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, instance.Instructions) } + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(instance.Inputs) != 3 { + t.Fatalf("Expected Inputs length to be 3, got %d", len(instance.Inputs)) + } + assertPromptyStringField(t, instance.Inputs[0], "Name", "firstName", "Inputs[0].Name") + assertPromptyStringField(t, instance.Inputs[0], "Kind", "string", "Inputs[0].Kind") + assertPromptyStringField(t, instance.Inputs[0], "Default", "Jane", "Inputs[0].Default") + assertPromptyStringField(t, instance.Inputs[1], "Name", "lastName", "Inputs[1].Name") + assertPromptyStringField(t, instance.Inputs[1], "Kind", "string", "Inputs[1].Kind") + assertPromptyStringField(t, instance.Inputs[1], "Default", "Doe", "Inputs[1].Default") + assertPromptyStringField(t, instance.Inputs[2], "Name", "question", "Inputs[2].Name") + assertPromptyStringField(t, instance.Inputs[2], "Kind", "string", "Inputs[2].Kind") + assertPromptyStringField(t, instance.Inputs[2], "Default", "What is the meaning of life?", "Inputs[2].Default") + if instance.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, instance.Model.Id) + } + if instance.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, instance.Template.Format.Kind) + } + if instance.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, instance.Template.Parser.Kind) + } } // TestPromptyLoadYAML5 tests loading Prompty from YAML @@ -2540,9 +4374,259 @@ instructions: "system: if instance.Instructions == nil || *instance.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, instance.Instructions) } + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(instance.Inputs) != 3 { + t.Fatalf("Expected Inputs length to be 3, got %d", len(instance.Inputs)) + } + assertPromptyStringField(t, instance.Inputs[0], "Name", "firstName", "Inputs[0].Name") + assertPromptyStringField(t, instance.Inputs[0], "Kind", "string", "Inputs[0].Kind") + assertPromptyStringField(t, instance.Inputs[0], "Default", "Jane", "Inputs[0].Default") + assertPromptyStringField(t, instance.Inputs[1], "Name", "lastName", "Inputs[1].Name") + assertPromptyStringField(t, instance.Inputs[1], "Kind", "string", "Inputs[1].Kind") + assertPromptyStringField(t, instance.Inputs[1], "Default", "Doe", "Inputs[1].Default") + assertPromptyStringField(t, instance.Inputs[2], "Name", "question", "Inputs[2].Name") + assertPromptyStringField(t, instance.Inputs[2], "Kind", "string", "Inputs[2].Kind") + assertPromptyStringField(t, instance.Inputs[2], "Default", "What is the meaning of life?", "Inputs[2].Default") + if instance.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, instance.Model.Id) + } + if instance.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, instance.Template.Format.Kind) + } + if instance.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, instance.Template.Parser.Kind) + } } -// TestPromptyRoundtrip5 tests load -> save -> load produces equivalent data +// TestPromptyFromJSON5 tests loading Prompty through the generated JSON helper +func TestPromptyFromJSON5(t *testing.T) { + jsonData := ` +{ + "name": "basic-prompt", + "displayName": "Basic Prompt", + "description": "A basic prompt that uses the GPT-3 chat API to answer questions", + "metadata": { + "authors": [ + "sethjuarez", + "jietong" + ], + "tags": [ + "example", + "prompt" + ] + }, + "inputs": [ + { + "name": "firstName", + "kind": "string", + "default": "Jane" + }, + { + "name": "lastName", + "kind": "string", + "default": "Doe" + }, + { + "name": "question", + "kind": "string", + "default": "What is the meaning of life?" + } + ], + "outputs": { + "answer": { + "kind": "string", + "description": "The answer to the user's question." + } + }, + "model": { + "id": "gpt-35-turbo", + "connection": { + "kind": "key", + "endpoint": "https://{your-custom-endpoint}.openai.azure.com/", + "apiKey": "{your-api-key}" + } + }, + "tools": { + "getCurrentWeather": { + "kind": "function", + "description": "Get the current weather in a given location", + "parameters": { + "location": { + "kind": "string", + "description": "The city and state, e.g. San Francisco, CA" + }, + "unit": { + "kind": "string", + "description": "The unit of temperature, e.g. Celsius or Fahrenheit" + } + } + } + }, + "template": { + "format": "mustache", + "parser": "prompty" + }, + "instructions": "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" +} +` + + instance, err := prompty.PromptyFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load Prompty from JSON helper: %v", err) + } + if instance.Name != "basic-prompt" { + t.Errorf(`Expected Name to be "basic-prompt", got %v`, instance.Name) + } + if instance.DisplayName == nil || *instance.DisplayName != "Basic Prompt" { + t.Errorf(`Expected DisplayName to be "Basic Prompt", got %v`, instance.DisplayName) + } + if instance.Description == nil || *instance.Description != "A basic prompt that uses the GPT-3 chat API to answer questions" { + t.Errorf(`Expected Description to be "A basic prompt that uses the GPT-3 chat API to answer questions", got %v`, instance.Description) + } + if instance.Instructions == nil || *instance.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { + t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, instance.Instructions) + } + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(instance.Inputs) != 3 { + t.Fatalf("Expected Inputs length to be 3, got %d", len(instance.Inputs)) + } + assertPromptyStringField(t, instance.Inputs[0], "Name", "firstName", "Inputs[0].Name") + assertPromptyStringField(t, instance.Inputs[0], "Kind", "string", "Inputs[0].Kind") + assertPromptyStringField(t, instance.Inputs[0], "Default", "Jane", "Inputs[0].Default") + assertPromptyStringField(t, instance.Inputs[1], "Name", "lastName", "Inputs[1].Name") + assertPromptyStringField(t, instance.Inputs[1], "Kind", "string", "Inputs[1].Kind") + assertPromptyStringField(t, instance.Inputs[1], "Default", "Doe", "Inputs[1].Default") + assertPromptyStringField(t, instance.Inputs[2], "Name", "question", "Inputs[2].Name") + assertPromptyStringField(t, instance.Inputs[2], "Kind", "string", "Inputs[2].Kind") + assertPromptyStringField(t, instance.Inputs[2], "Default", "What is the meaning of life?", "Inputs[2].Default") + if instance.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, instance.Model.Id) + } + if instance.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, instance.Template.Format.Kind) + } + if instance.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, instance.Template.Parser.Kind) + } +} + +// TestPromptyFromYAML5 tests loading Prompty through the generated YAML helper +func TestPromptyFromYAML5(t *testing.T) { + yamlData := ` +name: basic-prompt +displayName: Basic Prompt +description: A basic prompt that uses the GPT-3 chat API to answer questions +metadata: + authors: + - sethjuarez + - jietong + tags: + - example + - prompt +inputs: + - name: firstName + kind: string + default: Jane + - name: lastName + kind: string + default: Doe + - name: question + kind: string + default: What is the meaning of life? +outputs: + answer: + kind: string + description: The answer to the user's question. +model: + id: gpt-35-turbo + connection: + kind: key + endpoint: "https://{your-custom-endpoint}.openai.azure.com/" + apiKey: "{your-api-key}" +tools: + getCurrentWeather: + kind: function + description: Get the current weather in a given location + parameters: + location: + kind: string + description: The city and state, e.g. San Francisco, CA + unit: + kind: string + description: The unit of temperature, e.g. Celsius or Fahrenheit +template: + format: mustache + parser: prompty +instructions: "system: + + You are an AI assistant who helps people find information. + + As the assistant, you answer questions briefly, succinctly, + + and in a personable manner using markdown and even add some\ + + personal flair with appropriate emojis. + + + # Customer + + You are helping {{firstName}} {{lastName}} to find answers to\ + + their questions. Use their name to address them in your responses. + + user: + + {{question}}" + +` + + instance, err := prompty.PromptyFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load Prompty from YAML helper: %v", err) + } + if instance.Name != "basic-prompt" { + t.Errorf(`Expected Name to be "basic-prompt", got %v`, instance.Name) + } + if instance.DisplayName == nil || *instance.DisplayName != "Basic Prompt" { + t.Errorf(`Expected DisplayName to be "Basic Prompt", got %v`, instance.DisplayName) + } + if instance.Description == nil || *instance.Description != "A basic prompt that uses the GPT-3 chat API to answer questions" { + t.Errorf(`Expected Description to be "A basic prompt that uses the GPT-3 chat API to answer questions", got %v`, instance.Description) + } + if instance.Instructions == nil || *instance.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { + t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, instance.Instructions) + } + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(instance.Inputs) != 3 { + t.Fatalf("Expected Inputs length to be 3, got %d", len(instance.Inputs)) + } + assertPromptyStringField(t, instance.Inputs[0], "Name", "firstName", "Inputs[0].Name") + assertPromptyStringField(t, instance.Inputs[0], "Kind", "string", "Inputs[0].Kind") + assertPromptyStringField(t, instance.Inputs[0], "Default", "Jane", "Inputs[0].Default") + assertPromptyStringField(t, instance.Inputs[1], "Name", "lastName", "Inputs[1].Name") + assertPromptyStringField(t, instance.Inputs[1], "Kind", "string", "Inputs[1].Kind") + assertPromptyStringField(t, instance.Inputs[1], "Default", "Doe", "Inputs[1].Default") + assertPromptyStringField(t, instance.Inputs[2], "Name", "question", "Inputs[2].Name") + assertPromptyStringField(t, instance.Inputs[2], "Kind", "string", "Inputs[2].Kind") + assertPromptyStringField(t, instance.Inputs[2], "Default", "What is the meaning of life?", "Inputs[2].Default") + if instance.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, instance.Model.Id) + } + if instance.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, instance.Template.Format.Kind) + } + if instance.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, instance.Template.Parser.Kind) + } +} + +// TestPromptyRoundtrip5 tests load -> save -> load produces equivalent data func TestPromptyRoundtrip5(t *testing.T) { jsonData := ` { @@ -2642,6 +4726,30 @@ func TestPromptyRoundtrip5(t *testing.T) { if reloaded.Instructions == nil || *reloaded.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, reloaded.Instructions) } + if reloaded.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(reloaded.Inputs) != 3 { + t.Fatalf("Expected Inputs length to be 3, got %d", len(reloaded.Inputs)) + } + assertPromptyStringField(t, reloaded.Inputs[0], "Name", "firstName", "Inputs[0].Name") + assertPromptyStringField(t, reloaded.Inputs[0], "Kind", "string", "Inputs[0].Kind") + assertPromptyStringField(t, reloaded.Inputs[0], "Default", "Jane", "Inputs[0].Default") + assertPromptyStringField(t, reloaded.Inputs[1], "Name", "lastName", "Inputs[1].Name") + assertPromptyStringField(t, reloaded.Inputs[1], "Kind", "string", "Inputs[1].Kind") + assertPromptyStringField(t, reloaded.Inputs[1], "Default", "Doe", "Inputs[1].Default") + assertPromptyStringField(t, reloaded.Inputs[2], "Name", "question", "Inputs[2].Name") + assertPromptyStringField(t, reloaded.Inputs[2], "Kind", "string", "Inputs[2].Kind") + assertPromptyStringField(t, reloaded.Inputs[2], "Default", "What is the meaning of life?", "Inputs[2].Default") + if reloaded.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, reloaded.Model.Id) + } + if reloaded.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, reloaded.Template.Format.Kind) + } + if reloaded.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, reloaded.Template.Parser.Kind) + } } // TestPromptyToJSON5 tests that ToJSON produces valid JSON @@ -2734,6 +4842,47 @@ func TestPromptyToJSON5(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadPrompty(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Name != "basic-prompt" { + t.Errorf(`Expected Name to be "basic-prompt", got %v`, reloaded.Name) + } + if reloaded.DisplayName == nil || *reloaded.DisplayName != "Basic Prompt" { + t.Errorf(`Expected DisplayName to be "Basic Prompt", got %v`, reloaded.DisplayName) + } + if reloaded.Description == nil || *reloaded.Description != "A basic prompt that uses the GPT-3 chat API to answer questions" { + t.Errorf(`Expected Description to be "A basic prompt that uses the GPT-3 chat API to answer questions", got %v`, reloaded.Description) + } + if reloaded.Instructions == nil || *reloaded.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { + t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, reloaded.Instructions) + } + if reloaded.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(reloaded.Inputs) != 3 { + t.Fatalf("Expected Inputs length to be 3, got %d", len(reloaded.Inputs)) + } + assertPromptyStringField(t, reloaded.Inputs[0], "Name", "firstName", "Inputs[0].Name") + assertPromptyStringField(t, reloaded.Inputs[0], "Kind", "string", "Inputs[0].Kind") + assertPromptyStringField(t, reloaded.Inputs[0], "Default", "Jane", "Inputs[0].Default") + assertPromptyStringField(t, reloaded.Inputs[1], "Name", "lastName", "Inputs[1].Name") + assertPromptyStringField(t, reloaded.Inputs[1], "Kind", "string", "Inputs[1].Kind") + assertPromptyStringField(t, reloaded.Inputs[1], "Default", "Doe", "Inputs[1].Default") + assertPromptyStringField(t, reloaded.Inputs[2], "Name", "question", "Inputs[2].Name") + assertPromptyStringField(t, reloaded.Inputs[2], "Kind", "string", "Inputs[2].Kind") + assertPromptyStringField(t, reloaded.Inputs[2], "Default", "What is the meaning of life?", "Inputs[2].Default") + if reloaded.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, reloaded.Model.Id) + } + if reloaded.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, reloaded.Template.Format.Kind) + } + if reloaded.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, reloaded.Template.Parser.Kind) + } } // TestPromptyToYAML5 tests that ToYAML produces valid YAML @@ -2826,6 +4975,47 @@ func TestPromptyToYAML5(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadPrompty(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Name != "basic-prompt" { + t.Errorf(`Expected Name to be "basic-prompt", got %v`, reloaded.Name) + } + if reloaded.DisplayName == nil || *reloaded.DisplayName != "Basic Prompt" { + t.Errorf(`Expected DisplayName to be "Basic Prompt", got %v`, reloaded.DisplayName) + } + if reloaded.Description == nil || *reloaded.Description != "A basic prompt that uses the GPT-3 chat API to answer questions" { + t.Errorf(`Expected Description to be "A basic prompt that uses the GPT-3 chat API to answer questions", got %v`, reloaded.Description) + } + if reloaded.Instructions == nil || *reloaded.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { + t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, reloaded.Instructions) + } + if reloaded.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(reloaded.Inputs) != 3 { + t.Fatalf("Expected Inputs length to be 3, got %d", len(reloaded.Inputs)) + } + assertPromptyStringField(t, reloaded.Inputs[0], "Name", "firstName", "Inputs[0].Name") + assertPromptyStringField(t, reloaded.Inputs[0], "Kind", "string", "Inputs[0].Kind") + assertPromptyStringField(t, reloaded.Inputs[0], "Default", "Jane", "Inputs[0].Default") + assertPromptyStringField(t, reloaded.Inputs[1], "Name", "lastName", "Inputs[1].Name") + assertPromptyStringField(t, reloaded.Inputs[1], "Kind", "string", "Inputs[1].Kind") + assertPromptyStringField(t, reloaded.Inputs[1], "Default", "Doe", "Inputs[1].Default") + assertPromptyStringField(t, reloaded.Inputs[2], "Name", "question", "Inputs[2].Name") + assertPromptyStringField(t, reloaded.Inputs[2], "Kind", "string", "Inputs[2].Kind") + assertPromptyStringField(t, reloaded.Inputs[2], "Default", "What is the meaning of life?", "Inputs[2].Default") + if reloaded.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, reloaded.Model.Id) + } + if reloaded.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, reloaded.Template.Format.Kind) + } + if reloaded.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, reloaded.Template.Parser.Kind) + } } // TestPromptyLoadJSON6 tests loading Prompty from JSON @@ -2923,6 +5113,43 @@ func TestPromptyLoadJSON6(t *testing.T) { if instance.Instructions == nil || *instance.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, instance.Instructions) } + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(instance.Inputs) != 3 { + t.Fatalf("Expected Inputs length to be 3, got %d", len(instance.Inputs)) + } + assertPromptyStringField(t, instance.Inputs[0], "Name", "firstName", "Inputs[0].Name") + assertPromptyStringField(t, instance.Inputs[0], "Kind", "string", "Inputs[0].Kind") + assertPromptyStringField(t, instance.Inputs[0], "Default", "Jane", "Inputs[0].Default") + assertPromptyStringField(t, instance.Inputs[1], "Name", "lastName", "Inputs[1].Name") + assertPromptyStringField(t, instance.Inputs[1], "Kind", "string", "Inputs[1].Kind") + assertPromptyStringField(t, instance.Inputs[1], "Default", "Doe", "Inputs[1].Default") + assertPromptyStringField(t, instance.Inputs[2], "Name", "question", "Inputs[2].Name") + assertPromptyStringField(t, instance.Inputs[2], "Kind", "string", "Inputs[2].Kind") + assertPromptyStringField(t, instance.Inputs[2], "Default", "What is the meaning of life?", "Inputs[2].Default") + if len(instance.Outputs) != 1 { + t.Fatalf("Expected Outputs length to be 1, got %d", len(instance.Outputs)) + } + if instance.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, instance.Model.Id) + } + if len(instance.Tools) != 1 { + t.Fatalf("Expected Tools length to be 1, got %d", len(instance.Tools)) + } + tools0Value, ok := instance.Tools[0].(prompty.FunctionTool) + if !ok { + t.Fatalf("Expected Tools[0] to be prompty.FunctionTool, got %T", instance.Tools[0]) + } + if tools0Value.Kind != "function" { + t.Errorf(`Expected Kind to be "function", got %v`, tools0Value.Kind) + } + if instance.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, instance.Template.Format.Kind) + } + if instance.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, instance.Template.Parser.Kind) + } } // TestPromptyLoadYAML6 tests loading Prompty from YAML @@ -3016,10 +5243,47 @@ instructions: "system: if instance.Instructions == nil || *instance.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, instance.Instructions) } + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(instance.Inputs) != 3 { + t.Fatalf("Expected Inputs length to be 3, got %d", len(instance.Inputs)) + } + assertPromptyStringField(t, instance.Inputs[0], "Name", "firstName", "Inputs[0].Name") + assertPromptyStringField(t, instance.Inputs[0], "Kind", "string", "Inputs[0].Kind") + assertPromptyStringField(t, instance.Inputs[0], "Default", "Jane", "Inputs[0].Default") + assertPromptyStringField(t, instance.Inputs[1], "Name", "lastName", "Inputs[1].Name") + assertPromptyStringField(t, instance.Inputs[1], "Kind", "string", "Inputs[1].Kind") + assertPromptyStringField(t, instance.Inputs[1], "Default", "Doe", "Inputs[1].Default") + assertPromptyStringField(t, instance.Inputs[2], "Name", "question", "Inputs[2].Name") + assertPromptyStringField(t, instance.Inputs[2], "Kind", "string", "Inputs[2].Kind") + assertPromptyStringField(t, instance.Inputs[2], "Default", "What is the meaning of life?", "Inputs[2].Default") + if len(instance.Outputs) != 1 { + t.Fatalf("Expected Outputs length to be 1, got %d", len(instance.Outputs)) + } + if instance.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, instance.Model.Id) + } + if len(instance.Tools) != 1 { + t.Fatalf("Expected Tools length to be 1, got %d", len(instance.Tools)) + } + tools0Value, ok := instance.Tools[0].(prompty.FunctionTool) + if !ok { + t.Fatalf("Expected Tools[0] to be prompty.FunctionTool, got %T", instance.Tools[0]) + } + if tools0Value.Kind != "function" { + t.Errorf(`Expected Kind to be "function", got %v`, tools0Value.Kind) + } + if instance.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, instance.Template.Format.Kind) + } + if instance.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, instance.Template.Parser.Kind) + } } -// TestPromptyRoundtrip6 tests load -> save -> load produces equivalent data -func TestPromptyRoundtrip6(t *testing.T) { +// TestPromptyFromJSON6 tests loading Prompty through the generated JSON helper +func TestPromptyFromJSON6(t *testing.T) { jsonData := ` { "name": "basic-prompt", @@ -3091,19 +5355,273 @@ func TestPromptyRoundtrip6(t *testing.T) { "instructions": "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" } ` - var data map[string]interface{} - if err := json.Unmarshal([]byte(jsonData), &data); err != nil { - t.Fatalf("Failed to parse JSON: %v", err) - } - loadCtx := prompty.NewLoadContext() - instance, err := prompty.LoadPrompty(data, loadCtx) + instance, err := prompty.PromptyFromJSON(jsonData) if err != nil { - t.Fatalf("Failed to load Prompty: %v", err) + t.Fatalf("Failed to load Prompty from JSON helper: %v", err) } - saveCtx := prompty.NewSaveContext() - savedData := instance.Save(saveCtx) - + if instance.Name != "basic-prompt" { + t.Errorf(`Expected Name to be "basic-prompt", got %v`, instance.Name) + } + if instance.DisplayName == nil || *instance.DisplayName != "Basic Prompt" { + t.Errorf(`Expected DisplayName to be "Basic Prompt", got %v`, instance.DisplayName) + } + if instance.Description == nil || *instance.Description != "A basic prompt that uses the GPT-3 chat API to answer questions" { + t.Errorf(`Expected Description to be "A basic prompt that uses the GPT-3 chat API to answer questions", got %v`, instance.Description) + } + if instance.Instructions == nil || *instance.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { + t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, instance.Instructions) + } + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(instance.Inputs) != 3 { + t.Fatalf("Expected Inputs length to be 3, got %d", len(instance.Inputs)) + } + assertPromptyStringField(t, instance.Inputs[0], "Name", "firstName", "Inputs[0].Name") + assertPromptyStringField(t, instance.Inputs[0], "Kind", "string", "Inputs[0].Kind") + assertPromptyStringField(t, instance.Inputs[0], "Default", "Jane", "Inputs[0].Default") + assertPromptyStringField(t, instance.Inputs[1], "Name", "lastName", "Inputs[1].Name") + assertPromptyStringField(t, instance.Inputs[1], "Kind", "string", "Inputs[1].Kind") + assertPromptyStringField(t, instance.Inputs[1], "Default", "Doe", "Inputs[1].Default") + assertPromptyStringField(t, instance.Inputs[2], "Name", "question", "Inputs[2].Name") + assertPromptyStringField(t, instance.Inputs[2], "Kind", "string", "Inputs[2].Kind") + assertPromptyStringField(t, instance.Inputs[2], "Default", "What is the meaning of life?", "Inputs[2].Default") + if len(instance.Outputs) != 1 { + t.Fatalf("Expected Outputs length to be 1, got %d", len(instance.Outputs)) + } + if instance.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, instance.Model.Id) + } + if len(instance.Tools) != 1 { + t.Fatalf("Expected Tools length to be 1, got %d", len(instance.Tools)) + } + tools0Value, ok := instance.Tools[0].(prompty.FunctionTool) + if !ok { + t.Fatalf("Expected Tools[0] to be prompty.FunctionTool, got %T", instance.Tools[0]) + } + if tools0Value.Kind != "function" { + t.Errorf(`Expected Kind to be "function", got %v`, tools0Value.Kind) + } + if instance.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, instance.Template.Format.Kind) + } + if instance.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, instance.Template.Parser.Kind) + } +} + +// TestPromptyFromYAML6 tests loading Prompty through the generated YAML helper +func TestPromptyFromYAML6(t *testing.T) { + yamlData := ` +name: basic-prompt +displayName: Basic Prompt +description: A basic prompt that uses the GPT-3 chat API to answer questions +metadata: + authors: + - sethjuarez + - jietong + tags: + - example + - prompt +inputs: + - name: firstName + kind: string + default: Jane + - name: lastName + kind: string + default: Doe + - name: question + kind: string + default: What is the meaning of life? +outputs: + - name: answer + kind: string + description: The answer to the user's question. +model: + id: gpt-35-turbo + connection: + kind: key + endpoint: "https://{your-custom-endpoint}.openai.azure.com/" + apiKey: "{your-api-key}" +tools: + - name: getCurrentWeather + kind: function + description: Get the current weather in a given location + parameters: + location: + kind: string + description: The city and state, e.g. San Francisco, CA + unit: + kind: string + description: The unit of temperature, e.g. Celsius or Fahrenheit +template: + format: mustache + parser: prompty +instructions: "system: + + You are an AI assistant who helps people find information. + + As the assistant, you answer questions briefly, succinctly, + + and in a personable manner using markdown and even add some\ + + personal flair with appropriate emojis. + + + # Customer + + You are helping {{firstName}} {{lastName}} to find answers to\ + + their questions. Use their name to address them in your responses. + + user: + + {{question}}" + +` + + instance, err := prompty.PromptyFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load Prompty from YAML helper: %v", err) + } + if instance.Name != "basic-prompt" { + t.Errorf(`Expected Name to be "basic-prompt", got %v`, instance.Name) + } + if instance.DisplayName == nil || *instance.DisplayName != "Basic Prompt" { + t.Errorf(`Expected DisplayName to be "Basic Prompt", got %v`, instance.DisplayName) + } + if instance.Description == nil || *instance.Description != "A basic prompt that uses the GPT-3 chat API to answer questions" { + t.Errorf(`Expected Description to be "A basic prompt that uses the GPT-3 chat API to answer questions", got %v`, instance.Description) + } + if instance.Instructions == nil || *instance.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { + t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, instance.Instructions) + } + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(instance.Inputs) != 3 { + t.Fatalf("Expected Inputs length to be 3, got %d", len(instance.Inputs)) + } + assertPromptyStringField(t, instance.Inputs[0], "Name", "firstName", "Inputs[0].Name") + assertPromptyStringField(t, instance.Inputs[0], "Kind", "string", "Inputs[0].Kind") + assertPromptyStringField(t, instance.Inputs[0], "Default", "Jane", "Inputs[0].Default") + assertPromptyStringField(t, instance.Inputs[1], "Name", "lastName", "Inputs[1].Name") + assertPromptyStringField(t, instance.Inputs[1], "Kind", "string", "Inputs[1].Kind") + assertPromptyStringField(t, instance.Inputs[1], "Default", "Doe", "Inputs[1].Default") + assertPromptyStringField(t, instance.Inputs[2], "Name", "question", "Inputs[2].Name") + assertPromptyStringField(t, instance.Inputs[2], "Kind", "string", "Inputs[2].Kind") + assertPromptyStringField(t, instance.Inputs[2], "Default", "What is the meaning of life?", "Inputs[2].Default") + if len(instance.Outputs) != 1 { + t.Fatalf("Expected Outputs length to be 1, got %d", len(instance.Outputs)) + } + if instance.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, instance.Model.Id) + } + if len(instance.Tools) != 1 { + t.Fatalf("Expected Tools length to be 1, got %d", len(instance.Tools)) + } + tools0Value, ok := instance.Tools[0].(prompty.FunctionTool) + if !ok { + t.Fatalf("Expected Tools[0] to be prompty.FunctionTool, got %T", instance.Tools[0]) + } + if tools0Value.Kind != "function" { + t.Errorf(`Expected Kind to be "function", got %v`, tools0Value.Kind) + } + if instance.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, instance.Template.Format.Kind) + } + if instance.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, instance.Template.Parser.Kind) + } +} + +// TestPromptyRoundtrip6 tests load -> save -> load produces equivalent data +func TestPromptyRoundtrip6(t *testing.T) { + jsonData := ` +{ + "name": "basic-prompt", + "displayName": "Basic Prompt", + "description": "A basic prompt that uses the GPT-3 chat API to answer questions", + "metadata": { + "authors": [ + "sethjuarez", + "jietong" + ], + "tags": [ + "example", + "prompt" + ] + }, + "inputs": [ + { + "name": "firstName", + "kind": "string", + "default": "Jane" + }, + { + "name": "lastName", + "kind": "string", + "default": "Doe" + }, + { + "name": "question", + "kind": "string", + "default": "What is the meaning of life?" + } + ], + "outputs": [ + { + "name": "answer", + "kind": "string", + "description": "The answer to the user's question." + } + ], + "model": { + "id": "gpt-35-turbo", + "connection": { + "kind": "key", + "endpoint": "https://{your-custom-endpoint}.openai.azure.com/", + "apiKey": "{your-api-key}" + } + }, + "tools": [ + { + "name": "getCurrentWeather", + "kind": "function", + "description": "Get the current weather in a given location", + "parameters": { + "location": { + "kind": "string", + "description": "The city and state, e.g. San Francisco, CA" + }, + "unit": { + "kind": "string", + "description": "The unit of temperature, e.g. Celsius or Fahrenheit" + } + } + } + ], + "template": { + "format": "mustache", + "parser": "prompty" + }, + "instructions": "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + loadCtx := prompty.NewLoadContext() + instance, err := prompty.LoadPrompty(data, loadCtx) + if err != nil { + t.Fatalf("Failed to load Prompty: %v", err) + } + saveCtx := prompty.NewSaveContext() + savedData := instance.Save(saveCtx) + reloaded, err := prompty.LoadPrompty(savedData, loadCtx) if err != nil { t.Fatalf("Failed to reload Prompty: %v", err) @@ -3114,16 +5632,201 @@ func TestPromptyRoundtrip6(t *testing.T) { if reloaded.DisplayName == nil || *reloaded.DisplayName != "Basic Prompt" { t.Errorf(`Expected DisplayName to be "Basic Prompt", got %v`, reloaded.DisplayName) } - if reloaded.Description == nil || *reloaded.Description != "A basic prompt that uses the GPT-3 chat API to answer questions" { - t.Errorf(`Expected Description to be "A basic prompt that uses the GPT-3 chat API to answer questions", got %v`, reloaded.Description) + if reloaded.Description == nil || *reloaded.Description != "A basic prompt that uses the GPT-3 chat API to answer questions" { + t.Errorf(`Expected Description to be "A basic prompt that uses the GPT-3 chat API to answer questions", got %v`, reloaded.Description) + } + if reloaded.Instructions == nil || *reloaded.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { + t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, reloaded.Instructions) + } + if reloaded.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(reloaded.Inputs) != 3 { + t.Fatalf("Expected Inputs length to be 3, got %d", len(reloaded.Inputs)) + } + assertPromptyStringField(t, reloaded.Inputs[0], "Name", "firstName", "Inputs[0].Name") + assertPromptyStringField(t, reloaded.Inputs[0], "Kind", "string", "Inputs[0].Kind") + assertPromptyStringField(t, reloaded.Inputs[0], "Default", "Jane", "Inputs[0].Default") + assertPromptyStringField(t, reloaded.Inputs[1], "Name", "lastName", "Inputs[1].Name") + assertPromptyStringField(t, reloaded.Inputs[1], "Kind", "string", "Inputs[1].Kind") + assertPromptyStringField(t, reloaded.Inputs[1], "Default", "Doe", "Inputs[1].Default") + assertPromptyStringField(t, reloaded.Inputs[2], "Name", "question", "Inputs[2].Name") + assertPromptyStringField(t, reloaded.Inputs[2], "Kind", "string", "Inputs[2].Kind") + assertPromptyStringField(t, reloaded.Inputs[2], "Default", "What is the meaning of life?", "Inputs[2].Default") + if len(reloaded.Outputs) != 1 { + t.Fatalf("Expected Outputs length to be 1, got %d", len(reloaded.Outputs)) + } + if reloaded.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, reloaded.Model.Id) + } + if len(reloaded.Tools) != 1 { + t.Fatalf("Expected Tools length to be 1, got %d", len(reloaded.Tools)) + } + tools0Value, ok := reloaded.Tools[0].(prompty.FunctionTool) + if !ok { + t.Fatalf("Expected Tools[0] to be prompty.FunctionTool, got %T", reloaded.Tools[0]) + } + if tools0Value.Kind != "function" { + t.Errorf(`Expected Kind to be "function", got %v`, tools0Value.Kind) + } + if reloaded.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, reloaded.Template.Format.Kind) + } + if reloaded.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, reloaded.Template.Parser.Kind) + } +} + +// TestPromptyToJSON6 tests that ToJSON produces valid JSON +func TestPromptyToJSON6(t *testing.T) { + jsonData := ` +{ + "name": "basic-prompt", + "displayName": "Basic Prompt", + "description": "A basic prompt that uses the GPT-3 chat API to answer questions", + "metadata": { + "authors": [ + "sethjuarez", + "jietong" + ], + "tags": [ + "example", + "prompt" + ] + }, + "inputs": [ + { + "name": "firstName", + "kind": "string", + "default": "Jane" + }, + { + "name": "lastName", + "kind": "string", + "default": "Doe" + }, + { + "name": "question", + "kind": "string", + "default": "What is the meaning of life?" + } + ], + "outputs": [ + { + "name": "answer", + "kind": "string", + "description": "The answer to the user's question." + } + ], + "model": { + "id": "gpt-35-turbo", + "connection": { + "kind": "key", + "endpoint": "https://{your-custom-endpoint}.openai.azure.com/", + "apiKey": "{your-api-key}" + } + }, + "tools": [ + { + "name": "getCurrentWeather", + "kind": "function", + "description": "Get the current weather in a given location", + "parameters": { + "location": { + "kind": "string", + "description": "The city and state, e.g. San Francisco, CA" + }, + "unit": { + "kind": "string", + "description": "The unit of temperature, e.g. Celsius or Fahrenheit" + } + } + } + ], + "template": { + "format": "mustache", + "parser": "prompty" + }, + "instructions": "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadPrompty(data, ctx) + if err != nil { + t.Fatalf("Failed to load Prompty: %v", err) + } + jsonOutput, err := instance.ToJSON() + if err != nil { + t.Fatalf("Failed to convert to JSON: %v", err) + } + + var parsed map[string]interface{} + if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated JSON: %v", err) + } + + reloaded, err := prompty.LoadPrompty(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Name != "basic-prompt" { + t.Errorf(`Expected Name to be "basic-prompt", got %v`, reloaded.Name) + } + if reloaded.DisplayName == nil || *reloaded.DisplayName != "Basic Prompt" { + t.Errorf(`Expected DisplayName to be "Basic Prompt", got %v`, reloaded.DisplayName) + } + if reloaded.Description == nil || *reloaded.Description != "A basic prompt that uses the GPT-3 chat API to answer questions" { + t.Errorf(`Expected Description to be "A basic prompt that uses the GPT-3 chat API to answer questions", got %v`, reloaded.Description) + } + if reloaded.Instructions == nil || *reloaded.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { + t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, reloaded.Instructions) + } + if reloaded.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(reloaded.Inputs) != 3 { + t.Fatalf("Expected Inputs length to be 3, got %d", len(reloaded.Inputs)) + } + assertPromptyStringField(t, reloaded.Inputs[0], "Name", "firstName", "Inputs[0].Name") + assertPromptyStringField(t, reloaded.Inputs[0], "Kind", "string", "Inputs[0].Kind") + assertPromptyStringField(t, reloaded.Inputs[0], "Default", "Jane", "Inputs[0].Default") + assertPromptyStringField(t, reloaded.Inputs[1], "Name", "lastName", "Inputs[1].Name") + assertPromptyStringField(t, reloaded.Inputs[1], "Kind", "string", "Inputs[1].Kind") + assertPromptyStringField(t, reloaded.Inputs[1], "Default", "Doe", "Inputs[1].Default") + assertPromptyStringField(t, reloaded.Inputs[2], "Name", "question", "Inputs[2].Name") + assertPromptyStringField(t, reloaded.Inputs[2], "Kind", "string", "Inputs[2].Kind") + assertPromptyStringField(t, reloaded.Inputs[2], "Default", "What is the meaning of life?", "Inputs[2].Default") + if len(reloaded.Outputs) != 1 { + t.Fatalf("Expected Outputs length to be 1, got %d", len(reloaded.Outputs)) + } + if reloaded.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, reloaded.Model.Id) + } + if len(reloaded.Tools) != 1 { + t.Fatalf("Expected Tools length to be 1, got %d", len(reloaded.Tools)) + } + tools0Value, ok := reloaded.Tools[0].(prompty.FunctionTool) + if !ok { + t.Fatalf("Expected Tools[0] to be prompty.FunctionTool, got %T", reloaded.Tools[0]) + } + if tools0Value.Kind != "function" { + t.Errorf(`Expected Kind to be "function", got %v`, tools0Value.Kind) } - if reloaded.Instructions == nil || *reloaded.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { - t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, reloaded.Instructions) + if reloaded.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, reloaded.Template.Format.Kind) + } + if reloaded.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, reloaded.Template.Parser.Kind) } } -// TestPromptyToJSON6 tests that ToJSON produces valid JSON -func TestPromptyToJSON6(t *testing.T) { +// TestPromptyToYAML6 tests that ToYAML produces valid YAML +func TestPromptyToYAML6(t *testing.T) { jsonData := ` { "name": "basic-prompt", @@ -3205,19 +5908,73 @@ func TestPromptyToJSON6(t *testing.T) { if err != nil { t.Fatalf("Failed to load Prompty: %v", err) } - jsonOutput, err := instance.ToJSON() + yamlOutput, err := instance.ToYAML() if err != nil { - t.Fatalf("Failed to convert to JSON: %v", err) + t.Fatalf("Failed to convert to YAML: %v", err) } var parsed map[string]interface{} - if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { - t.Fatalf("Failed to parse generated JSON: %v", err) + if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { + t.Fatalf("Failed to parse generated YAML: %v", err) + } + + reloaded, err := prompty.LoadPrompty(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Name != "basic-prompt" { + t.Errorf(`Expected Name to be "basic-prompt", got %v`, reloaded.Name) + } + if reloaded.DisplayName == nil || *reloaded.DisplayName != "Basic Prompt" { + t.Errorf(`Expected DisplayName to be "Basic Prompt", got %v`, reloaded.DisplayName) + } + if reloaded.Description == nil || *reloaded.Description != "A basic prompt that uses the GPT-3 chat API to answer questions" { + t.Errorf(`Expected Description to be "A basic prompt that uses the GPT-3 chat API to answer questions", got %v`, reloaded.Description) + } + if reloaded.Instructions == nil || *reloaded.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { + t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, reloaded.Instructions) + } + if reloaded.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(reloaded.Inputs) != 3 { + t.Fatalf("Expected Inputs length to be 3, got %d", len(reloaded.Inputs)) + } + assertPromptyStringField(t, reloaded.Inputs[0], "Name", "firstName", "Inputs[0].Name") + assertPromptyStringField(t, reloaded.Inputs[0], "Kind", "string", "Inputs[0].Kind") + assertPromptyStringField(t, reloaded.Inputs[0], "Default", "Jane", "Inputs[0].Default") + assertPromptyStringField(t, reloaded.Inputs[1], "Name", "lastName", "Inputs[1].Name") + assertPromptyStringField(t, reloaded.Inputs[1], "Kind", "string", "Inputs[1].Kind") + assertPromptyStringField(t, reloaded.Inputs[1], "Default", "Doe", "Inputs[1].Default") + assertPromptyStringField(t, reloaded.Inputs[2], "Name", "question", "Inputs[2].Name") + assertPromptyStringField(t, reloaded.Inputs[2], "Kind", "string", "Inputs[2].Kind") + assertPromptyStringField(t, reloaded.Inputs[2], "Default", "What is the meaning of life?", "Inputs[2].Default") + if len(reloaded.Outputs) != 1 { + t.Fatalf("Expected Outputs length to be 1, got %d", len(reloaded.Outputs)) + } + if reloaded.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, reloaded.Model.Id) + } + if len(reloaded.Tools) != 1 { + t.Fatalf("Expected Tools length to be 1, got %d", len(reloaded.Tools)) + } + tools0Value, ok := reloaded.Tools[0].(prompty.FunctionTool) + if !ok { + t.Fatalf("Expected Tools[0] to be prompty.FunctionTool, got %T", reloaded.Tools[0]) + } + if tools0Value.Kind != "function" { + t.Errorf(`Expected Kind to be "function", got %v`, tools0Value.Kind) + } + if reloaded.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, reloaded.Template.Format.Kind) + } + if reloaded.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, reloaded.Template.Parser.Kind) } } -// TestPromptyToYAML6 tests that ToYAML produces valid YAML -func TestPromptyToYAML6(t *testing.T) { +// TestPromptyLoadJSON7 tests loading Prompty from JSON +func TestPromptyLoadJSON7(t *testing.T) { jsonData := ` { "name": "basic-prompt", @@ -3265,9 +6022,8 @@ func TestPromptyToYAML6(t *testing.T) { "apiKey": "{your-api-key}" } }, - "tools": [ - { - "name": "getCurrentWeather", + "tools": { + "getCurrentWeather": { "kind": "function", "description": "Get the current weather in a given location", "parameters": { @@ -3281,7 +6037,7 @@ func TestPromptyToYAML6(t *testing.T) { } } } - ], + }, "template": { "format": "mustache", "parser": "prompty" @@ -3299,19 +6055,169 @@ func TestPromptyToYAML6(t *testing.T) { if err != nil { t.Fatalf("Failed to load Prompty: %v", err) } - yamlOutput, err := instance.ToYAML() - if err != nil { - t.Fatalf("Failed to convert to YAML: %v", err) + if instance.Name != "basic-prompt" { + t.Errorf(`Expected Name to be "basic-prompt", got %v`, instance.Name) + } + if instance.DisplayName == nil || *instance.DisplayName != "Basic Prompt" { + t.Errorf(`Expected DisplayName to be "Basic Prompt", got %v`, instance.DisplayName) + } + if instance.Description == nil || *instance.Description != "A basic prompt that uses the GPT-3 chat API to answer questions" { + t.Errorf(`Expected Description to be "A basic prompt that uses the GPT-3 chat API to answer questions", got %v`, instance.Description) + } + if instance.Instructions == nil || *instance.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { + t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, instance.Instructions) + } + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(instance.Inputs) != 3 { + t.Fatalf("Expected Inputs length to be 3, got %d", len(instance.Inputs)) + } + assertPromptyStringField(t, instance.Inputs[0], "Name", "firstName", "Inputs[0].Name") + assertPromptyStringField(t, instance.Inputs[0], "Kind", "string", "Inputs[0].Kind") + assertPromptyStringField(t, instance.Inputs[0], "Default", "Jane", "Inputs[0].Default") + assertPromptyStringField(t, instance.Inputs[1], "Name", "lastName", "Inputs[1].Name") + assertPromptyStringField(t, instance.Inputs[1], "Kind", "string", "Inputs[1].Kind") + assertPromptyStringField(t, instance.Inputs[1], "Default", "Doe", "Inputs[1].Default") + assertPromptyStringField(t, instance.Inputs[2], "Name", "question", "Inputs[2].Name") + assertPromptyStringField(t, instance.Inputs[2], "Kind", "string", "Inputs[2].Kind") + assertPromptyStringField(t, instance.Inputs[2], "Default", "What is the meaning of life?", "Inputs[2].Default") + if len(instance.Outputs) != 1 { + t.Fatalf("Expected Outputs length to be 1, got %d", len(instance.Outputs)) + } + if instance.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, instance.Model.Id) + } + if instance.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, instance.Template.Format.Kind) + } + if instance.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, instance.Template.Parser.Kind) } +} - var parsed map[string]interface{} - if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { - t.Fatalf("Failed to parse generated YAML: %v", err) +// TestPromptyLoadYAML7 tests loading Prompty from YAML +func TestPromptyLoadYAML7(t *testing.T) { + yamlData := ` +name: basic-prompt +displayName: Basic Prompt +description: A basic prompt that uses the GPT-3 chat API to answer questions +metadata: + authors: + - sethjuarez + - jietong + tags: + - example + - prompt +inputs: + - name: firstName + kind: string + default: Jane + - name: lastName + kind: string + default: Doe + - name: question + kind: string + default: What is the meaning of life? +outputs: + - name: answer + kind: string + description: The answer to the user's question. +model: + id: gpt-35-turbo + connection: + kind: key + endpoint: "https://{your-custom-endpoint}.openai.azure.com/" + apiKey: "{your-api-key}" +tools: + getCurrentWeather: + kind: function + description: Get the current weather in a given location + parameters: + location: + kind: string + description: The city and state, e.g. San Francisco, CA + unit: + kind: string + description: The unit of temperature, e.g. Celsius or Fahrenheit +template: + format: mustache + parser: prompty +instructions: "system: + + You are an AI assistant who helps people find information. + + As the assistant, you answer questions briefly, succinctly, + + and in a personable manner using markdown and even add some\ + + personal flair with appropriate emojis. + + + # Customer + + You are helping {{firstName}} {{lastName}} to find answers to\ + + their questions. Use their name to address them in your responses. + + user: + + {{question}}" + +` + var data map[string]interface{} + if err := yaml.Unmarshal([]byte(yamlData), &data); err != nil { + t.Fatalf("Failed to parse YAML: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadPrompty(data, ctx) + if err != nil { + t.Fatalf("Failed to load Prompty: %v", err) + } + if instance.Name != "basic-prompt" { + t.Errorf(`Expected Name to be "basic-prompt", got %v`, instance.Name) + } + if instance.DisplayName == nil || *instance.DisplayName != "Basic Prompt" { + t.Errorf(`Expected DisplayName to be "Basic Prompt", got %v`, instance.DisplayName) + } + if instance.Description == nil || *instance.Description != "A basic prompt that uses the GPT-3 chat API to answer questions" { + t.Errorf(`Expected Description to be "A basic prompt that uses the GPT-3 chat API to answer questions", got %v`, instance.Description) + } + if instance.Instructions == nil || *instance.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { + t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, instance.Instructions) + } + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(instance.Inputs) != 3 { + t.Fatalf("Expected Inputs length to be 3, got %d", len(instance.Inputs)) + } + assertPromptyStringField(t, instance.Inputs[0], "Name", "firstName", "Inputs[0].Name") + assertPromptyStringField(t, instance.Inputs[0], "Kind", "string", "Inputs[0].Kind") + assertPromptyStringField(t, instance.Inputs[0], "Default", "Jane", "Inputs[0].Default") + assertPromptyStringField(t, instance.Inputs[1], "Name", "lastName", "Inputs[1].Name") + assertPromptyStringField(t, instance.Inputs[1], "Kind", "string", "Inputs[1].Kind") + assertPromptyStringField(t, instance.Inputs[1], "Default", "Doe", "Inputs[1].Default") + assertPromptyStringField(t, instance.Inputs[2], "Name", "question", "Inputs[2].Name") + assertPromptyStringField(t, instance.Inputs[2], "Kind", "string", "Inputs[2].Kind") + assertPromptyStringField(t, instance.Inputs[2], "Default", "What is the meaning of life?", "Inputs[2].Default") + if len(instance.Outputs) != 1 { + t.Fatalf("Expected Outputs length to be 1, got %d", len(instance.Outputs)) + } + if instance.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, instance.Model.Id) + } + if instance.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, instance.Template.Format.Kind) + } + if instance.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, instance.Template.Parser.Kind) } } -// TestPromptyLoadJSON7 tests loading Prompty from JSON -func TestPromptyLoadJSON7(t *testing.T) { +// TestPromptyFromJSON7 tests loading Prompty through the generated JSON helper +func TestPromptyFromJSON7(t *testing.T) { jsonData := ` { "name": "basic-prompt", @@ -3382,15 +6288,10 @@ func TestPromptyLoadJSON7(t *testing.T) { "instructions": "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" } ` - var data map[string]interface{} - if err := json.Unmarshal([]byte(jsonData), &data); err != nil { - t.Fatalf("Failed to parse JSON: %v", err) - } - ctx := prompty.NewLoadContext() - instance, err := prompty.LoadPrompty(data, ctx) + instance, err := prompty.PromptyFromJSON(jsonData) if err != nil { - t.Fatalf("Failed to load Prompty: %v", err) + t.Fatalf("Failed to load Prompty from JSON helper: %v", err) } if instance.Name != "basic-prompt" { t.Errorf(`Expected Name to be "basic-prompt", got %v`, instance.Name) @@ -3404,10 +6305,37 @@ func TestPromptyLoadJSON7(t *testing.T) { if instance.Instructions == nil || *instance.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, instance.Instructions) } + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(instance.Inputs) != 3 { + t.Fatalf("Expected Inputs length to be 3, got %d", len(instance.Inputs)) + } + assertPromptyStringField(t, instance.Inputs[0], "Name", "firstName", "Inputs[0].Name") + assertPromptyStringField(t, instance.Inputs[0], "Kind", "string", "Inputs[0].Kind") + assertPromptyStringField(t, instance.Inputs[0], "Default", "Jane", "Inputs[0].Default") + assertPromptyStringField(t, instance.Inputs[1], "Name", "lastName", "Inputs[1].Name") + assertPromptyStringField(t, instance.Inputs[1], "Kind", "string", "Inputs[1].Kind") + assertPromptyStringField(t, instance.Inputs[1], "Default", "Doe", "Inputs[1].Default") + assertPromptyStringField(t, instance.Inputs[2], "Name", "question", "Inputs[2].Name") + assertPromptyStringField(t, instance.Inputs[2], "Kind", "string", "Inputs[2].Kind") + assertPromptyStringField(t, instance.Inputs[2], "Default", "What is the meaning of life?", "Inputs[2].Default") + if len(instance.Outputs) != 1 { + t.Fatalf("Expected Outputs length to be 1, got %d", len(instance.Outputs)) + } + if instance.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, instance.Model.Id) + } + if instance.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, instance.Template.Format.Kind) + } + if instance.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, instance.Template.Parser.Kind) + } } -// TestPromptyLoadYAML7 tests loading Prompty from YAML -func TestPromptyLoadYAML7(t *testing.T) { +// TestPromptyFromYAML7 tests loading Prompty through the generated YAML helper +func TestPromptyFromYAML7(t *testing.T) { yamlData := ` name: basic-prompt displayName: Basic Prompt @@ -3475,15 +6403,10 @@ instructions: "system: {{question}}" ` - var data map[string]interface{} - if err := yaml.Unmarshal([]byte(yamlData), &data); err != nil { - t.Fatalf("Failed to parse YAML: %v", err) - } - ctx := prompty.NewLoadContext() - instance, err := prompty.LoadPrompty(data, ctx) + instance, err := prompty.PromptyFromYAML(yamlData) if err != nil { - t.Fatalf("Failed to load Prompty: %v", err) + t.Fatalf("Failed to load Prompty from YAML helper: %v", err) } if instance.Name != "basic-prompt" { t.Errorf(`Expected Name to be "basic-prompt", got %v`, instance.Name) @@ -3497,6 +6420,33 @@ instructions: "system: if instance.Instructions == nil || *instance.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, instance.Instructions) } + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(instance.Inputs) != 3 { + t.Fatalf("Expected Inputs length to be 3, got %d", len(instance.Inputs)) + } + assertPromptyStringField(t, instance.Inputs[0], "Name", "firstName", "Inputs[0].Name") + assertPromptyStringField(t, instance.Inputs[0], "Kind", "string", "Inputs[0].Kind") + assertPromptyStringField(t, instance.Inputs[0], "Default", "Jane", "Inputs[0].Default") + assertPromptyStringField(t, instance.Inputs[1], "Name", "lastName", "Inputs[1].Name") + assertPromptyStringField(t, instance.Inputs[1], "Kind", "string", "Inputs[1].Kind") + assertPromptyStringField(t, instance.Inputs[1], "Default", "Doe", "Inputs[1].Default") + assertPromptyStringField(t, instance.Inputs[2], "Name", "question", "Inputs[2].Name") + assertPromptyStringField(t, instance.Inputs[2], "Kind", "string", "Inputs[2].Kind") + assertPromptyStringField(t, instance.Inputs[2], "Default", "What is the meaning of life?", "Inputs[2].Default") + if len(instance.Outputs) != 1 { + t.Fatalf("Expected Outputs length to be 1, got %d", len(instance.Outputs)) + } + if instance.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, instance.Model.Id) + } + if instance.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, instance.Template.Format.Kind) + } + if instance.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, instance.Template.Parser.Kind) + } } // TestPromptyRoundtrip7 tests load -> save -> load produces equivalent data @@ -3600,6 +6550,33 @@ func TestPromptyRoundtrip7(t *testing.T) { if reloaded.Instructions == nil || *reloaded.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, reloaded.Instructions) } + if reloaded.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(reloaded.Inputs) != 3 { + t.Fatalf("Expected Inputs length to be 3, got %d", len(reloaded.Inputs)) + } + assertPromptyStringField(t, reloaded.Inputs[0], "Name", "firstName", "Inputs[0].Name") + assertPromptyStringField(t, reloaded.Inputs[0], "Kind", "string", "Inputs[0].Kind") + assertPromptyStringField(t, reloaded.Inputs[0], "Default", "Jane", "Inputs[0].Default") + assertPromptyStringField(t, reloaded.Inputs[1], "Name", "lastName", "Inputs[1].Name") + assertPromptyStringField(t, reloaded.Inputs[1], "Kind", "string", "Inputs[1].Kind") + assertPromptyStringField(t, reloaded.Inputs[1], "Default", "Doe", "Inputs[1].Default") + assertPromptyStringField(t, reloaded.Inputs[2], "Name", "question", "Inputs[2].Name") + assertPromptyStringField(t, reloaded.Inputs[2], "Kind", "string", "Inputs[2].Kind") + assertPromptyStringField(t, reloaded.Inputs[2], "Default", "What is the meaning of life?", "Inputs[2].Default") + if len(reloaded.Outputs) != 1 { + t.Fatalf("Expected Outputs length to be 1, got %d", len(reloaded.Outputs)) + } + if reloaded.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, reloaded.Model.Id) + } + if reloaded.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, reloaded.Template.Format.Kind) + } + if reloaded.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, reloaded.Template.Parser.Kind) + } } // TestPromptyToJSON7 tests that ToJSON produces valid JSON @@ -3693,6 +6670,50 @@ func TestPromptyToJSON7(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadPrompty(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Name != "basic-prompt" { + t.Errorf(`Expected Name to be "basic-prompt", got %v`, reloaded.Name) + } + if reloaded.DisplayName == nil || *reloaded.DisplayName != "Basic Prompt" { + t.Errorf(`Expected DisplayName to be "Basic Prompt", got %v`, reloaded.DisplayName) + } + if reloaded.Description == nil || *reloaded.Description != "A basic prompt that uses the GPT-3 chat API to answer questions" { + t.Errorf(`Expected Description to be "A basic prompt that uses the GPT-3 chat API to answer questions", got %v`, reloaded.Description) + } + if reloaded.Instructions == nil || *reloaded.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { + t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, reloaded.Instructions) + } + if reloaded.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(reloaded.Inputs) != 3 { + t.Fatalf("Expected Inputs length to be 3, got %d", len(reloaded.Inputs)) + } + assertPromptyStringField(t, reloaded.Inputs[0], "Name", "firstName", "Inputs[0].Name") + assertPromptyStringField(t, reloaded.Inputs[0], "Kind", "string", "Inputs[0].Kind") + assertPromptyStringField(t, reloaded.Inputs[0], "Default", "Jane", "Inputs[0].Default") + assertPromptyStringField(t, reloaded.Inputs[1], "Name", "lastName", "Inputs[1].Name") + assertPromptyStringField(t, reloaded.Inputs[1], "Kind", "string", "Inputs[1].Kind") + assertPromptyStringField(t, reloaded.Inputs[1], "Default", "Doe", "Inputs[1].Default") + assertPromptyStringField(t, reloaded.Inputs[2], "Name", "question", "Inputs[2].Name") + assertPromptyStringField(t, reloaded.Inputs[2], "Kind", "string", "Inputs[2].Kind") + assertPromptyStringField(t, reloaded.Inputs[2], "Default", "What is the meaning of life?", "Inputs[2].Default") + if len(reloaded.Outputs) != 1 { + t.Fatalf("Expected Outputs length to be 1, got %d", len(reloaded.Outputs)) + } + if reloaded.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, reloaded.Model.Id) + } + if reloaded.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, reloaded.Template.Format.Kind) + } + if reloaded.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, reloaded.Template.Parser.Kind) + } } // TestPromptyToYAML7 tests that ToYAML produces valid YAML @@ -3786,4 +6807,91 @@ func TestPromptyToYAML7(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadPrompty(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Name != "basic-prompt" { + t.Errorf(`Expected Name to be "basic-prompt", got %v`, reloaded.Name) + } + if reloaded.DisplayName == nil || *reloaded.DisplayName != "Basic Prompt" { + t.Errorf(`Expected DisplayName to be "Basic Prompt", got %v`, reloaded.DisplayName) + } + if reloaded.Description == nil || *reloaded.Description != "A basic prompt that uses the GPT-3 chat API to answer questions" { + t.Errorf(`Expected Description to be "A basic prompt that uses the GPT-3 chat API to answer questions", got %v`, reloaded.Description) + } + if reloaded.Instructions == nil || *reloaded.Instructions != "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}" { + t.Errorf(`Expected Instructions to be "system:\nYou are an AI assistant who helps people find information.\nAs the assistant, you answer questions briefly, succinctly,\nand in a personable manner using markdown and even add some \npersonal flair with appropriate emojis.\n\n# Customer\nYou are helping {{firstName}} {{lastName}} to find answers to \ntheir questions. Use their name to address them in your responses.\nuser:\n{{question}}", got %v`, reloaded.Instructions) + } + if reloaded.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if len(reloaded.Inputs) != 3 { + t.Fatalf("Expected Inputs length to be 3, got %d", len(reloaded.Inputs)) + } + assertPromptyStringField(t, reloaded.Inputs[0], "Name", "firstName", "Inputs[0].Name") + assertPromptyStringField(t, reloaded.Inputs[0], "Kind", "string", "Inputs[0].Kind") + assertPromptyStringField(t, reloaded.Inputs[0], "Default", "Jane", "Inputs[0].Default") + assertPromptyStringField(t, reloaded.Inputs[1], "Name", "lastName", "Inputs[1].Name") + assertPromptyStringField(t, reloaded.Inputs[1], "Kind", "string", "Inputs[1].Kind") + assertPromptyStringField(t, reloaded.Inputs[1], "Default", "Doe", "Inputs[1].Default") + assertPromptyStringField(t, reloaded.Inputs[2], "Name", "question", "Inputs[2].Name") + assertPromptyStringField(t, reloaded.Inputs[2], "Kind", "string", "Inputs[2].Kind") + assertPromptyStringField(t, reloaded.Inputs[2], "Default", "What is the meaning of life?", "Inputs[2].Default") + if len(reloaded.Outputs) != 1 { + t.Fatalf("Expected Outputs length to be 1, got %d", len(reloaded.Outputs)) + } + if reloaded.Model.Id != "gpt-35-turbo" { + t.Errorf(`Expected Model.Id to be "gpt-35-turbo", got %v`, reloaded.Model.Id) + } + if reloaded.Template.Format.Kind != "mustache" { + t.Errorf(`Expected Template.Format.Kind to be "mustache", got %v`, reloaded.Template.Format.Kind) + } + if reloaded.Template.Parser.Kind != "prompty" { + t.Errorf(`Expected Template.Parser.Kind to be "prompty", got %v`, reloaded.Template.Parser.Kind) + } +} + +// TestPromptyFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestPromptyFromJSONInvalid(t *testing.T) { + if _, err := prompty.PromptyFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } +} + +func assertPromptyStringField(t *testing.T, value interface{}, fieldName string, expected string, displayName string) { + t.Helper() + field := reflect.ValueOf(value) + if field.Kind() == reflect.Pointer { + if field.IsNil() { + t.Fatalf("Expected %s to be populated", displayName) + } + field = field.Elem() + } + if field.Kind() != reflect.Struct { + t.Fatalf("Expected %s receiver to be a struct, got %T", displayName, value) + } + member := field.FieldByName(fieldName) + if !member.IsValid() { + t.Fatalf("Expected %s to have field %s, got %T", displayName, fieldName, value) + } + if member.Kind() == reflect.Pointer { + if member.IsNil() { + t.Fatalf("Expected %s to be populated", displayName) + } + member = member.Elem() + } + if member.Kind() == reflect.Interface { + if member.IsNil() { + t.Fatalf("Expected %s to be populated", displayName) + } + member = member.Elem() + } + if member.Kind() != reflect.String { + t.Fatalf("Expected %s to be a string field, got %s", displayName, member.Kind()) + } + if got := member.String(); got != expected { + t.Errorf("Expected %s to be %q, got %q", displayName, expected, got) + } } diff --git a/runtime/go/prompty/model/prompty_tool_test.go b/runtime/go/prompty/model/prompty_tool_test.go index b36ba59d..719489be 100644 --- a/runtime/go/prompty/model/prompty_tool_test.go +++ b/runtime/go/prompty/model/prompty_tool_test.go @@ -71,6 +71,55 @@ mode: single } } +// TestPromptyToolFromJSON tests loading PromptyTool through the generated JSON helper +func TestPromptyToolFromJSON(t *testing.T) { + jsonData := ` +{ + "kind": "prompty", + "path": "./summarize.prompty", + "mode": "single" +} +` + + instance, err := prompty.PromptyToolFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load PromptyTool from JSON helper: %v", err) + } + if instance.Kind != "prompty" { + t.Errorf(`Expected Kind to be "prompty", got %v`, instance.Kind) + } + if instance.Path != "./summarize.prompty" { + t.Errorf(`Expected Path to be "./summarize.prompty", got %v`, instance.Path) + } + if instance.Mode != "single" { + t.Errorf(`Expected Mode to be "single", got %v`, instance.Mode) + } +} + +// TestPromptyToolFromYAML tests loading PromptyTool through the generated YAML helper +func TestPromptyToolFromYAML(t *testing.T) { + yamlData := ` +kind: prompty +path: ./summarize.prompty +mode: single + +` + + instance, err := prompty.PromptyToolFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load PromptyTool from YAML helper: %v", err) + } + if instance.Kind != "prompty" { + t.Errorf(`Expected Kind to be "prompty", got %v`, instance.Kind) + } + if instance.Path != "./summarize.prompty" { + t.Errorf(`Expected Path to be "./summarize.prompty", got %v`, instance.Path) + } + if instance.Mode != "single" { + t.Errorf(`Expected Mode to be "single", got %v`, instance.Mode) + } +} + // TestPromptyToolRoundtrip tests load -> save -> load produces equivalent data func TestPromptyToolRoundtrip(t *testing.T) { jsonData := ` @@ -136,6 +185,20 @@ func TestPromptyToolToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadPromptyTool(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Kind != "prompty" { + t.Errorf(`Expected Kind to be "prompty", got %v`, reloaded.Kind) + } + if reloaded.Path != "./summarize.prompty" { + t.Errorf(`Expected Path to be "./summarize.prompty", got %v`, reloaded.Path) + } + if reloaded.Mode != "single" { + t.Errorf(`Expected Mode to be "single", got %v`, reloaded.Mode) + } } // TestPromptyToolToYAML tests that ToYAML produces valid YAML @@ -166,4 +229,25 @@ func TestPromptyToolToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadPromptyTool(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Kind != "prompty" { + t.Errorf(`Expected Kind to be "prompty", got %v`, reloaded.Kind) + } + if reloaded.Path != "./summarize.prompty" { + t.Errorf(`Expected Path to be "./summarize.prompty", got %v`, reloaded.Path) + } + if reloaded.Mode != "single" { + t.Errorf(`Expected Mode to be "single", got %v`, reloaded.Mode) + } +} + +// TestPromptyToolFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestPromptyToolFromJSONInvalid(t *testing.T) { + if _, err := prompty.PromptyToolFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/property.go b/runtime/go/prompty/model/property.go index 14b7ce31..c6701621 100644 --- a/runtime/go/prompty/model/property.go +++ b/runtime/go/prompty/model/property.go @@ -85,7 +85,8 @@ func LoadProperty(data interface{}, ctx *LoadContext) (interface{}, error) { result.Example = &val } if val, ok := m["enumValues"]; ok && val != nil { - if arr, ok := val.([]interface{}); ok { + switch arr := val.(type) { + case []interface{}: result.EnumValues = arr } } @@ -95,7 +96,7 @@ func LoadProperty(data interface{}, ctx *LoadContext) (interface{}, error) { } // Save serializes Property to map[string]interface{} -func (obj *Property) Save(ctx *SaveContext) map[string]interface{} { +func (obj Property) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["name"] = obj.Name result["kind"] = obj.Kind @@ -131,11 +132,7 @@ func (obj *Property) ToJSON() (string, error) { func (obj *Property) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates Property from JSON string @@ -182,6 +179,9 @@ func LoadArrayProperty(data interface{}, ctx *LoadContext) (ArrayProperty, error loaded, _ := LoadProperty(m, ctx) // Polymorphic type - keep as interface{} result.Items = loaded + } else { + loaded, _ := LoadProperty(val, ctx) + result.Items = loaded } } } @@ -190,7 +190,7 @@ func LoadArrayProperty(data interface{}, ctx *LoadContext) (ArrayProperty, error } // Save serializes ArrayProperty to map[string]interface{} -func (obj *ArrayProperty) Save(ctx *SaveContext) map[string]interface{} { +func (obj ArrayProperty) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["kind"] = obj.Kind @@ -222,11 +222,7 @@ func (obj *ArrayProperty) ToJSON() (string, error) { func (obj *ArrayProperty) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates ArrayProperty from JSON string @@ -284,7 +280,7 @@ func LoadObjectProperty(data interface{}, ctx *LoadContext) (ObjectProperty, err } // Save serializes ObjectProperty to map[string]interface{} -func (obj *ObjectProperty) Save(ctx *SaveContext) map[string]interface{} { +func (obj ObjectProperty) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["kind"] = obj.Kind if obj.Properties != nil { @@ -321,11 +317,7 @@ func (obj *ObjectProperty) ToJSON() (string, error) { func (obj *ObjectProperty) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates ObjectProperty from JSON string diff --git a/runtime/go/prompty/model/property_test.go b/runtime/go/prompty/model/property_test.go index 945e4396..306569bd 100644 --- a/runtime/go/prompty/model/property_test.go +++ b/runtime/go/prompty/model/property_test.go @@ -74,6 +74,58 @@ enumValues: // Note: Validation skipped for polymorphic base types - test child types directly } +// TestPropertyFromJSON tests loading Property through the generated JSON helper +func TestPropertyFromJSON(t *testing.T) { + jsonData := ` +{ + "name": "my-input", + "kind": "string", + "description": "A description of the input property", + "required": true, + "default": "default value", + "example": "example value", + "enumValues": [ + "value1", + "value2", + "value3" + ] +} +` + + instance, err := prompty.PropertyFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load Property from JSON helper: %v", err) + } + // Polymorphic types return interface{}, extract common fields via reflection or type-specific access + _ = instance // Load succeeded, exact type depends on discriminator + // Note: Validation skipped for polymorphic base types - test child types directly +} + +// TestPropertyFromYAML tests loading Property through the generated YAML helper +func TestPropertyFromYAML(t *testing.T) { + yamlData := ` +name: my-input +kind: string +description: A description of the input property +required: true +default: default value +example: example value +enumValues: + - value1 + - value2 + - value3 + +` + + instance, err := prompty.PropertyFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load Property from YAML helper: %v", err) + } + // Polymorphic types return interface{}, extract common fields via reflection or type-specific access + _ = instance // Load succeeded, exact type depends on discriminator + // Note: Validation skipped for polymorphic base types - test child types directly +} + // TestPropertyRoundtrip tests load -> save -> load produces equivalent data func TestPropertyRoundtrip(t *testing.T) { jsonData := ` @@ -170,6 +222,13 @@ func TestPropertyToYAML(t *testing.T) { // Note: ToYAML test skipped for polymorphic base types - test child types directly } +// TestPropertyFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestPropertyFromJSONInvalid(t *testing.T) { + if _, err := prompty.PropertyFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } +} + // TestPropertyFromInput tests loading Property from bool func TestPropertyFromInput(t *testing.T) { ctx := prompty.NewLoadContext() diff --git a/runtime/go/prompty/model/redacted_field.go b/runtime/go/prompty/model/redacted_field.go index 70d63939..1c2821a0 100644 --- a/runtime/go/prompty/model/redacted_field.go +++ b/runtime/go/prompty/model/redacted_field.go @@ -51,7 +51,7 @@ func LoadRedactedField(data interface{}, ctx *LoadContext) (RedactedField, error } // Save serializes RedactedField to map[string]interface{} -func (obj *RedactedField) Save(ctx *SaveContext) map[string]interface{} { +func (obj RedactedField) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["path"] = obj.Path result["mode"] = string(obj.Mode) @@ -77,11 +77,7 @@ func (obj *RedactedField) ToJSON() (string, error) { func (obj *RedactedField) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates RedactedField from JSON string diff --git a/runtime/go/prompty/model/redacted_field_test.go b/runtime/go/prompty/model/redacted_field_test.go index bacb98cd..e628566b 100644 --- a/runtime/go/prompty/model/redacted_field_test.go +++ b/runtime/go/prompty/model/redacted_field_test.go @@ -71,6 +71,55 @@ reason: secret } } +// TestRedactedFieldFromJSON tests loading RedactedField through the generated JSON helper +func TestRedactedFieldFromJSON(t *testing.T) { + jsonData := ` +{ + "path": "$.arguments.apiKey", + "mode": "redacted", + "reason": "secret" +} +` + + instance, err := prompty.RedactedFieldFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load RedactedField from JSON helper: %v", err) + } + if instance.Path != "$.arguments.apiKey" { + t.Errorf(`Expected Path to be "$.arguments.apiKey", got %v`, instance.Path) + } + if instance.Mode != "redacted" { + t.Errorf(`Expected Mode to be "redacted", got %v`, instance.Mode) + } + if instance.Reason == nil || *instance.Reason != "secret" { + t.Errorf(`Expected Reason to be "secret", got %v`, instance.Reason) + } +} + +// TestRedactedFieldFromYAML tests loading RedactedField through the generated YAML helper +func TestRedactedFieldFromYAML(t *testing.T) { + yamlData := ` +path: $.arguments.apiKey +mode: redacted +reason: secret + +` + + instance, err := prompty.RedactedFieldFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load RedactedField from YAML helper: %v", err) + } + if instance.Path != "$.arguments.apiKey" { + t.Errorf(`Expected Path to be "$.arguments.apiKey", got %v`, instance.Path) + } + if instance.Mode != "redacted" { + t.Errorf(`Expected Mode to be "redacted", got %v`, instance.Mode) + } + if instance.Reason == nil || *instance.Reason != "secret" { + t.Errorf(`Expected Reason to be "secret", got %v`, instance.Reason) + } +} + // TestRedactedFieldRoundtrip tests load -> save -> load produces equivalent data func TestRedactedFieldRoundtrip(t *testing.T) { jsonData := ` @@ -136,6 +185,20 @@ func TestRedactedFieldToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadRedactedField(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Path != "$.arguments.apiKey" { + t.Errorf(`Expected Path to be "$.arguments.apiKey", got %v`, reloaded.Path) + } + if reloaded.Mode != "redacted" { + t.Errorf(`Expected Mode to be "redacted", got %v`, reloaded.Mode) + } + if reloaded.Reason == nil || *reloaded.Reason != "secret" { + t.Errorf(`Expected Reason to be "secret", got %v`, reloaded.Reason) + } } // TestRedactedFieldToYAML tests that ToYAML produces valid YAML @@ -166,4 +229,25 @@ func TestRedactedFieldToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadRedactedField(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Path != "$.arguments.apiKey" { + t.Errorf(`Expected Path to be "$.arguments.apiKey", got %v`, reloaded.Path) + } + if reloaded.Mode != "redacted" { + t.Errorf(`Expected Mode to be "redacted", got %v`, reloaded.Mode) + } + if reloaded.Reason == nil || *reloaded.Reason != "secret" { + t.Errorf(`Expected Reason to be "secret", got %v`, reloaded.Reason) + } +} + +// TestRedactedFieldFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestRedactedFieldFromJSONInvalid(t *testing.T) { + if _, err := prompty.RedactedFieldFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/redaction_metadata.go b/runtime/go/prompty/model/redaction_metadata.go index 36218637..c4fb9da4 100644 --- a/runtime/go/prompty/model/redaction_metadata.go +++ b/runtime/go/prompty/model/redaction_metadata.go @@ -49,7 +49,7 @@ func LoadRedactionMetadata(data interface{}, ctx *LoadContext) (RedactionMetadat } // Save serializes RedactionMetadata to map[string]interface{} -func (obj *RedactionMetadata) Save(ctx *SaveContext) map[string]interface{} { +func (obj RedactionMetadata) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) if obj.Sanitized != nil { result["sanitized"] = *obj.Sanitized @@ -83,11 +83,7 @@ func (obj *RedactionMetadata) ToJSON() (string, error) { func (obj *RedactionMetadata) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates RedactionMetadata from JSON string diff --git a/runtime/go/prompty/model/redaction_metadata_test.go b/runtime/go/prompty/model/redaction_metadata_test.go index e12ea0d4..d09d5c7d 100644 --- a/runtime/go/prompty/model/redaction_metadata_test.go +++ b/runtime/go/prompty/model/redaction_metadata_test.go @@ -63,6 +63,47 @@ policy: default-v1 } } +// TestRedactionMetadataFromJSON tests loading RedactionMetadata through the generated JSON helper +func TestRedactionMetadataFromJSON(t *testing.T) { + jsonData := ` +{ + "sanitized": true, + "policy": "default-v1" +} +` + + instance, err := prompty.RedactionMetadataFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load RedactionMetadata from JSON helper: %v", err) + } + if instance.Sanitized == nil || *instance.Sanitized != true { + t.Errorf(`Expected Sanitized to be true, got %v`, instance.Sanitized) + } + if instance.Policy == nil || *instance.Policy != "default-v1" { + t.Errorf(`Expected Policy to be "default-v1", got %v`, instance.Policy) + } +} + +// TestRedactionMetadataFromYAML tests loading RedactionMetadata through the generated YAML helper +func TestRedactionMetadataFromYAML(t *testing.T) { + yamlData := ` +sanitized: true +policy: default-v1 + +` + + instance, err := prompty.RedactionMetadataFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load RedactionMetadata from YAML helper: %v", err) + } + if instance.Sanitized == nil || *instance.Sanitized != true { + t.Errorf(`Expected Sanitized to be true, got %v`, instance.Sanitized) + } + if instance.Policy == nil || *instance.Policy != "default-v1" { + t.Errorf(`Expected Policy to be "default-v1", got %v`, instance.Policy) + } +} + // TestRedactionMetadataRoundtrip tests load -> save -> load produces equivalent data func TestRedactionMetadataRoundtrip(t *testing.T) { jsonData := ` @@ -123,6 +164,17 @@ func TestRedactionMetadataToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadRedactionMetadata(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Sanitized == nil || *reloaded.Sanitized != true { + t.Errorf(`Expected Sanitized to be true, got %v`, reloaded.Sanitized) + } + if reloaded.Policy == nil || *reloaded.Policy != "default-v1" { + t.Errorf(`Expected Policy to be "default-v1", got %v`, reloaded.Policy) + } } // TestRedactionMetadataToYAML tests that ToYAML produces valid YAML @@ -152,4 +204,22 @@ func TestRedactionMetadataToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadRedactionMetadata(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Sanitized == nil || *reloaded.Sanitized != true { + t.Errorf(`Expected Sanitized to be true, got %v`, reloaded.Sanitized) + } + if reloaded.Policy == nil || *reloaded.Policy != "default-v1" { + t.Errorf(`Expected Policy to be "default-v1", got %v`, reloaded.Policy) + } +} + +// TestRedactionMetadataFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestRedactionMetadataFromJSONInvalid(t *testing.T) { + if _, err := prompty.RedactionMetadataFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/reference_connection_test.go b/runtime/go/prompty/model/reference_connection_test.go index f4ab381d..0e3ff071 100644 --- a/runtime/go/prompty/model/reference_connection_test.go +++ b/runtime/go/prompty/model/reference_connection_test.go @@ -71,6 +71,55 @@ target: my-target-resource } } +// TestReferenceConnectionFromJSON tests loading ReferenceConnection through the generated JSON helper +func TestReferenceConnectionFromJSON(t *testing.T) { + jsonData := ` +{ + "kind": "reference", + "name": "my-reference-connection", + "target": "my-target-resource" +} +` + + instance, err := prompty.ReferenceConnectionFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load ReferenceConnection from JSON helper: %v", err) + } + if instance.Kind != "reference" { + t.Errorf(`Expected Kind to be "reference", got %v`, instance.Kind) + } + if instance.Name != "my-reference-connection" { + t.Errorf(`Expected Name to be "my-reference-connection", got %v`, instance.Name) + } + if instance.Target == nil || *instance.Target != "my-target-resource" { + t.Errorf(`Expected Target to be "my-target-resource", got %v`, instance.Target) + } +} + +// TestReferenceConnectionFromYAML tests loading ReferenceConnection through the generated YAML helper +func TestReferenceConnectionFromYAML(t *testing.T) { + yamlData := ` +kind: reference +name: my-reference-connection +target: my-target-resource + +` + + instance, err := prompty.ReferenceConnectionFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load ReferenceConnection from YAML helper: %v", err) + } + if instance.Kind != "reference" { + t.Errorf(`Expected Kind to be "reference", got %v`, instance.Kind) + } + if instance.Name != "my-reference-connection" { + t.Errorf(`Expected Name to be "my-reference-connection", got %v`, instance.Name) + } + if instance.Target == nil || *instance.Target != "my-target-resource" { + t.Errorf(`Expected Target to be "my-target-resource", got %v`, instance.Target) + } +} + // TestReferenceConnectionRoundtrip tests load -> save -> load produces equivalent data func TestReferenceConnectionRoundtrip(t *testing.T) { jsonData := ` @@ -136,6 +185,20 @@ func TestReferenceConnectionToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadReferenceConnection(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Kind != "reference" { + t.Errorf(`Expected Kind to be "reference", got %v`, reloaded.Kind) + } + if reloaded.Name != "my-reference-connection" { + t.Errorf(`Expected Name to be "my-reference-connection", got %v`, reloaded.Name) + } + if reloaded.Target == nil || *reloaded.Target != "my-target-resource" { + t.Errorf(`Expected Target to be "my-target-resource", got %v`, reloaded.Target) + } } // TestReferenceConnectionToYAML tests that ToYAML produces valid YAML @@ -166,4 +229,25 @@ func TestReferenceConnectionToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadReferenceConnection(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Kind != "reference" { + t.Errorf(`Expected Kind to be "reference", got %v`, reloaded.Kind) + } + if reloaded.Name != "my-reference-connection" { + t.Errorf(`Expected Name to be "my-reference-connection", got %v`, reloaded.Name) + } + if reloaded.Target == nil || *reloaded.Target != "my-target-resource" { + t.Errorf(`Expected Target to be "my-target-resource", got %v`, reloaded.Target) + } +} + +// TestReferenceConnectionFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestReferenceConnectionFromJSONInvalid(t *testing.T) { + if _, err := prompty.ReferenceConnectionFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/remote_connection_test.go b/runtime/go/prompty/model/remote_connection_test.go index 6ce6b6ec..2cb55b1c 100644 --- a/runtime/go/prompty/model/remote_connection_test.go +++ b/runtime/go/prompty/model/remote_connection_test.go @@ -71,6 +71,55 @@ endpoint: "https://{your-custom-endpoint}.openai.azure.com/" } } +// TestRemoteConnectionFromJSON tests loading RemoteConnection through the generated JSON helper +func TestRemoteConnectionFromJSON(t *testing.T) { + jsonData := ` +{ + "kind": "remote", + "name": "my-reference-connection", + "endpoint": "https://{your-custom-endpoint}.openai.azure.com/" +} +` + + instance, err := prompty.RemoteConnectionFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load RemoteConnection from JSON helper: %v", err) + } + if instance.Kind != "remote" { + t.Errorf(`Expected Kind to be "remote", got %v`, instance.Kind) + } + if instance.Name != "my-reference-connection" { + t.Errorf(`Expected Name to be "my-reference-connection", got %v`, instance.Name) + } + if instance.Endpoint != "https://{your-custom-endpoint}.openai.azure.com/" { + t.Errorf(`Expected Endpoint to be "https://{your-custom-endpoint}.openai.azure.com/", got %v`, instance.Endpoint) + } +} + +// TestRemoteConnectionFromYAML tests loading RemoteConnection through the generated YAML helper +func TestRemoteConnectionFromYAML(t *testing.T) { + yamlData := ` +kind: remote +name: my-reference-connection +endpoint: "https://{your-custom-endpoint}.openai.azure.com/" + +` + + instance, err := prompty.RemoteConnectionFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load RemoteConnection from YAML helper: %v", err) + } + if instance.Kind != "remote" { + t.Errorf(`Expected Kind to be "remote", got %v`, instance.Kind) + } + if instance.Name != "my-reference-connection" { + t.Errorf(`Expected Name to be "my-reference-connection", got %v`, instance.Name) + } + if instance.Endpoint != "https://{your-custom-endpoint}.openai.azure.com/" { + t.Errorf(`Expected Endpoint to be "https://{your-custom-endpoint}.openai.azure.com/", got %v`, instance.Endpoint) + } +} + // TestRemoteConnectionRoundtrip tests load -> save -> load produces equivalent data func TestRemoteConnectionRoundtrip(t *testing.T) { jsonData := ` @@ -136,6 +185,20 @@ func TestRemoteConnectionToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadRemoteConnection(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Kind != "remote" { + t.Errorf(`Expected Kind to be "remote", got %v`, reloaded.Kind) + } + if reloaded.Name != "my-reference-connection" { + t.Errorf(`Expected Name to be "my-reference-connection", got %v`, reloaded.Name) + } + if reloaded.Endpoint != "https://{your-custom-endpoint}.openai.azure.com/" { + t.Errorf(`Expected Endpoint to be "https://{your-custom-endpoint}.openai.azure.com/", got %v`, reloaded.Endpoint) + } } // TestRemoteConnectionToYAML tests that ToYAML produces valid YAML @@ -166,4 +229,25 @@ func TestRemoteConnectionToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadRemoteConnection(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Kind != "remote" { + t.Errorf(`Expected Kind to be "remote", got %v`, reloaded.Kind) + } + if reloaded.Name != "my-reference-connection" { + t.Errorf(`Expected Name to be "my-reference-connection", got %v`, reloaded.Name) + } + if reloaded.Endpoint != "https://{your-custom-endpoint}.openai.azure.com/" { + t.Errorf(`Expected Endpoint to be "https://{your-custom-endpoint}.openai.azure.com/", got %v`, reloaded.Endpoint) + } +} + +// TestRemoteConnectionFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestRemoteConnectionFromJSONInvalid(t *testing.T) { + if _, err := prompty.RemoteConnectionFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/retry_payload.go b/runtime/go/prompty/model/retry_payload.go index f1057fb5..f87b974e 100644 --- a/runtime/go/prompty/model/retry_payload.go +++ b/runtime/go/prompty/model/retry_payload.go @@ -83,7 +83,7 @@ func LoadRetryPayload(data interface{}, ctx *LoadContext) (RetryPayload, error) } // Save serializes RetryPayload to map[string]interface{} -func (obj *RetryPayload) Save(ctx *SaveContext) map[string]interface{} { +func (obj RetryPayload) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["operation"] = obj.Operation result["attempt"] = obj.Attempt @@ -115,11 +115,7 @@ func (obj *RetryPayload) ToJSON() (string, error) { func (obj *RetryPayload) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates RetryPayload from JSON string diff --git a/runtime/go/prompty/model/retry_payload_test.go b/runtime/go/prompty/model/retry_payload_test.go index 19113bc6..c652d28d 100644 --- a/runtime/go/prompty/model/retry_payload_test.go +++ b/runtime/go/prompty/model/retry_payload_test.go @@ -87,6 +87,71 @@ reason: rate_limit } } +// TestRetryPayloadFromJSON tests loading RetryPayload through the generated JSON helper +func TestRetryPayloadFromJSON(t *testing.T) { + jsonData := ` +{ + "operation": "llm", + "attempt": 2, + "maxAttempts": 3, + "delayMs": 1250, + "reason": "rate_limit" +} +` + + instance, err := prompty.RetryPayloadFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load RetryPayload from JSON helper: %v", err) + } + if instance.Operation != "llm" { + t.Errorf(`Expected Operation to be "llm", got %v`, instance.Operation) + } + if instance.Attempt != 2 { + t.Errorf(`Expected Attempt to be 2, got %v`, instance.Attempt) + } + if instance.MaxAttempts == nil || *instance.MaxAttempts != 3 { + t.Errorf(`Expected MaxAttempts to be 3, got %v`, instance.MaxAttempts) + } + if instance.DelayMs == nil || *instance.DelayMs != 1250 { + t.Errorf(`Expected DelayMs to be 1250, got %v`, instance.DelayMs) + } + if instance.Reason == nil || *instance.Reason != "rate_limit" { + t.Errorf(`Expected Reason to be "rate_limit", got %v`, instance.Reason) + } +} + +// TestRetryPayloadFromYAML tests loading RetryPayload through the generated YAML helper +func TestRetryPayloadFromYAML(t *testing.T) { + yamlData := ` +operation: llm +attempt: 2 +maxAttempts: 3 +delayMs: 1250 +reason: rate_limit + +` + + instance, err := prompty.RetryPayloadFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load RetryPayload from YAML helper: %v", err) + } + if instance.Operation != "llm" { + t.Errorf(`Expected Operation to be "llm", got %v`, instance.Operation) + } + if instance.Attempt != 2 { + t.Errorf(`Expected Attempt to be 2, got %v`, instance.Attempt) + } + if instance.MaxAttempts == nil || *instance.MaxAttempts != 3 { + t.Errorf(`Expected MaxAttempts to be 3, got %v`, instance.MaxAttempts) + } + if instance.DelayMs == nil || *instance.DelayMs != 1250 { + t.Errorf(`Expected DelayMs to be 1250, got %v`, instance.DelayMs) + } + if instance.Reason == nil || *instance.Reason != "rate_limit" { + t.Errorf(`Expected Reason to be "rate_limit", got %v`, instance.Reason) + } +} + // TestRetryPayloadRoundtrip tests load -> save -> load produces equivalent data func TestRetryPayloadRoundtrip(t *testing.T) { jsonData := ` @@ -162,6 +227,26 @@ func TestRetryPayloadToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadRetryPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Operation != "llm" { + t.Errorf(`Expected Operation to be "llm", got %v`, reloaded.Operation) + } + if reloaded.Attempt != 2 { + t.Errorf(`Expected Attempt to be 2, got %v`, reloaded.Attempt) + } + if reloaded.MaxAttempts == nil || *reloaded.MaxAttempts != 3 { + t.Errorf(`Expected MaxAttempts to be 3, got %v`, reloaded.MaxAttempts) + } + if reloaded.DelayMs == nil || *reloaded.DelayMs != 1250 { + t.Errorf(`Expected DelayMs to be 1250, got %v`, reloaded.DelayMs) + } + if reloaded.Reason == nil || *reloaded.Reason != "rate_limit" { + t.Errorf(`Expected Reason to be "rate_limit", got %v`, reloaded.Reason) + } } // TestRetryPayloadToYAML tests that ToYAML produces valid YAML @@ -194,4 +279,31 @@ func TestRetryPayloadToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadRetryPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Operation != "llm" { + t.Errorf(`Expected Operation to be "llm", got %v`, reloaded.Operation) + } + if reloaded.Attempt != 2 { + t.Errorf(`Expected Attempt to be 2, got %v`, reloaded.Attempt) + } + if reloaded.MaxAttempts == nil || *reloaded.MaxAttempts != 3 { + t.Errorf(`Expected MaxAttempts to be 3, got %v`, reloaded.MaxAttempts) + } + if reloaded.DelayMs == nil || *reloaded.DelayMs != 1250 { + t.Errorf(`Expected DelayMs to be 1250, got %v`, reloaded.DelayMs) + } + if reloaded.Reason == nil || *reloaded.Reason != "rate_limit" { + t.Errorf(`Expected Reason to be "rate_limit", got %v`, reloaded.Reason) + } +} + +// TestRetryPayloadFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestRetryPayloadFromJSONInvalid(t *testing.T) { + if _, err := prompty.RetryPayloadFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/session_end_payload.go b/runtime/go/prompty/model/session_end_payload.go index be968217..76599b37 100644 --- a/runtime/go/prompty/model/session_end_payload.go +++ b/runtime/go/prompty/model/session_end_payload.go @@ -69,7 +69,7 @@ func LoadSessionEndPayload(data interface{}, ctx *LoadContext) (SessionEndPayloa } // Save serializes SessionEndPayload to map[string]interface{} -func (obj *SessionEndPayload) Save(ctx *SaveContext) map[string]interface{} { +func (obj SessionEndPayload) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) if obj.SessionId != nil { result["sessionId"] = *obj.SessionId @@ -102,11 +102,7 @@ func (obj *SessionEndPayload) ToJSON() (string, error) { func (obj *SessionEndPayload) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates SessionEndPayload from JSON string diff --git a/runtime/go/prompty/model/session_end_payload_test.go b/runtime/go/prompty/model/session_end_payload_test.go index 263986c2..076e371c 100644 --- a/runtime/go/prompty/model/session_end_payload_test.go +++ b/runtime/go/prompty/model/session_end_payload_test.go @@ -79,6 +79,63 @@ durationMs: 12500 } } +// TestSessionEndPayloadFromJSON tests loading SessionEndPayload through the generated JSON helper +func TestSessionEndPayloadFromJSON(t *testing.T) { + jsonData := ` +{ + "sessionId": "sess_abc123", + "status": "success", + "reason": "complete", + "durationMs": 12500 +} +` + + instance, err := prompty.SessionEndPayloadFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load SessionEndPayload from JSON helper: %v", err) + } + if instance.SessionId == nil || *instance.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, instance.SessionId) + } + if instance.Status == nil || *instance.Status != "success" { + t.Errorf(`Expected Status to be "success", got %v`, instance.Status) + } + if instance.Reason == nil || *instance.Reason != "complete" { + t.Errorf(`Expected Reason to be "complete", got %v`, instance.Reason) + } + if instance.DurationMs == nil || *instance.DurationMs != 12500 { + t.Errorf(`Expected DurationMs to be 12500, got %v`, instance.DurationMs) + } +} + +// TestSessionEndPayloadFromYAML tests loading SessionEndPayload through the generated YAML helper +func TestSessionEndPayloadFromYAML(t *testing.T) { + yamlData := ` +sessionId: sess_abc123 +status: success +reason: complete +durationMs: 12500 + +` + + instance, err := prompty.SessionEndPayloadFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load SessionEndPayload from YAML helper: %v", err) + } + if instance.SessionId == nil || *instance.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, instance.SessionId) + } + if instance.Status == nil || *instance.Status != "success" { + t.Errorf(`Expected Status to be "success", got %v`, instance.Status) + } + if instance.Reason == nil || *instance.Reason != "complete" { + t.Errorf(`Expected Reason to be "complete", got %v`, instance.Reason) + } + if instance.DurationMs == nil || *instance.DurationMs != 12500 { + t.Errorf(`Expected DurationMs to be 12500, got %v`, instance.DurationMs) + } +} + // TestSessionEndPayloadRoundtrip tests load -> save -> load produces equivalent data func TestSessionEndPayloadRoundtrip(t *testing.T) { jsonData := ` @@ -149,6 +206,23 @@ func TestSessionEndPayloadToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadSessionEndPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.SessionId == nil || *reloaded.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, reloaded.SessionId) + } + if reloaded.Status == nil || *reloaded.Status != "success" { + t.Errorf(`Expected Status to be "success", got %v`, reloaded.Status) + } + if reloaded.Reason == nil || *reloaded.Reason != "complete" { + t.Errorf(`Expected Reason to be "complete", got %v`, reloaded.Reason) + } + if reloaded.DurationMs == nil || *reloaded.DurationMs != 12500 { + t.Errorf(`Expected DurationMs to be 12500, got %v`, reloaded.DurationMs) + } } // TestSessionEndPayloadToYAML tests that ToYAML produces valid YAML @@ -180,4 +254,28 @@ func TestSessionEndPayloadToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadSessionEndPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.SessionId == nil || *reloaded.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, reloaded.SessionId) + } + if reloaded.Status == nil || *reloaded.Status != "success" { + t.Errorf(`Expected Status to be "success", got %v`, reloaded.Status) + } + if reloaded.Reason == nil || *reloaded.Reason != "complete" { + t.Errorf(`Expected Reason to be "complete", got %v`, reloaded.Reason) + } + if reloaded.DurationMs == nil || *reloaded.DurationMs != 12500 { + t.Errorf(`Expected DurationMs to be 12500, got %v`, reloaded.DurationMs) + } +} + +// TestSessionEndPayloadFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestSessionEndPayloadFromJSONInvalid(t *testing.T) { + if _, err := prompty.SessionEndPayloadFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/session_event.go b/runtime/go/prompty/model/session_event.go index 2b2081c2..adb21111 100644 --- a/runtime/go/prompty/model/session_event.go +++ b/runtime/go/prompty/model/session_event.go @@ -85,7 +85,7 @@ func LoadSessionEvent(data interface{}, ctx *LoadContext) (SessionEvent, error) } // Save serializes SessionEvent to map[string]interface{} -func (obj *SessionEvent) Save(ctx *SaveContext) map[string]interface{} { +func (obj SessionEvent) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["id"] = obj.Id result["type"] = string(obj.Type) @@ -125,11 +125,7 @@ func (obj *SessionEvent) ToJSON() (string, error) { func (obj *SessionEvent) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates SessionEvent from JSON string diff --git a/runtime/go/prompty/model/session_event_test.go b/runtime/go/prompty/model/session_event_test.go index 2fbf5270..c253e9d4 100644 --- a/runtime/go/prompty/model/session_event_test.go +++ b/runtime/go/prompty/model/session_event_test.go @@ -95,6 +95,79 @@ spanId: span_hook_001 } } +// TestSessionEventFromJSON tests loading SessionEvent through the generated JSON helper +func TestSessionEventFromJSON(t *testing.T) { + jsonData := ` +{ + "id": "evt_abc123", + "timestamp": "2026-06-09T20:00:00Z", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "parentId": "evt_parent", + "spanId": "span_hook_001" +} +` + + instance, err := prompty.SessionEventFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load SessionEvent from JSON helper: %v", err) + } + if instance.Id != "evt_abc123" { + t.Errorf(`Expected Id to be "evt_abc123", got %v`, instance.Id) + } + if instance.Timestamp != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected Timestamp to be "2026-06-09T20:00:00Z", got %v`, instance.Timestamp) + } + if instance.SessionId == nil || *instance.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, instance.SessionId) + } + if instance.TurnId == nil || *instance.TurnId != "turn_001" { + t.Errorf(`Expected TurnId to be "turn_001", got %v`, instance.TurnId) + } + if instance.ParentId == nil || *instance.ParentId != "evt_parent" { + t.Errorf(`Expected ParentId to be "evt_parent", got %v`, instance.ParentId) + } + if instance.SpanId == nil || *instance.SpanId != "span_hook_001" { + t.Errorf(`Expected SpanId to be "span_hook_001", got %v`, instance.SpanId) + } +} + +// TestSessionEventFromYAML tests loading SessionEvent through the generated YAML helper +func TestSessionEventFromYAML(t *testing.T) { + yamlData := ` +id: evt_abc123 +timestamp: "2026-06-09T20:00:00Z" +sessionId: sess_abc123 +turnId: turn_001 +parentId: evt_parent +spanId: span_hook_001 + +` + + instance, err := prompty.SessionEventFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load SessionEvent from YAML helper: %v", err) + } + if instance.Id != "evt_abc123" { + t.Errorf(`Expected Id to be "evt_abc123", got %v`, instance.Id) + } + if instance.Timestamp != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected Timestamp to be "2026-06-09T20:00:00Z", got %v`, instance.Timestamp) + } + if instance.SessionId == nil || *instance.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, instance.SessionId) + } + if instance.TurnId == nil || *instance.TurnId != "turn_001" { + t.Errorf(`Expected TurnId to be "turn_001", got %v`, instance.TurnId) + } + if instance.ParentId == nil || *instance.ParentId != "evt_parent" { + t.Errorf(`Expected ParentId to be "evt_parent", got %v`, instance.ParentId) + } + if instance.SpanId == nil || *instance.SpanId != "span_hook_001" { + t.Errorf(`Expected SpanId to be "span_hook_001", got %v`, instance.SpanId) + } +} + // TestSessionEventRoundtrip tests load -> save -> load produces equivalent data func TestSessionEventRoundtrip(t *testing.T) { jsonData := ` @@ -175,6 +248,29 @@ func TestSessionEventToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadSessionEvent(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Id != "evt_abc123" { + t.Errorf(`Expected Id to be "evt_abc123", got %v`, reloaded.Id) + } + if reloaded.Timestamp != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected Timestamp to be "2026-06-09T20:00:00Z", got %v`, reloaded.Timestamp) + } + if reloaded.SessionId == nil || *reloaded.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, reloaded.SessionId) + } + if reloaded.TurnId == nil || *reloaded.TurnId != "turn_001" { + t.Errorf(`Expected TurnId to be "turn_001", got %v`, reloaded.TurnId) + } + if reloaded.ParentId == nil || *reloaded.ParentId != "evt_parent" { + t.Errorf(`Expected ParentId to be "evt_parent", got %v`, reloaded.ParentId) + } + if reloaded.SpanId == nil || *reloaded.SpanId != "span_hook_001" { + t.Errorf(`Expected SpanId to be "span_hook_001", got %v`, reloaded.SpanId) + } } // TestSessionEventToYAML tests that ToYAML produces valid YAML @@ -208,4 +304,34 @@ func TestSessionEventToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadSessionEvent(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Id != "evt_abc123" { + t.Errorf(`Expected Id to be "evt_abc123", got %v`, reloaded.Id) + } + if reloaded.Timestamp != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected Timestamp to be "2026-06-09T20:00:00Z", got %v`, reloaded.Timestamp) + } + if reloaded.SessionId == nil || *reloaded.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, reloaded.SessionId) + } + if reloaded.TurnId == nil || *reloaded.TurnId != "turn_001" { + t.Errorf(`Expected TurnId to be "turn_001", got %v`, reloaded.TurnId) + } + if reloaded.ParentId == nil || *reloaded.ParentId != "evt_parent" { + t.Errorf(`Expected ParentId to be "evt_parent", got %v`, reloaded.ParentId) + } + if reloaded.SpanId == nil || *reloaded.SpanId != "span_hook_001" { + t.Errorf(`Expected SpanId to be "span_hook_001", got %v`, reloaded.SpanId) + } +} + +// TestSessionEventFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestSessionEventFromJSONInvalid(t *testing.T) { + if _, err := prompty.SessionEventFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/session_file_ref.go b/runtime/go/prompty/model/session_file_ref.go index e6e4df6a..d120057c 100644 --- a/runtime/go/prompty/model/session_file_ref.go +++ b/runtime/go/prompty/model/session_file_ref.go @@ -61,7 +61,7 @@ func LoadSessionFileRef(data interface{}, ctx *LoadContext) (SessionFileRef, err } // Save serializes SessionFileRef to map[string]interface{} -func (obj *SessionFileRef) Save(ctx *SaveContext) map[string]interface{} { +func (obj SessionFileRef) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) if obj.SessionId != nil { result["sessionId"] = *obj.SessionId @@ -95,11 +95,7 @@ func (obj *SessionFileRef) ToJSON() (string, error) { func (obj *SessionFileRef) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates SessionFileRef from JSON string diff --git a/runtime/go/prompty/model/session_file_ref_test.go b/runtime/go/prompty/model/session_file_ref_test.go index 187663a9..3a1d0c51 100644 --- a/runtime/go/prompty/model/session_file_ref_test.go +++ b/runtime/go/prompty/model/session_file_ref_test.go @@ -87,6 +87,71 @@ firstSeenAt: "2026-06-09T20:00:00Z" } } +// TestSessionFileRefFromJSON tests loading SessionFileRef through the generated JSON helper +func TestSessionFileRefFromJSON(t *testing.T) { + jsonData := ` +{ + "sessionId": "sess_abc123", + "path": "src/index.ts", + "toolName": "view", + "turnIndex": 2, + "firstSeenAt": "2026-06-09T20:00:00Z" +} +` + + instance, err := prompty.SessionFileRefFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load SessionFileRef from JSON helper: %v", err) + } + if instance.SessionId == nil || *instance.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, instance.SessionId) + } + if instance.Path != "src/index.ts" { + t.Errorf(`Expected Path to be "src/index.ts", got %v`, instance.Path) + } + if instance.ToolName == nil || *instance.ToolName != "view" { + t.Errorf(`Expected ToolName to be "view", got %v`, instance.ToolName) + } + if instance.TurnIndex == nil || *instance.TurnIndex != 2 { + t.Errorf(`Expected TurnIndex to be 2, got %v`, instance.TurnIndex) + } + if instance.FirstSeenAt == nil || *instance.FirstSeenAt != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected FirstSeenAt to be "2026-06-09T20:00:00Z", got %v`, instance.FirstSeenAt) + } +} + +// TestSessionFileRefFromYAML tests loading SessionFileRef through the generated YAML helper +func TestSessionFileRefFromYAML(t *testing.T) { + yamlData := ` +sessionId: sess_abc123 +path: src/index.ts +toolName: view +turnIndex: 2 +firstSeenAt: "2026-06-09T20:00:00Z" + +` + + instance, err := prompty.SessionFileRefFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load SessionFileRef from YAML helper: %v", err) + } + if instance.SessionId == nil || *instance.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, instance.SessionId) + } + if instance.Path != "src/index.ts" { + t.Errorf(`Expected Path to be "src/index.ts", got %v`, instance.Path) + } + if instance.ToolName == nil || *instance.ToolName != "view" { + t.Errorf(`Expected ToolName to be "view", got %v`, instance.ToolName) + } + if instance.TurnIndex == nil || *instance.TurnIndex != 2 { + t.Errorf(`Expected TurnIndex to be 2, got %v`, instance.TurnIndex) + } + if instance.FirstSeenAt == nil || *instance.FirstSeenAt != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected FirstSeenAt to be "2026-06-09T20:00:00Z", got %v`, instance.FirstSeenAt) + } +} + // TestSessionFileRefRoundtrip tests load -> save -> load produces equivalent data func TestSessionFileRefRoundtrip(t *testing.T) { jsonData := ` @@ -162,6 +227,26 @@ func TestSessionFileRefToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadSessionFileRef(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.SessionId == nil || *reloaded.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, reloaded.SessionId) + } + if reloaded.Path != "src/index.ts" { + t.Errorf(`Expected Path to be "src/index.ts", got %v`, reloaded.Path) + } + if reloaded.ToolName == nil || *reloaded.ToolName != "view" { + t.Errorf(`Expected ToolName to be "view", got %v`, reloaded.ToolName) + } + if reloaded.TurnIndex == nil || *reloaded.TurnIndex != 2 { + t.Errorf(`Expected TurnIndex to be 2, got %v`, reloaded.TurnIndex) + } + if reloaded.FirstSeenAt == nil || *reloaded.FirstSeenAt != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected FirstSeenAt to be "2026-06-09T20:00:00Z", got %v`, reloaded.FirstSeenAt) + } } // TestSessionFileRefToYAML tests that ToYAML produces valid YAML @@ -194,4 +279,31 @@ func TestSessionFileRefToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadSessionFileRef(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.SessionId == nil || *reloaded.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, reloaded.SessionId) + } + if reloaded.Path != "src/index.ts" { + t.Errorf(`Expected Path to be "src/index.ts", got %v`, reloaded.Path) + } + if reloaded.ToolName == nil || *reloaded.ToolName != "view" { + t.Errorf(`Expected ToolName to be "view", got %v`, reloaded.ToolName) + } + if reloaded.TurnIndex == nil || *reloaded.TurnIndex != 2 { + t.Errorf(`Expected TurnIndex to be 2, got %v`, reloaded.TurnIndex) + } + if reloaded.FirstSeenAt == nil || *reloaded.FirstSeenAt != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected FirstSeenAt to be "2026-06-09T20:00:00Z", got %v`, reloaded.FirstSeenAt) + } +} + +// TestSessionFileRefFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestSessionFileRefFromJSONInvalid(t *testing.T) { + if _, err := prompty.SessionFileRefFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/session_ref.go b/runtime/go/prompty/model/session_ref.go index cbd19ece..f262df1c 100644 --- a/runtime/go/prompty/model/session_ref.go +++ b/runtime/go/prompty/model/session_ref.go @@ -60,7 +60,7 @@ func LoadSessionRef(data interface{}, ctx *LoadContext) (SessionRef, error) { } // Save serializes SessionRef to map[string]interface{} -func (obj *SessionRef) Save(ctx *SaveContext) map[string]interface{} { +func (obj SessionRef) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) if obj.SessionId != nil { result["sessionId"] = *obj.SessionId @@ -92,11 +92,7 @@ func (obj *SessionRef) ToJSON() (string, error) { func (obj *SessionRef) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates SessionRef from JSON string diff --git a/runtime/go/prompty/model/session_ref_test.go b/runtime/go/prompty/model/session_ref_test.go index 7bbe90c9..6014effd 100644 --- a/runtime/go/prompty/model/session_ref_test.go +++ b/runtime/go/prompty/model/session_ref_test.go @@ -87,6 +87,71 @@ createdAt: "2026-06-09T20:00:00Z" } } +// TestSessionRefFromJSON tests loading SessionRef through the generated JSON helper +func TestSessionRefFromJSON(t *testing.T) { + jsonData := ` +{ + "sessionId": "sess_abc123", + "refType": "issue", + "refValue": "owner/repo#123", + "turnIndex": 2, + "createdAt": "2026-06-09T20:00:00Z" +} +` + + instance, err := prompty.SessionRefFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load SessionRef from JSON helper: %v", err) + } + if instance.SessionId == nil || *instance.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, instance.SessionId) + } + if instance.RefType != "issue" { + t.Errorf(`Expected RefType to be "issue", got %v`, instance.RefType) + } + if instance.RefValue != "owner/repo#123" { + t.Errorf(`Expected RefValue to be "owner/repo#123", got %v`, instance.RefValue) + } + if instance.TurnIndex == nil || *instance.TurnIndex != 2 { + t.Errorf(`Expected TurnIndex to be 2, got %v`, instance.TurnIndex) + } + if instance.CreatedAt == nil || *instance.CreatedAt != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected CreatedAt to be "2026-06-09T20:00:00Z", got %v`, instance.CreatedAt) + } +} + +// TestSessionRefFromYAML tests loading SessionRef through the generated YAML helper +func TestSessionRefFromYAML(t *testing.T) { + yamlData := ` +sessionId: sess_abc123 +refType: issue +refValue: "owner/repo#123" +turnIndex: 2 +createdAt: "2026-06-09T20:00:00Z" + +` + + instance, err := prompty.SessionRefFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load SessionRef from YAML helper: %v", err) + } + if instance.SessionId == nil || *instance.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, instance.SessionId) + } + if instance.RefType != "issue" { + t.Errorf(`Expected RefType to be "issue", got %v`, instance.RefType) + } + if instance.RefValue != "owner/repo#123" { + t.Errorf(`Expected RefValue to be "owner/repo#123", got %v`, instance.RefValue) + } + if instance.TurnIndex == nil || *instance.TurnIndex != 2 { + t.Errorf(`Expected TurnIndex to be 2, got %v`, instance.TurnIndex) + } + if instance.CreatedAt == nil || *instance.CreatedAt != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected CreatedAt to be "2026-06-09T20:00:00Z", got %v`, instance.CreatedAt) + } +} + // TestSessionRefRoundtrip tests load -> save -> load produces equivalent data func TestSessionRefRoundtrip(t *testing.T) { jsonData := ` @@ -162,6 +227,26 @@ func TestSessionRefToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadSessionRef(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.SessionId == nil || *reloaded.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, reloaded.SessionId) + } + if reloaded.RefType != "issue" { + t.Errorf(`Expected RefType to be "issue", got %v`, reloaded.RefType) + } + if reloaded.RefValue != "owner/repo#123" { + t.Errorf(`Expected RefValue to be "owner/repo#123", got %v`, reloaded.RefValue) + } + if reloaded.TurnIndex == nil || *reloaded.TurnIndex != 2 { + t.Errorf(`Expected TurnIndex to be 2, got %v`, reloaded.TurnIndex) + } + if reloaded.CreatedAt == nil || *reloaded.CreatedAt != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected CreatedAt to be "2026-06-09T20:00:00Z", got %v`, reloaded.CreatedAt) + } } // TestSessionRefToYAML tests that ToYAML produces valid YAML @@ -194,4 +279,31 @@ func TestSessionRefToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadSessionRef(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.SessionId == nil || *reloaded.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, reloaded.SessionId) + } + if reloaded.RefType != "issue" { + t.Errorf(`Expected RefType to be "issue", got %v`, reloaded.RefType) + } + if reloaded.RefValue != "owner/repo#123" { + t.Errorf(`Expected RefValue to be "owner/repo#123", got %v`, reloaded.RefValue) + } + if reloaded.TurnIndex == nil || *reloaded.TurnIndex != 2 { + t.Errorf(`Expected TurnIndex to be 2, got %v`, reloaded.TurnIndex) + } + if reloaded.CreatedAt == nil || *reloaded.CreatedAt != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected CreatedAt to be "2026-06-09T20:00:00Z", got %v`, reloaded.CreatedAt) + } +} + +// TestSessionRefFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestSessionRefFromJSONInvalid(t *testing.T) { + if _, err := prompty.SessionRefFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/session_start_payload.go b/runtime/go/prompty/model/session_start_payload.go index b642e5c9..cd483fc9 100644 --- a/runtime/go/prompty/model/session_start_payload.go +++ b/runtime/go/prompty/model/session_start_payload.go @@ -73,7 +73,7 @@ func LoadSessionStartPayload(data interface{}, ctx *LoadContext) (SessionStartPa } // Save serializes SessionStartPayload to map[string]interface{} -func (obj *SessionStartPayload) Save(ctx *SaveContext) map[string]interface{} { +func (obj SessionStartPayload) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["sessionId"] = obj.SessionId if obj.SchemaVersion != nil { @@ -119,11 +119,7 @@ func (obj *SessionStartPayload) ToJSON() (string, error) { func (obj *SessionStartPayload) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates SessionStartPayload from JSON string diff --git a/runtime/go/prompty/model/session_start_payload_test.go b/runtime/go/prompty/model/session_start_payload_test.go index 8aba7f73..0a4c1ec5 100644 --- a/runtime/go/prompty/model/session_start_payload_test.go +++ b/runtime/go/prompty/model/session_start_payload_test.go @@ -111,6 +111,95 @@ reasoningEffort: medium } } +// TestSessionStartPayloadFromJSON tests loading SessionStartPayload through the generated JSON helper +func TestSessionStartPayloadFromJSON(t *testing.T) { + jsonData := ` +{ + "sessionId": "sess_abc123", + "schemaVersion": "1", + "producer": "prompty-agent", + "runtime": "typescript", + "promptyVersion": "2.0.0", + "startTime": "2026-06-09T20:00:00Z", + "selectedModel": "gpt-4o-mini", + "reasoningEffort": "medium" +} +` + + instance, err := prompty.SessionStartPayloadFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load SessionStartPayload from JSON helper: %v", err) + } + if instance.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, instance.SessionId) + } + if instance.SchemaVersion == nil || *instance.SchemaVersion != "1" { + t.Errorf(`Expected SchemaVersion to be "1", got %v`, instance.SchemaVersion) + } + if instance.Producer == nil || *instance.Producer != "prompty-agent" { + t.Errorf(`Expected Producer to be "prompty-agent", got %v`, instance.Producer) + } + if instance.Runtime == nil || *instance.Runtime != "typescript" { + t.Errorf(`Expected Runtime to be "typescript", got %v`, instance.Runtime) + } + if instance.PromptyVersion == nil || *instance.PromptyVersion != "2.0.0" { + t.Errorf(`Expected PromptyVersion to be "2.0.0", got %v`, instance.PromptyVersion) + } + if instance.StartTime == nil || *instance.StartTime != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected StartTime to be "2026-06-09T20:00:00Z", got %v`, instance.StartTime) + } + if instance.SelectedModel == nil || *instance.SelectedModel != "gpt-4o-mini" { + t.Errorf(`Expected SelectedModel to be "gpt-4o-mini", got %v`, instance.SelectedModel) + } + if instance.ReasoningEffort == nil || *instance.ReasoningEffort != "medium" { + t.Errorf(`Expected ReasoningEffort to be "medium", got %v`, instance.ReasoningEffort) + } +} + +// TestSessionStartPayloadFromYAML tests loading SessionStartPayload through the generated YAML helper +func TestSessionStartPayloadFromYAML(t *testing.T) { + yamlData := ` +sessionId: sess_abc123 +schemaVersion: "1" +producer: prompty-agent +runtime: typescript +promptyVersion: 2.0.0 +startTime: "2026-06-09T20:00:00Z" +selectedModel: gpt-4o-mini +reasoningEffort: medium + +` + + instance, err := prompty.SessionStartPayloadFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load SessionStartPayload from YAML helper: %v", err) + } + if instance.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, instance.SessionId) + } + if instance.SchemaVersion == nil || *instance.SchemaVersion != "1" { + t.Errorf(`Expected SchemaVersion to be "1", got %v`, instance.SchemaVersion) + } + if instance.Producer == nil || *instance.Producer != "prompty-agent" { + t.Errorf(`Expected Producer to be "prompty-agent", got %v`, instance.Producer) + } + if instance.Runtime == nil || *instance.Runtime != "typescript" { + t.Errorf(`Expected Runtime to be "typescript", got %v`, instance.Runtime) + } + if instance.PromptyVersion == nil || *instance.PromptyVersion != "2.0.0" { + t.Errorf(`Expected PromptyVersion to be "2.0.0", got %v`, instance.PromptyVersion) + } + if instance.StartTime == nil || *instance.StartTime != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected StartTime to be "2026-06-09T20:00:00Z", got %v`, instance.StartTime) + } + if instance.SelectedModel == nil || *instance.SelectedModel != "gpt-4o-mini" { + t.Errorf(`Expected SelectedModel to be "gpt-4o-mini", got %v`, instance.SelectedModel) + } + if instance.ReasoningEffort == nil || *instance.ReasoningEffort != "medium" { + t.Errorf(`Expected ReasoningEffort to be "medium", got %v`, instance.ReasoningEffort) + } +} + // TestSessionStartPayloadRoundtrip tests load -> save -> load produces equivalent data func TestSessionStartPayloadRoundtrip(t *testing.T) { jsonData := ` @@ -201,6 +290,35 @@ func TestSessionStartPayloadToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadSessionStartPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, reloaded.SessionId) + } + if reloaded.SchemaVersion == nil || *reloaded.SchemaVersion != "1" { + t.Errorf(`Expected SchemaVersion to be "1", got %v`, reloaded.SchemaVersion) + } + if reloaded.Producer == nil || *reloaded.Producer != "prompty-agent" { + t.Errorf(`Expected Producer to be "prompty-agent", got %v`, reloaded.Producer) + } + if reloaded.Runtime == nil || *reloaded.Runtime != "typescript" { + t.Errorf(`Expected Runtime to be "typescript", got %v`, reloaded.Runtime) + } + if reloaded.PromptyVersion == nil || *reloaded.PromptyVersion != "2.0.0" { + t.Errorf(`Expected PromptyVersion to be "2.0.0", got %v`, reloaded.PromptyVersion) + } + if reloaded.StartTime == nil || *reloaded.StartTime != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected StartTime to be "2026-06-09T20:00:00Z", got %v`, reloaded.StartTime) + } + if reloaded.SelectedModel == nil || *reloaded.SelectedModel != "gpt-4o-mini" { + t.Errorf(`Expected SelectedModel to be "gpt-4o-mini", got %v`, reloaded.SelectedModel) + } + if reloaded.ReasoningEffort == nil || *reloaded.ReasoningEffort != "medium" { + t.Errorf(`Expected ReasoningEffort to be "medium", got %v`, reloaded.ReasoningEffort) + } } // TestSessionStartPayloadToYAML tests that ToYAML produces valid YAML @@ -236,4 +354,40 @@ func TestSessionStartPayloadToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadSessionStartPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, reloaded.SessionId) + } + if reloaded.SchemaVersion == nil || *reloaded.SchemaVersion != "1" { + t.Errorf(`Expected SchemaVersion to be "1", got %v`, reloaded.SchemaVersion) + } + if reloaded.Producer == nil || *reloaded.Producer != "prompty-agent" { + t.Errorf(`Expected Producer to be "prompty-agent", got %v`, reloaded.Producer) + } + if reloaded.Runtime == nil || *reloaded.Runtime != "typescript" { + t.Errorf(`Expected Runtime to be "typescript", got %v`, reloaded.Runtime) + } + if reloaded.PromptyVersion == nil || *reloaded.PromptyVersion != "2.0.0" { + t.Errorf(`Expected PromptyVersion to be "2.0.0", got %v`, reloaded.PromptyVersion) + } + if reloaded.StartTime == nil || *reloaded.StartTime != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected StartTime to be "2026-06-09T20:00:00Z", got %v`, reloaded.StartTime) + } + if reloaded.SelectedModel == nil || *reloaded.SelectedModel != "gpt-4o-mini" { + t.Errorf(`Expected SelectedModel to be "gpt-4o-mini", got %v`, reloaded.SelectedModel) + } + if reloaded.ReasoningEffort == nil || *reloaded.ReasoningEffort != "medium" { + t.Errorf(`Expected ReasoningEffort to be "medium", got %v`, reloaded.ReasoningEffort) + } +} + +// TestSessionStartPayloadFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestSessionStartPayloadFromJSONInvalid(t *testing.T) { + if _, err := prompty.SessionStartPayloadFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/session_summary.go b/runtime/go/prompty/model/session_summary.go index c83f4ab6..255110db 100644 --- a/runtime/go/prompty/model/session_summary.go +++ b/runtime/go/prompty/model/session_summary.go @@ -100,7 +100,7 @@ func LoadSessionSummary(data interface{}, ctx *LoadContext) (SessionSummary, err } // Save serializes SessionSummary to map[string]interface{} -func (obj *SessionSummary) Save(ctx *SaveContext) map[string]interface{} { +func (obj SessionSummary) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["sessionId"] = obj.SessionId if obj.Status != nil { @@ -137,11 +137,7 @@ func (obj *SessionSummary) ToJSON() (string, error) { func (obj *SessionSummary) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates SessionSummary from JSON string diff --git a/runtime/go/prompty/model/session_summary_test.go b/runtime/go/prompty/model/session_summary_test.go index 55ac95d0..ecbb0b8f 100644 --- a/runtime/go/prompty/model/session_summary_test.go +++ b/runtime/go/prompty/model/session_summary_test.go @@ -87,6 +87,71 @@ durationMs: 12500 } } +// TestSessionSummaryFromJSON tests loading SessionSummary through the generated JSON helper +func TestSessionSummaryFromJSON(t *testing.T) { + jsonData := ` +{ + "sessionId": "sess_abc123", + "status": "success", + "turns": 5, + "checkpoints": 2, + "durationMs": 12500 +} +` + + instance, err := prompty.SessionSummaryFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load SessionSummary from JSON helper: %v", err) + } + if instance.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, instance.SessionId) + } + if instance.Status == nil || *instance.Status != "success" { + t.Errorf(`Expected Status to be "success", got %v`, instance.Status) + } + if instance.Turns == nil || *instance.Turns != 5 { + t.Errorf(`Expected Turns to be 5, got %v`, instance.Turns) + } + if instance.Checkpoints == nil || *instance.Checkpoints != 2 { + t.Errorf(`Expected Checkpoints to be 2, got %v`, instance.Checkpoints) + } + if instance.DurationMs == nil || *instance.DurationMs != 12500 { + t.Errorf(`Expected DurationMs to be 12500, got %v`, instance.DurationMs) + } +} + +// TestSessionSummaryFromYAML tests loading SessionSummary through the generated YAML helper +func TestSessionSummaryFromYAML(t *testing.T) { + yamlData := ` +sessionId: sess_abc123 +status: success +turns: 5 +checkpoints: 2 +durationMs: 12500 + +` + + instance, err := prompty.SessionSummaryFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load SessionSummary from YAML helper: %v", err) + } + if instance.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, instance.SessionId) + } + if instance.Status == nil || *instance.Status != "success" { + t.Errorf(`Expected Status to be "success", got %v`, instance.Status) + } + if instance.Turns == nil || *instance.Turns != 5 { + t.Errorf(`Expected Turns to be 5, got %v`, instance.Turns) + } + if instance.Checkpoints == nil || *instance.Checkpoints != 2 { + t.Errorf(`Expected Checkpoints to be 2, got %v`, instance.Checkpoints) + } + if instance.DurationMs == nil || *instance.DurationMs != 12500 { + t.Errorf(`Expected DurationMs to be 12500, got %v`, instance.DurationMs) + } +} + // TestSessionSummaryRoundtrip tests load -> save -> load produces equivalent data func TestSessionSummaryRoundtrip(t *testing.T) { jsonData := ` @@ -162,6 +227,26 @@ func TestSessionSummaryToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadSessionSummary(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, reloaded.SessionId) + } + if reloaded.Status == nil || *reloaded.Status != "success" { + t.Errorf(`Expected Status to be "success", got %v`, reloaded.Status) + } + if reloaded.Turns == nil || *reloaded.Turns != 5 { + t.Errorf(`Expected Turns to be 5, got %v`, reloaded.Turns) + } + if reloaded.Checkpoints == nil || *reloaded.Checkpoints != 2 { + t.Errorf(`Expected Checkpoints to be 2, got %v`, reloaded.Checkpoints) + } + if reloaded.DurationMs == nil || *reloaded.DurationMs != 12500 { + t.Errorf(`Expected DurationMs to be 12500, got %v`, reloaded.DurationMs) + } } // TestSessionSummaryToYAML tests that ToYAML produces valid YAML @@ -194,4 +279,31 @@ func TestSessionSummaryToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadSessionSummary(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, reloaded.SessionId) + } + if reloaded.Status == nil || *reloaded.Status != "success" { + t.Errorf(`Expected Status to be "success", got %v`, reloaded.Status) + } + if reloaded.Turns == nil || *reloaded.Turns != 5 { + t.Errorf(`Expected Turns to be 5, got %v`, reloaded.Turns) + } + if reloaded.Checkpoints == nil || *reloaded.Checkpoints != 2 { + t.Errorf(`Expected Checkpoints to be 2, got %v`, reloaded.Checkpoints) + } + if reloaded.DurationMs == nil || *reloaded.DurationMs != 12500 { + t.Errorf(`Expected DurationMs to be 12500, got %v`, reloaded.DurationMs) + } +} + +// TestSessionSummaryFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestSessionSummaryFromJSONInvalid(t *testing.T) { + if _, err := prompty.SessionSummaryFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/session_trace.go b/runtime/go/prompty/model/session_trace.go index f8fe8bfd..4e8aca84 100644 --- a/runtime/go/prompty/model/session_trace.go +++ b/runtime/go/prompty/model/session_trace.go @@ -125,7 +125,7 @@ func LoadSessionTrace(data interface{}, ctx *LoadContext) (SessionTrace, error) } // Save serializes SessionTrace to map[string]interface{} -func (obj *SessionTrace) Save(ctx *SaveContext) map[string]interface{} { +func (obj SessionTrace) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["version"] = obj.Version if obj.Runtime != nil { @@ -201,11 +201,7 @@ func (obj *SessionTrace) ToJSON() (string, error) { func (obj *SessionTrace) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates SessionTrace from JSON string diff --git a/runtime/go/prompty/model/session_trace_test.go b/runtime/go/prompty/model/session_trace_test.go index a5b2cb02..0c6403ee 100644 --- a/runtime/go/prompty/model/session_trace_test.go +++ b/runtime/go/prompty/model/session_trace_test.go @@ -79,6 +79,63 @@ sessionId: sess_abc123 } } +// TestSessionTraceFromJSON tests loading SessionTrace through the generated JSON helper +func TestSessionTraceFromJSON(t *testing.T) { + jsonData := ` +{ + "version": "1", + "runtime": "typescript", + "promptyVersion": "2.0.0", + "sessionId": "sess_abc123" +} +` + + instance, err := prompty.SessionTraceFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load SessionTrace from JSON helper: %v", err) + } + if instance.Version != "1" { + t.Errorf(`Expected Version to be "1", got %v`, instance.Version) + } + if instance.Runtime == nil || *instance.Runtime != "typescript" { + t.Errorf(`Expected Runtime to be "typescript", got %v`, instance.Runtime) + } + if instance.PromptyVersion == nil || *instance.PromptyVersion != "2.0.0" { + t.Errorf(`Expected PromptyVersion to be "2.0.0", got %v`, instance.PromptyVersion) + } + if instance.SessionId == nil || *instance.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, instance.SessionId) + } +} + +// TestSessionTraceFromYAML tests loading SessionTrace through the generated YAML helper +func TestSessionTraceFromYAML(t *testing.T) { + yamlData := ` +version: "1" +runtime: typescript +promptyVersion: 2.0.0 +sessionId: sess_abc123 + +` + + instance, err := prompty.SessionTraceFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load SessionTrace from YAML helper: %v", err) + } + if instance.Version != "1" { + t.Errorf(`Expected Version to be "1", got %v`, instance.Version) + } + if instance.Runtime == nil || *instance.Runtime != "typescript" { + t.Errorf(`Expected Runtime to be "typescript", got %v`, instance.Runtime) + } + if instance.PromptyVersion == nil || *instance.PromptyVersion != "2.0.0" { + t.Errorf(`Expected PromptyVersion to be "2.0.0", got %v`, instance.PromptyVersion) + } + if instance.SessionId == nil || *instance.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, instance.SessionId) + } +} + // TestSessionTraceRoundtrip tests load -> save -> load produces equivalent data func TestSessionTraceRoundtrip(t *testing.T) { jsonData := ` @@ -149,6 +206,23 @@ func TestSessionTraceToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadSessionTrace(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Version != "1" { + t.Errorf(`Expected Version to be "1", got %v`, reloaded.Version) + } + if reloaded.Runtime == nil || *reloaded.Runtime != "typescript" { + t.Errorf(`Expected Runtime to be "typescript", got %v`, reloaded.Runtime) + } + if reloaded.PromptyVersion == nil || *reloaded.PromptyVersion != "2.0.0" { + t.Errorf(`Expected PromptyVersion to be "2.0.0", got %v`, reloaded.PromptyVersion) + } + if reloaded.SessionId == nil || *reloaded.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, reloaded.SessionId) + } } // TestSessionTraceToYAML tests that ToYAML produces valid YAML @@ -180,4 +254,28 @@ func TestSessionTraceToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadSessionTrace(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Version != "1" { + t.Errorf(`Expected Version to be "1", got %v`, reloaded.Version) + } + if reloaded.Runtime == nil || *reloaded.Runtime != "typescript" { + t.Errorf(`Expected Runtime to be "typescript", got %v`, reloaded.Runtime) + } + if reloaded.PromptyVersion == nil || *reloaded.PromptyVersion != "2.0.0" { + t.Errorf(`Expected PromptyVersion to be "2.0.0", got %v`, reloaded.PromptyVersion) + } + if reloaded.SessionId == nil || *reloaded.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, reloaded.SessionId) + } +} + +// TestSessionTraceFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestSessionTraceFromJSONInvalid(t *testing.T) { + if _, err := prompty.SessionTraceFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/session_warning_payload.go b/runtime/go/prompty/model/session_warning_payload.go index af0e39b8..fd368017 100644 --- a/runtime/go/prompty/model/session_warning_payload.go +++ b/runtime/go/prompty/model/session_warning_payload.go @@ -41,7 +41,7 @@ func LoadSessionWarningPayload(data interface{}, ctx *LoadContext) (SessionWarni } // Save serializes SessionWarningPayload to map[string]interface{} -func (obj *SessionWarningPayload) Save(ctx *SaveContext) map[string]interface{} { +func (obj SessionWarningPayload) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["warningType"] = obj.WarningType result["message"] = obj.Message @@ -67,11 +67,7 @@ func (obj *SessionWarningPayload) ToJSON() (string, error) { func (obj *SessionWarningPayload) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates SessionWarningPayload from JSON string diff --git a/runtime/go/prompty/model/session_warning_payload_test.go b/runtime/go/prompty/model/session_warning_payload_test.go index 273124d7..e8356bb7 100644 --- a/runtime/go/prompty/model/session_warning_payload_test.go +++ b/runtime/go/prompty/model/session_warning_payload_test.go @@ -63,6 +63,47 @@ message: Remote session disabled } } +// TestSessionWarningPayloadFromJSON tests loading SessionWarningPayload through the generated JSON helper +func TestSessionWarningPayloadFromJSON(t *testing.T) { + jsonData := ` +{ + "warningType": "remote", + "message": "Remote session disabled" +} +` + + instance, err := prompty.SessionWarningPayloadFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load SessionWarningPayload from JSON helper: %v", err) + } + if instance.WarningType != "remote" { + t.Errorf(`Expected WarningType to be "remote", got %v`, instance.WarningType) + } + if instance.Message != "Remote session disabled" { + t.Errorf(`Expected Message to be "Remote session disabled", got %v`, instance.Message) + } +} + +// TestSessionWarningPayloadFromYAML tests loading SessionWarningPayload through the generated YAML helper +func TestSessionWarningPayloadFromYAML(t *testing.T) { + yamlData := ` +warningType: remote +message: Remote session disabled + +` + + instance, err := prompty.SessionWarningPayloadFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load SessionWarningPayload from YAML helper: %v", err) + } + if instance.WarningType != "remote" { + t.Errorf(`Expected WarningType to be "remote", got %v`, instance.WarningType) + } + if instance.Message != "Remote session disabled" { + t.Errorf(`Expected Message to be "Remote session disabled", got %v`, instance.Message) + } +} + // TestSessionWarningPayloadRoundtrip tests load -> save -> load produces equivalent data func TestSessionWarningPayloadRoundtrip(t *testing.T) { jsonData := ` @@ -123,6 +164,17 @@ func TestSessionWarningPayloadToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadSessionWarningPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.WarningType != "remote" { + t.Errorf(`Expected WarningType to be "remote", got %v`, reloaded.WarningType) + } + if reloaded.Message != "Remote session disabled" { + t.Errorf(`Expected Message to be "Remote session disabled", got %v`, reloaded.Message) + } } // TestSessionWarningPayloadToYAML tests that ToYAML produces valid YAML @@ -152,4 +204,22 @@ func TestSessionWarningPayloadToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadSessionWarningPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.WarningType != "remote" { + t.Errorf(`Expected WarningType to be "remote", got %v`, reloaded.WarningType) + } + if reloaded.Message != "Remote session disabled" { + t.Errorf(`Expected Message to be "Remote session disabled", got %v`, reloaded.Message) + } +} + +// TestSessionWarningPayloadFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestSessionWarningPayloadFromJSONInvalid(t *testing.T) { + if _, err := prompty.SessionWarningPayloadFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/status_event_payload.go b/runtime/go/prompty/model/status_event_payload.go index d7d3db3c..51b68a98 100644 --- a/runtime/go/prompty/model/status_event_payload.go +++ b/runtime/go/prompty/model/status_event_payload.go @@ -31,7 +31,7 @@ func LoadStatusEventPayload(data interface{}, ctx *LoadContext) (StatusEventPayl } // Save serializes StatusEventPayload to map[string]interface{} -func (obj *StatusEventPayload) Save(ctx *SaveContext) map[string]interface{} { +func (obj StatusEventPayload) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["message"] = obj.Message @@ -53,11 +53,7 @@ func (obj *StatusEventPayload) ToJSON() (string, error) { func (obj *StatusEventPayload) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates StatusEventPayload from JSON string diff --git a/runtime/go/prompty/model/status_event_payload_test.go b/runtime/go/prompty/model/status_event_payload_test.go index b76f9a19..202a4114 100644 --- a/runtime/go/prompty/model/status_event_payload_test.go +++ b/runtime/go/prompty/model/status_event_payload_test.go @@ -55,6 +55,39 @@ message: Starting iteration 3 } } +// TestStatusEventPayloadFromJSON tests loading StatusEventPayload through the generated JSON helper +func TestStatusEventPayloadFromJSON(t *testing.T) { + jsonData := ` +{ + "message": "Starting iteration 3" +} +` + + instance, err := prompty.StatusEventPayloadFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load StatusEventPayload from JSON helper: %v", err) + } + if instance.Message != "Starting iteration 3" { + t.Errorf(`Expected Message to be "Starting iteration 3", got %v`, instance.Message) + } +} + +// TestStatusEventPayloadFromYAML tests loading StatusEventPayload through the generated YAML helper +func TestStatusEventPayloadFromYAML(t *testing.T) { + yamlData := ` +message: Starting iteration 3 + +` + + instance, err := prompty.StatusEventPayloadFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load StatusEventPayload from YAML helper: %v", err) + } + if instance.Message != "Starting iteration 3" { + t.Errorf(`Expected Message to be "Starting iteration 3", got %v`, instance.Message) + } +} + // TestStatusEventPayloadRoundtrip tests load -> save -> load produces equivalent data func TestStatusEventPayloadRoundtrip(t *testing.T) { jsonData := ` @@ -110,6 +143,14 @@ func TestStatusEventPayloadToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadStatusEventPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Message != "Starting iteration 3" { + t.Errorf(`Expected Message to be "Starting iteration 3", got %v`, reloaded.Message) + } } // TestStatusEventPayloadToYAML tests that ToYAML produces valid YAML @@ -138,4 +179,19 @@ func TestStatusEventPayloadToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadStatusEventPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Message != "Starting iteration 3" { + t.Errorf(`Expected Message to be "Starting iteration 3", got %v`, reloaded.Message) + } +} + +// TestStatusEventPayloadFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestStatusEventPayloadFromJSONInvalid(t *testing.T) { + if _, err := prompty.StatusEventPayloadFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/stream_chunk.go b/runtime/go/prompty/model/stream_chunk.go index 714705f6..ab03e351 100644 --- a/runtime/go/prompty/model/stream_chunk.go +++ b/runtime/go/prompty/model/stream_chunk.go @@ -48,7 +48,7 @@ func LoadStreamChunk(data interface{}, ctx *LoadContext) (interface{}, error) { } // Save serializes StreamChunk to map[string]interface{} -func (obj *StreamChunk) Save(ctx *SaveContext) map[string]interface{} { +func (obj StreamChunk) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["kind"] = obj.Kind @@ -70,11 +70,7 @@ func (obj *StreamChunk) ToJSON() (string, error) { func (obj *StreamChunk) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates StreamChunk from JSON string @@ -124,7 +120,7 @@ func LoadTextChunk(data interface{}, ctx *LoadContext) (TextChunk, error) { } // Save serializes TextChunk to map[string]interface{} -func (obj *TextChunk) Save(ctx *SaveContext) map[string]interface{} { +func (obj TextChunk) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["kind"] = obj.Kind result["value"] = obj.Value @@ -147,11 +143,7 @@ func (obj *TextChunk) ToJSON() (string, error) { func (obj *TextChunk) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates TextChunk from JSON string @@ -199,7 +191,7 @@ func LoadThinkingChunk(data interface{}, ctx *LoadContext) (ThinkingChunk, error } // Save serializes ThinkingChunk to map[string]interface{} -func (obj *ThinkingChunk) Save(ctx *SaveContext) map[string]interface{} { +func (obj ThinkingChunk) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["kind"] = obj.Kind result["value"] = obj.Value @@ -222,11 +214,7 @@ func (obj *ThinkingChunk) ToJSON() (string, error) { func (obj *ThinkingChunk) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates ThinkingChunk from JSON string @@ -277,7 +265,7 @@ func LoadToolChunk(data interface{}, ctx *LoadContext) (ToolChunk, error) { } // Save serializes ToolChunk to map[string]interface{} -func (obj *ToolChunk) Save(ctx *SaveContext) map[string]interface{} { +func (obj ToolChunk) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["kind"] = obj.Kind @@ -301,11 +289,7 @@ func (obj *ToolChunk) ToJSON() (string, error) { func (obj *ToolChunk) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates ToolChunk from JSON string @@ -353,7 +337,7 @@ func LoadErrorChunk(data interface{}, ctx *LoadContext) (ErrorChunk, error) { } // Save serializes ErrorChunk to map[string]interface{} -func (obj *ErrorChunk) Save(ctx *SaveContext) map[string]interface{} { +func (obj ErrorChunk) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["kind"] = obj.Kind result["message"] = obj.Message @@ -376,11 +360,7 @@ func (obj *ErrorChunk) ToJSON() (string, error) { func (obj *ErrorChunk) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates ErrorChunk from JSON string diff --git a/runtime/go/prompty/model/stream_options.go b/runtime/go/prompty/model/stream_options.go index 6527f6d8..a874b014 100644 --- a/runtime/go/prompty/model/stream_options.go +++ b/runtime/go/prompty/model/stream_options.go @@ -33,7 +33,7 @@ func LoadStreamOptions(data interface{}, ctx *LoadContext) (StreamOptions, error } // Save serializes StreamOptions to map[string]interface{} -func (obj *StreamOptions) Save(ctx *SaveContext) map[string]interface{} { +func (obj StreamOptions) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) if obj.IncludeUsage != nil { result["includeUsage"] = *obj.IncludeUsage @@ -57,11 +57,7 @@ func (obj *StreamOptions) ToJSON() (string, error) { func (obj *StreamOptions) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates StreamOptions from JSON string diff --git a/runtime/go/prompty/model/stream_options_test.go b/runtime/go/prompty/model/stream_options_test.go index 6f4a274a..a2b95ff9 100644 --- a/runtime/go/prompty/model/stream_options_test.go +++ b/runtime/go/prompty/model/stream_options_test.go @@ -55,6 +55,39 @@ includeUsage: true } } +// TestStreamOptionsFromJSON tests loading StreamOptions through the generated JSON helper +func TestStreamOptionsFromJSON(t *testing.T) { + jsonData := ` +{ + "includeUsage": true +} +` + + instance, err := prompty.StreamOptionsFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load StreamOptions from JSON helper: %v", err) + } + if instance.IncludeUsage == nil || *instance.IncludeUsage != true { + t.Errorf(`Expected IncludeUsage to be true, got %v`, instance.IncludeUsage) + } +} + +// TestStreamOptionsFromYAML tests loading StreamOptions through the generated YAML helper +func TestStreamOptionsFromYAML(t *testing.T) { + yamlData := ` +includeUsage: true + +` + + instance, err := prompty.StreamOptionsFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load StreamOptions from YAML helper: %v", err) + } + if instance.IncludeUsage == nil || *instance.IncludeUsage != true { + t.Errorf(`Expected IncludeUsage to be true, got %v`, instance.IncludeUsage) + } +} + // TestStreamOptionsRoundtrip tests load -> save -> load produces equivalent data func TestStreamOptionsRoundtrip(t *testing.T) { jsonData := ` @@ -110,6 +143,14 @@ func TestStreamOptionsToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadStreamOptions(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.IncludeUsage == nil || *reloaded.IncludeUsage != true { + t.Errorf(`Expected IncludeUsage to be true, got %v`, reloaded.IncludeUsage) + } } // TestStreamOptionsToYAML tests that ToYAML produces valid YAML @@ -138,4 +179,19 @@ func TestStreamOptionsToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadStreamOptions(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.IncludeUsage == nil || *reloaded.IncludeUsage != true { + t.Errorf(`Expected IncludeUsage to be true, got %v`, reloaded.IncludeUsage) + } +} + +// TestStreamOptionsFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestStreamOptionsFromJSONInvalid(t *testing.T) { + if _, err := prompty.StreamOptionsFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/template.go b/runtime/go/prompty/model/template.go index 2e2c5b53..c4c84054 100644 --- a/runtime/go/prompty/model/template.go +++ b/runtime/go/prompty/model/template.go @@ -34,12 +34,18 @@ func LoadTemplate(data interface{}, ctx *LoadContext) (Template, error) { if m, ok := val.(map[string]interface{}); ok { loaded, _ := LoadFormatConfig(m, ctx) result.Format = loaded + } else { + loaded, _ := LoadFormatConfig(val, ctx) + result.Format = loaded } } if val, ok := m["parser"]; ok && val != nil { if m, ok := val.(map[string]interface{}); ok { loaded, _ := LoadParserConfig(m, ctx) result.Parser = loaded + } else { + loaded, _ := LoadParserConfig(val, ctx) + result.Parser = loaded } } } @@ -48,7 +54,7 @@ func LoadTemplate(data interface{}, ctx *LoadContext) (Template, error) { } // Save serializes Template to map[string]interface{} -func (obj *Template) Save(ctx *SaveContext) map[string]interface{} { +func (obj Template) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["format"] = obj.Format.Save(ctx) @@ -73,11 +79,7 @@ func (obj *Template) ToJSON() (string, error) { func (obj *Template) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates Template from JSON string diff --git a/runtime/go/prompty/model/template_test.go b/runtime/go/prompty/model/template_test.go index fba6744f..06d277b8 100644 --- a/runtime/go/prompty/model/template_test.go +++ b/runtime/go/prompty/model/template_test.go @@ -35,6 +35,12 @@ func TestTemplateLoadJSON(t *testing.T) { t.Fatalf("Failed to load Template: %v", err) } _ = instance // No scalar properties to validate + if instance.Format.Kind != "mustache" { + t.Errorf(`Expected Format.Kind to be "mustache", got %v`, instance.Format.Kind) + } + if instance.Parser.Kind != "mustache" { + t.Errorf(`Expected Parser.Kind to be "mustache", got %v`, instance.Parser.Kind) + } } // TestTemplateLoadYAML tests loading Template from YAML @@ -57,6 +63,61 @@ parser: t.Fatalf("Failed to load Template: %v", err) } _ = instance // No scalar properties to validate + if instance.Format.Kind != "mustache" { + t.Errorf(`Expected Format.Kind to be "mustache", got %v`, instance.Format.Kind) + } + if instance.Parser.Kind != "mustache" { + t.Errorf(`Expected Parser.Kind to be "mustache", got %v`, instance.Parser.Kind) + } +} + +// TestTemplateFromJSON tests loading Template through the generated JSON helper +func TestTemplateFromJSON(t *testing.T) { + jsonData := ` +{ + "format": { + "kind": "mustache" + }, + "parser": { + "kind": "mustache" + } +} +` + + instance, err := prompty.TemplateFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load Template from JSON helper: %v", err) + } + _ = instance // No scalar properties to validate + if instance.Format.Kind != "mustache" { + t.Errorf(`Expected Format.Kind to be "mustache", got %v`, instance.Format.Kind) + } + if instance.Parser.Kind != "mustache" { + t.Errorf(`Expected Parser.Kind to be "mustache", got %v`, instance.Parser.Kind) + } +} + +// TestTemplateFromYAML tests loading Template through the generated YAML helper +func TestTemplateFromYAML(t *testing.T) { + yamlData := ` +format: + kind: mustache +parser: + kind: mustache + +` + + instance, err := prompty.TemplateFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load Template from YAML helper: %v", err) + } + _ = instance // No scalar properties to validate + if instance.Format.Kind != "mustache" { + t.Errorf(`Expected Format.Kind to be "mustache", got %v`, instance.Format.Kind) + } + if instance.Parser.Kind != "mustache" { + t.Errorf(`Expected Parser.Kind to be "mustache", got %v`, instance.Parser.Kind) + } } // TestTemplateRoundtrip tests load -> save -> load produces equivalent data @@ -89,6 +150,12 @@ func TestTemplateRoundtrip(t *testing.T) { t.Fatalf("Failed to reload Template: %v", err) } _ = reloaded // No scalar properties to validate + if reloaded.Format.Kind != "mustache" { + t.Errorf(`Expected Format.Kind to be "mustache", got %v`, reloaded.Format.Kind) + } + if reloaded.Parser.Kind != "mustache" { + t.Errorf(`Expected Parser.Kind to be "mustache", got %v`, reloaded.Parser.Kind) + } } // TestTemplateToJSON tests that ToJSON produces valid JSON @@ -122,6 +189,18 @@ func TestTemplateToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadTemplate(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + _ = reloaded // No scalar properties to validate + if reloaded.Format.Kind != "mustache" { + t.Errorf(`Expected Format.Kind to be "mustache", got %v`, reloaded.Format.Kind) + } + if reloaded.Parser.Kind != "mustache" { + t.Errorf(`Expected Parser.Kind to be "mustache", got %v`, reloaded.Parser.Kind) + } } // TestTemplateToYAML tests that ToYAML produces valid YAML @@ -155,4 +234,23 @@ func TestTemplateToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadTemplate(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + _ = reloaded // No scalar properties to validate + if reloaded.Format.Kind != "mustache" { + t.Errorf(`Expected Format.Kind to be "mustache", got %v`, reloaded.Format.Kind) + } + if reloaded.Parser.Kind != "mustache" { + t.Errorf(`Expected Parser.Kind to be "mustache", got %v`, reloaded.Parser.Kind) + } +} + +// TestTemplateFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestTemplateFromJSONInvalid(t *testing.T) { + if _, err := prompty.TemplateFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/text_chunk_test.go b/runtime/go/prompty/model/text_chunk_test.go index aff59956..282c0e30 100644 --- a/runtime/go/prompty/model/text_chunk_test.go +++ b/runtime/go/prompty/model/text_chunk_test.go @@ -55,6 +55,39 @@ value: Hello } } +// TestTextChunkFromJSON tests loading TextChunk through the generated JSON helper +func TestTextChunkFromJSON(t *testing.T) { + jsonData := ` +{ + "value": "Hello" +} +` + + instance, err := prompty.TextChunkFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load TextChunk from JSON helper: %v", err) + } + if instance.Value != "Hello" { + t.Errorf(`Expected Value to be "Hello", got %v`, instance.Value) + } +} + +// TestTextChunkFromYAML tests loading TextChunk through the generated YAML helper +func TestTextChunkFromYAML(t *testing.T) { + yamlData := ` +value: Hello + +` + + instance, err := prompty.TextChunkFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load TextChunk from YAML helper: %v", err) + } + if instance.Value != "Hello" { + t.Errorf(`Expected Value to be "Hello", got %v`, instance.Value) + } +} + // TestTextChunkRoundtrip tests load -> save -> load produces equivalent data func TestTextChunkRoundtrip(t *testing.T) { jsonData := ` @@ -110,6 +143,14 @@ func TestTextChunkToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadTextChunk(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Value != "Hello" { + t.Errorf(`Expected Value to be "Hello", got %v`, reloaded.Value) + } } // TestTextChunkToYAML tests that ToYAML produces valid YAML @@ -138,4 +179,19 @@ func TestTextChunkToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadTextChunk(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Value != "Hello" { + t.Errorf(`Expected Value to be "Hello", got %v`, reloaded.Value) + } +} + +// TestTextChunkFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestTextChunkFromJSONInvalid(t *testing.T) { + if _, err := prompty.TextChunkFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/text_part_test.go b/runtime/go/prompty/model/text_part_test.go index 742286a9..6822a429 100644 --- a/runtime/go/prompty/model/text_part_test.go +++ b/runtime/go/prompty/model/text_part_test.go @@ -55,6 +55,39 @@ value: Hello, world! } } +// TestTextPartFromJSON tests loading TextPart through the generated JSON helper +func TestTextPartFromJSON(t *testing.T) { + jsonData := ` +{ + "value": "Hello, world!" +} +` + + instance, err := prompty.TextPartFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load TextPart from JSON helper: %v", err) + } + if instance.Value != "Hello, world!" { + t.Errorf(`Expected Value to be "Hello, world!", got %v`, instance.Value) + } +} + +// TestTextPartFromYAML tests loading TextPart through the generated YAML helper +func TestTextPartFromYAML(t *testing.T) { + yamlData := ` +value: Hello, world! + +` + + instance, err := prompty.TextPartFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load TextPart from YAML helper: %v", err) + } + if instance.Value != "Hello, world!" { + t.Errorf(`Expected Value to be "Hello, world!", got %v`, instance.Value) + } +} + // TestTextPartRoundtrip tests load -> save -> load produces equivalent data func TestTextPartRoundtrip(t *testing.T) { jsonData := ` @@ -110,6 +143,14 @@ func TestTextPartToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadTextPart(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Value != "Hello, world!" { + t.Errorf(`Expected Value to be "Hello, world!", got %v`, reloaded.Value) + } } // TestTextPartToYAML tests that ToYAML produces valid YAML @@ -138,4 +179,19 @@ func TestTextPartToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadTextPart(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Value != "Hello, world!" { + t.Errorf(`Expected Value to be "Hello, world!", got %v`, reloaded.Value) + } +} + +// TestTextPartFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestTextPartFromJSONInvalid(t *testing.T) { + if _, err := prompty.TextPartFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/thinking_chunk_test.go b/runtime/go/prompty/model/thinking_chunk_test.go index 14c1dc60..480833f1 100644 --- a/runtime/go/prompty/model/thinking_chunk_test.go +++ b/runtime/go/prompty/model/thinking_chunk_test.go @@ -55,6 +55,39 @@ value: Let me consider... } } +// TestThinkingChunkFromJSON tests loading ThinkingChunk through the generated JSON helper +func TestThinkingChunkFromJSON(t *testing.T) { + jsonData := ` +{ + "value": "Let me consider..." +} +` + + instance, err := prompty.ThinkingChunkFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load ThinkingChunk from JSON helper: %v", err) + } + if instance.Value != "Let me consider..." { + t.Errorf(`Expected Value to be "Let me consider...", got %v`, instance.Value) + } +} + +// TestThinkingChunkFromYAML tests loading ThinkingChunk through the generated YAML helper +func TestThinkingChunkFromYAML(t *testing.T) { + yamlData := ` +value: Let me consider... + +` + + instance, err := prompty.ThinkingChunkFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load ThinkingChunk from YAML helper: %v", err) + } + if instance.Value != "Let me consider..." { + t.Errorf(`Expected Value to be "Let me consider...", got %v`, instance.Value) + } +} + // TestThinkingChunkRoundtrip tests load -> save -> load produces equivalent data func TestThinkingChunkRoundtrip(t *testing.T) { jsonData := ` @@ -110,6 +143,14 @@ func TestThinkingChunkToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadThinkingChunk(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Value != "Let me consider..." { + t.Errorf(`Expected Value to be "Let me consider...", got %v`, reloaded.Value) + } } // TestThinkingChunkToYAML tests that ToYAML produces valid YAML @@ -138,4 +179,19 @@ func TestThinkingChunkToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadThinkingChunk(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Value != "Let me consider..." { + t.Errorf(`Expected Value to be "Let me consider...", got %v`, reloaded.Value) + } +} + +// TestThinkingChunkFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestThinkingChunkFromJSONInvalid(t *testing.T) { + if _, err := prompty.ThinkingChunkFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/thinking_event_payload.go b/runtime/go/prompty/model/thinking_event_payload.go index 0cb6db91..901854f5 100644 --- a/runtime/go/prompty/model/thinking_event_payload.go +++ b/runtime/go/prompty/model/thinking_event_payload.go @@ -31,7 +31,7 @@ func LoadThinkingEventPayload(data interface{}, ctx *LoadContext) (ThinkingEvent } // Save serializes ThinkingEventPayload to map[string]interface{} -func (obj *ThinkingEventPayload) Save(ctx *SaveContext) map[string]interface{} { +func (obj ThinkingEventPayload) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["token"] = obj.Token @@ -53,11 +53,7 @@ func (obj *ThinkingEventPayload) ToJSON() (string, error) { func (obj *ThinkingEventPayload) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates ThinkingEventPayload from JSON string diff --git a/runtime/go/prompty/model/thinking_event_payload_test.go b/runtime/go/prompty/model/thinking_event_payload_test.go index 36260c01..12bd2da2 100644 --- a/runtime/go/prompty/model/thinking_event_payload_test.go +++ b/runtime/go/prompty/model/thinking_event_payload_test.go @@ -55,6 +55,39 @@ token: Let me consider... } } +// TestThinkingEventPayloadFromJSON tests loading ThinkingEventPayload through the generated JSON helper +func TestThinkingEventPayloadFromJSON(t *testing.T) { + jsonData := ` +{ + "token": "Let me consider..." +} +` + + instance, err := prompty.ThinkingEventPayloadFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load ThinkingEventPayload from JSON helper: %v", err) + } + if instance.Token != "Let me consider..." { + t.Errorf(`Expected Token to be "Let me consider...", got %v`, instance.Token) + } +} + +// TestThinkingEventPayloadFromYAML tests loading ThinkingEventPayload through the generated YAML helper +func TestThinkingEventPayloadFromYAML(t *testing.T) { + yamlData := ` +token: Let me consider... + +` + + instance, err := prompty.ThinkingEventPayloadFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load ThinkingEventPayload from YAML helper: %v", err) + } + if instance.Token != "Let me consider..." { + t.Errorf(`Expected Token to be "Let me consider...", got %v`, instance.Token) + } +} + // TestThinkingEventPayloadRoundtrip tests load -> save -> load produces equivalent data func TestThinkingEventPayloadRoundtrip(t *testing.T) { jsonData := ` @@ -110,6 +143,14 @@ func TestThinkingEventPayloadToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadThinkingEventPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Token != "Let me consider..." { + t.Errorf(`Expected Token to be "Let me consider...", got %v`, reloaded.Token) + } } // TestThinkingEventPayloadToYAML tests that ToYAML produces valid YAML @@ -138,4 +179,19 @@ func TestThinkingEventPayloadToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadThinkingEventPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Token != "Let me consider..." { + t.Errorf(`Expected Token to be "Let me consider...", got %v`, reloaded.Token) + } +} + +// TestThinkingEventPayloadFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestThinkingEventPayloadFromJSONInvalid(t *testing.T) { + if _, err := prompty.ThinkingEventPayloadFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/thread_marker.go b/runtime/go/prompty/model/thread_marker.go index c86ad2d4..6d9b85da 100644 --- a/runtime/go/prompty/model/thread_marker.go +++ b/runtime/go/prompty/model/thread_marker.go @@ -39,7 +39,7 @@ func LoadThreadMarker(data interface{}, ctx *LoadContext) (ThreadMarker, error) } // Save serializes ThreadMarker to map[string]interface{} -func (obj *ThreadMarker) Save(ctx *SaveContext) map[string]interface{} { +func (obj ThreadMarker) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["name"] = obj.Name result["kind"] = obj.Kind @@ -62,11 +62,7 @@ func (obj *ThreadMarker) ToJSON() (string, error) { func (obj *ThreadMarker) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates ThreadMarker from JSON string diff --git a/runtime/go/prompty/model/thread_marker_test.go b/runtime/go/prompty/model/thread_marker_test.go index 781fc8bd..ae2792f2 100644 --- a/runtime/go/prompty/model/thread_marker_test.go +++ b/runtime/go/prompty/model/thread_marker_test.go @@ -63,6 +63,47 @@ kind: thread } } +// TestThreadMarkerFromJSON tests loading ThreadMarker through the generated JSON helper +func TestThreadMarkerFromJSON(t *testing.T) { + jsonData := ` +{ + "name": "thread", + "kind": "thread" +} +` + + instance, err := prompty.ThreadMarkerFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load ThreadMarker from JSON helper: %v", err) + } + if instance.Name != "thread" { + t.Errorf(`Expected Name to be "thread", got %v`, instance.Name) + } + if instance.Kind != "thread" { + t.Errorf(`Expected Kind to be "thread", got %v`, instance.Kind) + } +} + +// TestThreadMarkerFromYAML tests loading ThreadMarker through the generated YAML helper +func TestThreadMarkerFromYAML(t *testing.T) { + yamlData := ` +name: thread +kind: thread + +` + + instance, err := prompty.ThreadMarkerFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load ThreadMarker from YAML helper: %v", err) + } + if instance.Name != "thread" { + t.Errorf(`Expected Name to be "thread", got %v`, instance.Name) + } + if instance.Kind != "thread" { + t.Errorf(`Expected Kind to be "thread", got %v`, instance.Kind) + } +} + // TestThreadMarkerRoundtrip tests load -> save -> load produces equivalent data func TestThreadMarkerRoundtrip(t *testing.T) { jsonData := ` @@ -123,6 +164,17 @@ func TestThreadMarkerToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadThreadMarker(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Name != "thread" { + t.Errorf(`Expected Name to be "thread", got %v`, reloaded.Name) + } + if reloaded.Kind != "thread" { + t.Errorf(`Expected Kind to be "thread", got %v`, reloaded.Kind) + } } // TestThreadMarkerToYAML tests that ToYAML produces valid YAML @@ -152,4 +204,22 @@ func TestThreadMarkerToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadThreadMarker(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Name != "thread" { + t.Errorf(`Expected Name to be "thread", got %v`, reloaded.Name) + } + if reloaded.Kind != "thread" { + t.Errorf(`Expected Kind to be "thread", got %v`, reloaded.Kind) + } +} + +// TestThreadMarkerFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestThreadMarkerFromJSONInvalid(t *testing.T) { + if _, err := prompty.ThreadMarkerFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/token_event_payload.go b/runtime/go/prompty/model/token_event_payload.go index c3151a2e..172f300b 100644 --- a/runtime/go/prompty/model/token_event_payload.go +++ b/runtime/go/prompty/model/token_event_payload.go @@ -31,7 +31,7 @@ func LoadTokenEventPayload(data interface{}, ctx *LoadContext) (TokenEventPayloa } // Save serializes TokenEventPayload to map[string]interface{} -func (obj *TokenEventPayload) Save(ctx *SaveContext) map[string]interface{} { +func (obj TokenEventPayload) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["token"] = obj.Token @@ -53,11 +53,7 @@ func (obj *TokenEventPayload) ToJSON() (string, error) { func (obj *TokenEventPayload) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates TokenEventPayload from JSON string diff --git a/runtime/go/prompty/model/token_event_payload_test.go b/runtime/go/prompty/model/token_event_payload_test.go index 91769945..7408d58a 100644 --- a/runtime/go/prompty/model/token_event_payload_test.go +++ b/runtime/go/prompty/model/token_event_payload_test.go @@ -55,6 +55,39 @@ token: Hello } } +// TestTokenEventPayloadFromJSON tests loading TokenEventPayload through the generated JSON helper +func TestTokenEventPayloadFromJSON(t *testing.T) { + jsonData := ` +{ + "token": "Hello" +} +` + + instance, err := prompty.TokenEventPayloadFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load TokenEventPayload from JSON helper: %v", err) + } + if instance.Token != "Hello" { + t.Errorf(`Expected Token to be "Hello", got %v`, instance.Token) + } +} + +// TestTokenEventPayloadFromYAML tests loading TokenEventPayload through the generated YAML helper +func TestTokenEventPayloadFromYAML(t *testing.T) { + yamlData := ` +token: Hello + +` + + instance, err := prompty.TokenEventPayloadFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load TokenEventPayload from YAML helper: %v", err) + } + if instance.Token != "Hello" { + t.Errorf(`Expected Token to be "Hello", got %v`, instance.Token) + } +} + // TestTokenEventPayloadRoundtrip tests load -> save -> load produces equivalent data func TestTokenEventPayloadRoundtrip(t *testing.T) { jsonData := ` @@ -110,6 +143,14 @@ func TestTokenEventPayloadToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadTokenEventPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Token != "Hello" { + t.Errorf(`Expected Token to be "Hello", got %v`, reloaded.Token) + } } // TestTokenEventPayloadToYAML tests that ToYAML produces valid YAML @@ -138,4 +179,19 @@ func TestTokenEventPayloadToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadTokenEventPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Token != "Hello" { + t.Errorf(`Expected Token to be "Hello", got %v`, reloaded.Token) + } +} + +// TestTokenEventPayloadFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestTokenEventPayloadFromJSONInvalid(t *testing.T) { + if _, err := prompty.TokenEventPayloadFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/token_usage.go b/runtime/go/prompty/model/token_usage.go index d85f351c..195468ce 100644 --- a/runtime/go/prompty/model/token_usage.go +++ b/runtime/go/prompty/model/token_usage.go @@ -74,7 +74,7 @@ func LoadTokenUsage(data interface{}, ctx *LoadContext) (TokenUsage, error) { } // Save serializes TokenUsage to map[string]interface{} -func (obj *TokenUsage) Save(ctx *SaveContext) map[string]interface{} { +func (obj TokenUsage) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) if obj.PromptTokens != nil { result["promptTokens"] = *obj.PromptTokens @@ -123,11 +123,7 @@ func (obj *TokenUsage) ToJSON() (string, error) { func (obj *TokenUsage) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates TokenUsage from JSON string diff --git a/runtime/go/prompty/model/token_usage_test.go b/runtime/go/prompty/model/token_usage_test.go index dd649ad5..c90347f6 100644 --- a/runtime/go/prompty/model/token_usage_test.go +++ b/runtime/go/prompty/model/token_usage_test.go @@ -71,6 +71,55 @@ totalTokens: 192 } } +// TestTokenUsageFromJSON tests loading TokenUsage through the generated JSON helper +func TestTokenUsageFromJSON(t *testing.T) { + jsonData := ` +{ + "promptTokens": 150, + "completionTokens": 42, + "totalTokens": 192 +} +` + + instance, err := prompty.TokenUsageFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load TokenUsage from JSON helper: %v", err) + } + if instance.PromptTokens == nil || *instance.PromptTokens != 150 { + t.Errorf(`Expected PromptTokens to be 150, got %v`, instance.PromptTokens) + } + if instance.CompletionTokens == nil || *instance.CompletionTokens != 42 { + t.Errorf(`Expected CompletionTokens to be 42, got %v`, instance.CompletionTokens) + } + if instance.TotalTokens == nil || *instance.TotalTokens != 192 { + t.Errorf(`Expected TotalTokens to be 192, got %v`, instance.TotalTokens) + } +} + +// TestTokenUsageFromYAML tests loading TokenUsage through the generated YAML helper +func TestTokenUsageFromYAML(t *testing.T) { + yamlData := ` +promptTokens: 150 +completionTokens: 42 +totalTokens: 192 + +` + + instance, err := prompty.TokenUsageFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load TokenUsage from YAML helper: %v", err) + } + if instance.PromptTokens == nil || *instance.PromptTokens != 150 { + t.Errorf(`Expected PromptTokens to be 150, got %v`, instance.PromptTokens) + } + if instance.CompletionTokens == nil || *instance.CompletionTokens != 42 { + t.Errorf(`Expected CompletionTokens to be 42, got %v`, instance.CompletionTokens) + } + if instance.TotalTokens == nil || *instance.TotalTokens != 192 { + t.Errorf(`Expected TotalTokens to be 192, got %v`, instance.TotalTokens) + } +} + // TestTokenUsageRoundtrip tests load -> save -> load produces equivalent data func TestTokenUsageRoundtrip(t *testing.T) { jsonData := ` @@ -136,6 +185,20 @@ func TestTokenUsageToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadTokenUsage(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.PromptTokens == nil || *reloaded.PromptTokens != 150 { + t.Errorf(`Expected PromptTokens to be 150, got %v`, reloaded.PromptTokens) + } + if reloaded.CompletionTokens == nil || *reloaded.CompletionTokens != 42 { + t.Errorf(`Expected CompletionTokens to be 42, got %v`, reloaded.CompletionTokens) + } + if reloaded.TotalTokens == nil || *reloaded.TotalTokens != 192 { + t.Errorf(`Expected TotalTokens to be 192, got %v`, reloaded.TotalTokens) + } } // TestTokenUsageToYAML tests that ToYAML produces valid YAML @@ -166,4 +229,80 @@ func TestTokenUsageToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadTokenUsage(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.PromptTokens == nil || *reloaded.PromptTokens != 150 { + t.Errorf(`Expected PromptTokens to be 150, got %v`, reloaded.PromptTokens) + } + if reloaded.CompletionTokens == nil || *reloaded.CompletionTokens != 42 { + t.Errorf(`Expected CompletionTokens to be 42, got %v`, reloaded.CompletionTokens) + } + if reloaded.TotalTokens == nil || *reloaded.TotalTokens != 192 { + t.Errorf(`Expected TotalTokens to be 192, got %v`, reloaded.TotalTokens) + } +} + +// TestTokenUsageFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestTokenUsageFromJSONInvalid(t *testing.T) { + if _, err := prompty.TokenUsageFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } +} + +// TestTokenUsageToWire tests provider-specific wire field names +func TestTokenUsageToWire(t *testing.T) { + jsonData := ` +{ + "promptTokens": 150, + "completionTokens": 42, + "totalTokens": 192 +} +` + var data map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &data); err != nil { + t.Fatalf("Failed to parse JSON: %v", err) + } + + ctx := prompty.NewLoadContext() + instance, err := prompty.LoadTokenUsage(data, ctx) + if err != nil { + t.Fatalf("Failed to load TokenUsage: %v", err) + } + + openaiWire := instance.ToWire("openai") + if _, ok := openaiWire["prompt_tokens"]; !ok { + t.Errorf("Expected openai wire output to include prompt_tokens") + } + if _, ok := openaiWire["promptTokens"]; ok { + t.Errorf("Expected openai wire output to omit source field promptTokens") + } + if _, ok := openaiWire["completion_tokens"]; !ok { + t.Errorf("Expected openai wire output to include completion_tokens") + } + if _, ok := openaiWire["completionTokens"]; ok { + t.Errorf("Expected openai wire output to omit source field completionTokens") + } + if _, ok := openaiWire["total_tokens"]; !ok { + t.Errorf("Expected openai wire output to include total_tokens") + } + if _, ok := openaiWire["totalTokens"]; ok { + t.Errorf("Expected openai wire output to omit source field totalTokens") + } + + anthropicWire := instance.ToWire("anthropic") + if _, ok := anthropicWire["input_tokens"]; !ok { + t.Errorf("Expected anthropic wire output to include input_tokens") + } + if _, ok := anthropicWire["promptTokens"]; ok { + t.Errorf("Expected anthropic wire output to omit source field promptTokens") + } + if _, ok := anthropicWire["output_tokens"]; !ok { + t.Errorf("Expected anthropic wire output to include output_tokens") + } + if _, ok := anthropicWire["completionTokens"]; ok { + t.Errorf("Expected anthropic wire output to omit source field completionTokens") + } } diff --git a/runtime/go/prompty/model/tool.go b/runtime/go/prompty/model/tool.go index 48d46486..af834d26 100644 --- a/runtime/go/prompty/model/tool.go +++ b/runtime/go/prompty/model/tool.go @@ -70,7 +70,7 @@ func LoadTool(data interface{}, ctx *LoadContext) (interface{}, error) { } // Save serializes Tool to map[string]interface{} -func (obj *Tool) Save(ctx *SaveContext) map[string]interface{} { +func (obj Tool) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["name"] = obj.Name result["kind"] = obj.Kind @@ -103,11 +103,7 @@ func (obj *Tool) ToJSON() (string, error) { func (obj *Tool) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates Tool from JSON string @@ -171,7 +167,7 @@ func LoadFunctionTool(data interface{}, ctx *LoadContext) (FunctionTool, error) } // Save serializes FunctionTool to map[string]interface{} -func (obj *FunctionTool) Save(ctx *SaveContext) map[string]interface{} { +func (obj FunctionTool) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["kind"] = obj.Kind if obj.Parameters != nil { @@ -211,11 +207,7 @@ func (obj *FunctionTool) ToJSON() (string, error) { func (obj *FunctionTool) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates FunctionTool from JSON string @@ -277,7 +269,7 @@ func LoadCustomTool(data interface{}, ctx *LoadContext) (CustomTool, error) { } // Save serializes CustomTool to map[string]interface{} -func (obj *CustomTool) Save(ctx *SaveContext) map[string]interface{} { +func (obj CustomTool) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["kind"] = obj.Kind @@ -310,11 +302,7 @@ func (obj *CustomTool) ToJSON() (string, error) { func (obj *CustomTool) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates CustomTool from JSON string @@ -375,14 +363,20 @@ func LoadMcpTool(data interface{}, ctx *LoadContext) (McpTool, error) { if m, ok := val.(map[string]interface{}); ok { loaded, _ := LoadMcpApprovalMode(m, ctx) result.ApprovalMode = loaded + } else { + loaded, _ := LoadMcpApprovalMode(val, ctx) + result.ApprovalMode = loaded } } if val, ok := m["allowedTools"]; ok && val != nil { - if arr, ok := val.([]interface{}); ok { + switch arr := val.(type) { + case []interface{}: result.AllowedTools = make([]string, len(arr)) for i, v := range arr { result.AllowedTools[i] = v.(string) } + case []string: + result.AllowedTools = arr } } } @@ -391,7 +385,7 @@ func LoadMcpTool(data interface{}, ctx *LoadContext) (McpTool, error) { } // Save serializes McpTool to map[string]interface{} -func (obj *McpTool) Save(ctx *SaveContext) map[string]interface{} { +func (obj McpTool) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["kind"] = obj.Kind @@ -430,11 +424,7 @@ func (obj *McpTool) ToJSON() (string, error) { func (obj *McpTool) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates McpTool from JSON string @@ -489,7 +479,7 @@ func LoadOpenApiTool(data interface{}, ctx *LoadContext) (OpenApiTool, error) { } // Save serializes OpenApiTool to map[string]interface{} -func (obj *OpenApiTool) Save(ctx *SaveContext) map[string]interface{} { +func (obj OpenApiTool) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["kind"] = obj.Kind @@ -522,11 +512,7 @@ func (obj *OpenApiTool) ToJSON() (string, error) { func (obj *OpenApiTool) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates OpenApiTool from JSON string @@ -581,7 +567,7 @@ func LoadPromptyTool(data interface{}, ctx *LoadContext) (PromptyTool, error) { } // Save serializes PromptyTool to map[string]interface{} -func (obj *PromptyTool) Save(ctx *SaveContext) map[string]interface{} { +func (obj PromptyTool) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["kind"] = obj.Kind result["path"] = obj.Path @@ -605,11 +591,7 @@ func (obj *PromptyTool) ToJSON() (string, error) { func (obj *PromptyTool) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates PromptyTool from JSON string diff --git a/runtime/go/prompty/model/tool_call.go b/runtime/go/prompty/model/tool_call.go index 8796e6ee..e9100ae1 100644 --- a/runtime/go/prompty/model/tool_call.go +++ b/runtime/go/prompty/model/tool_call.go @@ -40,7 +40,7 @@ func LoadToolCall(data interface{}, ctx *LoadContext) (ToolCall, error) { } // Save serializes ToolCall to map[string]interface{} -func (obj *ToolCall) Save(ctx *SaveContext) map[string]interface{} { +func (obj ToolCall) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["id"] = obj.Id result["name"] = obj.Name @@ -64,11 +64,7 @@ func (obj *ToolCall) ToJSON() (string, error) { func (obj *ToolCall) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates ToolCall from JSON string diff --git a/runtime/go/prompty/model/tool_call_complete_payload.go b/runtime/go/prompty/model/tool_call_complete_payload.go index 427b3b14..1669573e 100644 --- a/runtime/go/prompty/model/tool_call_complete_payload.go +++ b/runtime/go/prompty/model/tool_call_complete_payload.go @@ -69,7 +69,7 @@ func LoadToolCallCompletePayload(data interface{}, ctx *LoadContext) (ToolCallCo } // Save serializes ToolCallCompletePayload to map[string]interface{} -func (obj *ToolCallCompletePayload) Save(ctx *SaveContext) map[string]interface{} { +func (obj ToolCallCompletePayload) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) if obj.Id != nil { result["id"] = *obj.Id @@ -104,11 +104,7 @@ func (obj *ToolCallCompletePayload) ToJSON() (string, error) { func (obj *ToolCallCompletePayload) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates ToolCallCompletePayload from JSON string diff --git a/runtime/go/prompty/model/tool_call_complete_payload_test.go b/runtime/go/prompty/model/tool_call_complete_payload_test.go index ba7b11f5..9c481a2e 100644 --- a/runtime/go/prompty/model/tool_call_complete_payload_test.go +++ b/runtime/go/prompty/model/tool_call_complete_payload_test.go @@ -87,6 +87,71 @@ errorKind: timeout } } +// TestToolCallCompletePayloadFromJSON tests loading ToolCallCompletePayload through the generated JSON helper +func TestToolCallCompletePayloadFromJSON(t *testing.T) { + jsonData := ` +{ + "id": "call_abc123", + "name": "get_weather", + "success": true, + "durationMs": 42, + "errorKind": "timeout" +} +` + + instance, err := prompty.ToolCallCompletePayloadFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load ToolCallCompletePayload from JSON helper: %v", err) + } + if instance.Id == nil || *instance.Id != "call_abc123" { + t.Errorf(`Expected Id to be "call_abc123", got %v`, instance.Id) + } + if instance.Name != "get_weather" { + t.Errorf(`Expected Name to be "get_weather", got %v`, instance.Name) + } + if instance.Success != true { + t.Errorf(`Expected Success to be true, got %v`, instance.Success) + } + if instance.DurationMs == nil || *instance.DurationMs != 42 { + t.Errorf(`Expected DurationMs to be 42, got %v`, instance.DurationMs) + } + if instance.ErrorKind == nil || *instance.ErrorKind != "timeout" { + t.Errorf(`Expected ErrorKind to be "timeout", got %v`, instance.ErrorKind) + } +} + +// TestToolCallCompletePayloadFromYAML tests loading ToolCallCompletePayload through the generated YAML helper +func TestToolCallCompletePayloadFromYAML(t *testing.T) { + yamlData := ` +id: call_abc123 +name: get_weather +success: true +durationMs: 42 +errorKind: timeout + +` + + instance, err := prompty.ToolCallCompletePayloadFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load ToolCallCompletePayload from YAML helper: %v", err) + } + if instance.Id == nil || *instance.Id != "call_abc123" { + t.Errorf(`Expected Id to be "call_abc123", got %v`, instance.Id) + } + if instance.Name != "get_weather" { + t.Errorf(`Expected Name to be "get_weather", got %v`, instance.Name) + } + if instance.Success != true { + t.Errorf(`Expected Success to be true, got %v`, instance.Success) + } + if instance.DurationMs == nil || *instance.DurationMs != 42 { + t.Errorf(`Expected DurationMs to be 42, got %v`, instance.DurationMs) + } + if instance.ErrorKind == nil || *instance.ErrorKind != "timeout" { + t.Errorf(`Expected ErrorKind to be "timeout", got %v`, instance.ErrorKind) + } +} + // TestToolCallCompletePayloadRoundtrip tests load -> save -> load produces equivalent data func TestToolCallCompletePayloadRoundtrip(t *testing.T) { jsonData := ` @@ -162,6 +227,26 @@ func TestToolCallCompletePayloadToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadToolCallCompletePayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Id == nil || *reloaded.Id != "call_abc123" { + t.Errorf(`Expected Id to be "call_abc123", got %v`, reloaded.Id) + } + if reloaded.Name != "get_weather" { + t.Errorf(`Expected Name to be "get_weather", got %v`, reloaded.Name) + } + if reloaded.Success != true { + t.Errorf(`Expected Success to be true, got %v`, reloaded.Success) + } + if reloaded.DurationMs == nil || *reloaded.DurationMs != 42 { + t.Errorf(`Expected DurationMs to be 42, got %v`, reloaded.DurationMs) + } + if reloaded.ErrorKind == nil || *reloaded.ErrorKind != "timeout" { + t.Errorf(`Expected ErrorKind to be "timeout", got %v`, reloaded.ErrorKind) + } } // TestToolCallCompletePayloadToYAML tests that ToYAML produces valid YAML @@ -194,4 +279,31 @@ func TestToolCallCompletePayloadToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadToolCallCompletePayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Id == nil || *reloaded.Id != "call_abc123" { + t.Errorf(`Expected Id to be "call_abc123", got %v`, reloaded.Id) + } + if reloaded.Name != "get_weather" { + t.Errorf(`Expected Name to be "get_weather", got %v`, reloaded.Name) + } + if reloaded.Success != true { + t.Errorf(`Expected Success to be true, got %v`, reloaded.Success) + } + if reloaded.DurationMs == nil || *reloaded.DurationMs != 42 { + t.Errorf(`Expected DurationMs to be 42, got %v`, reloaded.DurationMs) + } + if reloaded.ErrorKind == nil || *reloaded.ErrorKind != "timeout" { + t.Errorf(`Expected ErrorKind to be "timeout", got %v`, reloaded.ErrorKind) + } +} + +// TestToolCallCompletePayloadFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestToolCallCompletePayloadFromJSONInvalid(t *testing.T) { + if _, err := prompty.ToolCallCompletePayloadFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/tool_call_start_payload.go b/runtime/go/prompty/model/tool_call_start_payload.go index 6817a60a..87e23f1f 100644 --- a/runtime/go/prompty/model/tool_call_start_payload.go +++ b/runtime/go/prompty/model/tool_call_start_payload.go @@ -40,7 +40,7 @@ func LoadToolCallStartPayload(data interface{}, ctx *LoadContext) (ToolCallStart } // Save serializes ToolCallStartPayload to map[string]interface{} -func (obj *ToolCallStartPayload) Save(ctx *SaveContext) map[string]interface{} { +func (obj ToolCallStartPayload) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) if obj.Id != nil { result["id"] = *obj.Id @@ -66,11 +66,7 @@ func (obj *ToolCallStartPayload) ToJSON() (string, error) { func (obj *ToolCallStartPayload) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates ToolCallStartPayload from JSON string diff --git a/runtime/go/prompty/model/tool_call_start_payload_test.go b/runtime/go/prompty/model/tool_call_start_payload_test.go index e3a534b0..70ae6cef 100644 --- a/runtime/go/prompty/model/tool_call_start_payload_test.go +++ b/runtime/go/prompty/model/tool_call_start_payload_test.go @@ -71,6 +71,55 @@ arguments: "{\"city\": \"Paris\"}" } } +// TestToolCallStartPayloadFromJSON tests loading ToolCallStartPayload through the generated JSON helper +func TestToolCallStartPayloadFromJSON(t *testing.T) { + jsonData := ` +{ + "id": "call_abc123", + "name": "get_weather", + "arguments": "{\"city\": \"Paris\"}" +} +` + + instance, err := prompty.ToolCallStartPayloadFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load ToolCallStartPayload from JSON helper: %v", err) + } + if instance.Id == nil || *instance.Id != "call_abc123" { + t.Errorf(`Expected Id to be "call_abc123", got %v`, instance.Id) + } + if instance.Name != "get_weather" { + t.Errorf(`Expected Name to be "get_weather", got %v`, instance.Name) + } + if instance.Arguments != "{\"city\": \"Paris\"}" { + t.Errorf(`Expected Arguments to be "{\"city\": \"Paris\"}", got %v`, instance.Arguments) + } +} + +// TestToolCallStartPayloadFromYAML tests loading ToolCallStartPayload through the generated YAML helper +func TestToolCallStartPayloadFromYAML(t *testing.T) { + yamlData := ` +id: call_abc123 +name: get_weather +arguments: "{\"city\": \"Paris\"}" + +` + + instance, err := prompty.ToolCallStartPayloadFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load ToolCallStartPayload from YAML helper: %v", err) + } + if instance.Id == nil || *instance.Id != "call_abc123" { + t.Errorf(`Expected Id to be "call_abc123", got %v`, instance.Id) + } + if instance.Name != "get_weather" { + t.Errorf(`Expected Name to be "get_weather", got %v`, instance.Name) + } + if instance.Arguments != "{\"city\": \"Paris\"}" { + t.Errorf(`Expected Arguments to be "{\"city\": \"Paris\"}", got %v`, instance.Arguments) + } +} + // TestToolCallStartPayloadRoundtrip tests load -> save -> load produces equivalent data func TestToolCallStartPayloadRoundtrip(t *testing.T) { jsonData := ` @@ -136,6 +185,20 @@ func TestToolCallStartPayloadToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadToolCallStartPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Id == nil || *reloaded.Id != "call_abc123" { + t.Errorf(`Expected Id to be "call_abc123", got %v`, reloaded.Id) + } + if reloaded.Name != "get_weather" { + t.Errorf(`Expected Name to be "get_weather", got %v`, reloaded.Name) + } + if reloaded.Arguments != "{\"city\": \"Paris\"}" { + t.Errorf(`Expected Arguments to be "{\"city\": \"Paris\"}", got %v`, reloaded.Arguments) + } } // TestToolCallStartPayloadToYAML tests that ToYAML produces valid YAML @@ -166,4 +229,25 @@ func TestToolCallStartPayloadToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadToolCallStartPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Id == nil || *reloaded.Id != "call_abc123" { + t.Errorf(`Expected Id to be "call_abc123", got %v`, reloaded.Id) + } + if reloaded.Name != "get_weather" { + t.Errorf(`Expected Name to be "get_weather", got %v`, reloaded.Name) + } + if reloaded.Arguments != "{\"city\": \"Paris\"}" { + t.Errorf(`Expected Arguments to be "{\"city\": \"Paris\"}", got %v`, reloaded.Arguments) + } +} + +// TestToolCallStartPayloadFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestToolCallStartPayloadFromJSONInvalid(t *testing.T) { + if _, err := prompty.ToolCallStartPayloadFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/tool_call_test.go b/runtime/go/prompty/model/tool_call_test.go index 7585868e..691a2a89 100644 --- a/runtime/go/prompty/model/tool_call_test.go +++ b/runtime/go/prompty/model/tool_call_test.go @@ -71,6 +71,55 @@ arguments: "{\"city\": \"Paris\"}" } } +// TestToolCallFromJSON tests loading ToolCall through the generated JSON helper +func TestToolCallFromJSON(t *testing.T) { + jsonData := ` +{ + "id": "call_abc123", + "name": "get_weather", + "arguments": "{\"city\": \"Paris\"}" +} +` + + instance, err := prompty.ToolCallFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load ToolCall from JSON helper: %v", err) + } + if instance.Id != "call_abc123" { + t.Errorf(`Expected Id to be "call_abc123", got %v`, instance.Id) + } + if instance.Name != "get_weather" { + t.Errorf(`Expected Name to be "get_weather", got %v`, instance.Name) + } + if instance.Arguments != "{\"city\": \"Paris\"}" { + t.Errorf(`Expected Arguments to be "{\"city\": \"Paris\"}", got %v`, instance.Arguments) + } +} + +// TestToolCallFromYAML tests loading ToolCall through the generated YAML helper +func TestToolCallFromYAML(t *testing.T) { + yamlData := ` +id: call_abc123 +name: get_weather +arguments: "{\"city\": \"Paris\"}" + +` + + instance, err := prompty.ToolCallFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load ToolCall from YAML helper: %v", err) + } + if instance.Id != "call_abc123" { + t.Errorf(`Expected Id to be "call_abc123", got %v`, instance.Id) + } + if instance.Name != "get_weather" { + t.Errorf(`Expected Name to be "get_weather", got %v`, instance.Name) + } + if instance.Arguments != "{\"city\": \"Paris\"}" { + t.Errorf(`Expected Arguments to be "{\"city\": \"Paris\"}", got %v`, instance.Arguments) + } +} + // TestToolCallRoundtrip tests load -> save -> load produces equivalent data func TestToolCallRoundtrip(t *testing.T) { jsonData := ` @@ -136,6 +185,20 @@ func TestToolCallToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadToolCall(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Id != "call_abc123" { + t.Errorf(`Expected Id to be "call_abc123", got %v`, reloaded.Id) + } + if reloaded.Name != "get_weather" { + t.Errorf(`Expected Name to be "get_weather", got %v`, reloaded.Name) + } + if reloaded.Arguments != "{\"city\": \"Paris\"}" { + t.Errorf(`Expected Arguments to be "{\"city\": \"Paris\"}", got %v`, reloaded.Arguments) + } } // TestToolCallToYAML tests that ToYAML produces valid YAML @@ -166,4 +229,25 @@ func TestToolCallToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadToolCall(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Id != "call_abc123" { + t.Errorf(`Expected Id to be "call_abc123", got %v`, reloaded.Id) + } + if reloaded.Name != "get_weather" { + t.Errorf(`Expected Name to be "get_weather", got %v`, reloaded.Name) + } + if reloaded.Arguments != "{\"city\": \"Paris\"}" { + t.Errorf(`Expected Arguments to be "{\"city\": \"Paris\"}", got %v`, reloaded.Arguments) + } +} + +// TestToolCallFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestToolCallFromJSONInvalid(t *testing.T) { + if _, err := prompty.ToolCallFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/tool_chunk_test.go b/runtime/go/prompty/model/tool_chunk_test.go index 0bc09c61..3ce05079 100644 --- a/runtime/go/prompty/model/tool_chunk_test.go +++ b/runtime/go/prompty/model/tool_chunk_test.go @@ -34,6 +34,15 @@ func TestToolChunkLoadJSON(t *testing.T) { t.Fatalf("Failed to load ToolChunk: %v", err) } _ = instance // No scalar properties to validate + if instance.ToolCall.Id != "call_abc123" { + t.Errorf(`Expected ToolCall.Id to be "call_abc123", got %v`, instance.ToolCall.Id) + } + if instance.ToolCall.Name != "get_weather" { + t.Errorf(`Expected ToolCall.Name to be "get_weather", got %v`, instance.ToolCall.Name) + } + if instance.ToolCall.Arguments != "{\"city\": \"Paris\"}" { + t.Errorf(`Expected ToolCall.Arguments to be "{\"city\": \"Paris\"}", got %v`, instance.ToolCall.Arguments) + } } // TestToolChunkLoadYAML tests loading ToolChunk from YAML @@ -56,6 +65,69 @@ toolCall: t.Fatalf("Failed to load ToolChunk: %v", err) } _ = instance // No scalar properties to validate + if instance.ToolCall.Id != "call_abc123" { + t.Errorf(`Expected ToolCall.Id to be "call_abc123", got %v`, instance.ToolCall.Id) + } + if instance.ToolCall.Name != "get_weather" { + t.Errorf(`Expected ToolCall.Name to be "get_weather", got %v`, instance.ToolCall.Name) + } + if instance.ToolCall.Arguments != "{\"city\": \"Paris\"}" { + t.Errorf(`Expected ToolCall.Arguments to be "{\"city\": \"Paris\"}", got %v`, instance.ToolCall.Arguments) + } +} + +// TestToolChunkFromJSON tests loading ToolChunk through the generated JSON helper +func TestToolChunkFromJSON(t *testing.T) { + jsonData := ` +{ + "toolCall": { + "id": "call_abc123", + "name": "get_weather", + "arguments": "{\"city\": \"Paris\"}" + } +} +` + + instance, err := prompty.ToolChunkFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load ToolChunk from JSON helper: %v", err) + } + _ = instance // No scalar properties to validate + if instance.ToolCall.Id != "call_abc123" { + t.Errorf(`Expected ToolCall.Id to be "call_abc123", got %v`, instance.ToolCall.Id) + } + if instance.ToolCall.Name != "get_weather" { + t.Errorf(`Expected ToolCall.Name to be "get_weather", got %v`, instance.ToolCall.Name) + } + if instance.ToolCall.Arguments != "{\"city\": \"Paris\"}" { + t.Errorf(`Expected ToolCall.Arguments to be "{\"city\": \"Paris\"}", got %v`, instance.ToolCall.Arguments) + } +} + +// TestToolChunkFromYAML tests loading ToolChunk through the generated YAML helper +func TestToolChunkFromYAML(t *testing.T) { + yamlData := ` +toolCall: + id: call_abc123 + name: get_weather + arguments: "{\"city\": \"Paris\"}" + +` + + instance, err := prompty.ToolChunkFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load ToolChunk from YAML helper: %v", err) + } + _ = instance // No scalar properties to validate + if instance.ToolCall.Id != "call_abc123" { + t.Errorf(`Expected ToolCall.Id to be "call_abc123", got %v`, instance.ToolCall.Id) + } + if instance.ToolCall.Name != "get_weather" { + t.Errorf(`Expected ToolCall.Name to be "get_weather", got %v`, instance.ToolCall.Name) + } + if instance.ToolCall.Arguments != "{\"city\": \"Paris\"}" { + t.Errorf(`Expected ToolCall.Arguments to be "{\"city\": \"Paris\"}", got %v`, instance.ToolCall.Arguments) + } } // TestToolChunkRoundtrip tests load -> save -> load produces equivalent data @@ -87,6 +159,15 @@ func TestToolChunkRoundtrip(t *testing.T) { t.Fatalf("Failed to reload ToolChunk: %v", err) } _ = reloaded // No scalar properties to validate + if reloaded.ToolCall.Id != "call_abc123" { + t.Errorf(`Expected ToolCall.Id to be "call_abc123", got %v`, reloaded.ToolCall.Id) + } + if reloaded.ToolCall.Name != "get_weather" { + t.Errorf(`Expected ToolCall.Name to be "get_weather", got %v`, reloaded.ToolCall.Name) + } + if reloaded.ToolCall.Arguments != "{\"city\": \"Paris\"}" { + t.Errorf(`Expected ToolCall.Arguments to be "{\"city\": \"Paris\"}", got %v`, reloaded.ToolCall.Arguments) + } } // TestToolChunkToJSON tests that ToJSON produces valid JSON @@ -119,6 +200,21 @@ func TestToolChunkToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadToolChunk(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + _ = reloaded // No scalar properties to validate + if reloaded.ToolCall.Id != "call_abc123" { + t.Errorf(`Expected ToolCall.Id to be "call_abc123", got %v`, reloaded.ToolCall.Id) + } + if reloaded.ToolCall.Name != "get_weather" { + t.Errorf(`Expected ToolCall.Name to be "get_weather", got %v`, reloaded.ToolCall.Name) + } + if reloaded.ToolCall.Arguments != "{\"city\": \"Paris\"}" { + t.Errorf(`Expected ToolCall.Arguments to be "{\"city\": \"Paris\"}", got %v`, reloaded.ToolCall.Arguments) + } } // TestToolChunkToYAML tests that ToYAML produces valid YAML @@ -151,4 +247,26 @@ func TestToolChunkToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadToolChunk(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + _ = reloaded // No scalar properties to validate + if reloaded.ToolCall.Id != "call_abc123" { + t.Errorf(`Expected ToolCall.Id to be "call_abc123", got %v`, reloaded.ToolCall.Id) + } + if reloaded.ToolCall.Name != "get_weather" { + t.Errorf(`Expected ToolCall.Name to be "get_weather", got %v`, reloaded.ToolCall.Name) + } + if reloaded.ToolCall.Arguments != "{\"city\": \"Paris\"}" { + t.Errorf(`Expected ToolCall.Arguments to be "{\"city\": \"Paris\"}", got %v`, reloaded.ToolCall.Arguments) + } +} + +// TestToolChunkFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestToolChunkFromJSONInvalid(t *testing.T) { + if _, err := prompty.ToolChunkFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/tool_context.go b/runtime/go/prompty/model/tool_context.go index 777f98ff..cde2c7b6 100644 --- a/runtime/go/prompty/model/tool_context.go +++ b/runtime/go/prompty/model/tool_context.go @@ -47,7 +47,7 @@ func LoadToolContext(data interface{}, ctx *LoadContext) (ToolContext, error) { } // Save serializes ToolContext to map[string]interface{} -func (obj *ToolContext) Save(ctx *SaveContext) map[string]interface{} { +func (obj ToolContext) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) if obj.Messages != nil { arr := make([]interface{}, len(obj.Messages)) @@ -78,11 +78,7 @@ func (obj *ToolContext) ToJSON() (string, error) { func (obj *ToolContext) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates ToolContext from JSON string diff --git a/runtime/go/prompty/model/tool_context_test.go b/runtime/go/prompty/model/tool_context_test.go index 5a45f2f1..b106068a 100644 --- a/runtime/go/prompty/model/tool_context_test.go +++ b/runtime/go/prompty/model/tool_context_test.go @@ -32,6 +32,12 @@ func TestToolContextLoadJSON(t *testing.T) { t.Fatalf("Failed to load ToolContext: %v", err) } _ = instance // No scalar properties to validate + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if got := instance.Metadata["userId"]; got != "user-123" { + t.Errorf(`Expected Metadata["userId"] to be "user-123", got %v`, got) + } } // TestToolContextLoadYAML tests loading ToolContext from YAML @@ -52,6 +58,56 @@ metadata: t.Fatalf("Failed to load ToolContext: %v", err) } _ = instance // No scalar properties to validate + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if got := instance.Metadata["userId"]; got != "user-123" { + t.Errorf(`Expected Metadata["userId"] to be "user-123", got %v`, got) + } +} + +// TestToolContextFromJSON tests loading ToolContext through the generated JSON helper +func TestToolContextFromJSON(t *testing.T) { + jsonData := ` +{ + "metadata": { + "userId": "user-123" + } +} +` + + instance, err := prompty.ToolContextFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load ToolContext from JSON helper: %v", err) + } + _ = instance // No scalar properties to validate + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if got := instance.Metadata["userId"]; got != "user-123" { + t.Errorf(`Expected Metadata["userId"] to be "user-123", got %v`, got) + } +} + +// TestToolContextFromYAML tests loading ToolContext through the generated YAML helper +func TestToolContextFromYAML(t *testing.T) { + yamlData := ` +metadata: + userId: user-123 + +` + + instance, err := prompty.ToolContextFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load ToolContext from YAML helper: %v", err) + } + _ = instance // No scalar properties to validate + if instance.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if got := instance.Metadata["userId"]; got != "user-123" { + t.Errorf(`Expected Metadata["userId"] to be "user-123", got %v`, got) + } } // TestToolContextRoundtrip tests load -> save -> load produces equivalent data @@ -81,6 +137,12 @@ func TestToolContextRoundtrip(t *testing.T) { t.Fatalf("Failed to reload ToolContext: %v", err) } _ = reloaded // No scalar properties to validate + if reloaded.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if got := reloaded.Metadata["userId"]; got != "user-123" { + t.Errorf(`Expected Metadata["userId"] to be "user-123", got %v`, got) + } } // TestToolContextToJSON tests that ToJSON produces valid JSON @@ -111,6 +173,18 @@ func TestToolContextToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadToolContext(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + _ = reloaded // No scalar properties to validate + if reloaded.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if got := reloaded.Metadata["userId"]; got != "user-123" { + t.Errorf(`Expected Metadata["userId"] to be "user-123", got %v`, got) + } } // TestToolContextToYAML tests that ToYAML produces valid YAML @@ -141,4 +215,23 @@ func TestToolContextToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadToolContext(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + _ = reloaded // No scalar properties to validate + if reloaded.Metadata == nil { + t.Fatalf("Expected Metadata to be populated") + } + if got := reloaded.Metadata["userId"]; got != "user-123" { + t.Errorf(`Expected Metadata["userId"] to be "user-123", got %v`, got) + } +} + +// TestToolContextFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestToolContextFromJSONInvalid(t *testing.T) { + if _, err := prompty.ToolContextFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/tool_dispatch_result.go b/runtime/go/prompty/model/tool_dispatch_result.go index 95985a8f..4a52b4a0 100644 --- a/runtime/go/prompty/model/tool_dispatch_result.go +++ b/runtime/go/prompty/model/tool_dispatch_result.go @@ -44,7 +44,7 @@ func LoadToolDispatchResult(data interface{}, ctx *LoadContext) (ToolDispatchRes } // Save serializes ToolDispatchResult to map[string]interface{} -func (obj *ToolDispatchResult) Save(ctx *SaveContext) map[string]interface{} { +func (obj ToolDispatchResult) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["toolCallId"] = obj.ToolCallId result["name"] = obj.Name @@ -69,11 +69,7 @@ func (obj *ToolDispatchResult) ToJSON() (string, error) { func (obj *ToolDispatchResult) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates ToolDispatchResult from JSON string diff --git a/runtime/go/prompty/model/tool_dispatch_result_test.go b/runtime/go/prompty/model/tool_dispatch_result_test.go index 939045dc..0d74571e 100644 --- a/runtime/go/prompty/model/tool_dispatch_result_test.go +++ b/runtime/go/prompty/model/tool_dispatch_result_test.go @@ -75,6 +75,59 @@ result: } } +// TestToolDispatchResultFromJSON tests loading ToolDispatchResult through the generated JSON helper +func TestToolDispatchResultFromJSON(t *testing.T) { + jsonData := ` +{ + "toolCallId": "call_abc123", + "name": "get_weather", + "result": { + "parts": [ + { + "kind": "text", + "value": "72°F and sunny" + } + ] + } +} +` + + instance, err := prompty.ToolDispatchResultFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load ToolDispatchResult from JSON helper: %v", err) + } + if instance.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, instance.ToolCallId) + } + if instance.Name != "get_weather" { + t.Errorf(`Expected Name to be "get_weather", got %v`, instance.Name) + } +} + +// TestToolDispatchResultFromYAML tests loading ToolDispatchResult through the generated YAML helper +func TestToolDispatchResultFromYAML(t *testing.T) { + yamlData := ` +toolCallId: call_abc123 +name: get_weather +result: + parts: + - kind: text + value: 72°F and sunny + +` + + instance, err := prompty.ToolDispatchResultFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load ToolDispatchResult from YAML helper: %v", err) + } + if instance.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, instance.ToolCallId) + } + if instance.Name != "get_weather" { + t.Errorf(`Expected Name to be "get_weather", got %v`, instance.Name) + } +} + // TestToolDispatchResultRoundtrip tests load -> save -> load produces equivalent data func TestToolDispatchResultRoundtrip(t *testing.T) { jsonData := ` @@ -151,6 +204,17 @@ func TestToolDispatchResultToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadToolDispatchResult(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, reloaded.ToolCallId) + } + if reloaded.Name != "get_weather" { + t.Errorf(`Expected Name to be "get_weather", got %v`, reloaded.Name) + } } // TestToolDispatchResultToYAML tests that ToYAML produces valid YAML @@ -188,4 +252,22 @@ func TestToolDispatchResultToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadToolDispatchResult(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, reloaded.ToolCallId) + } + if reloaded.Name != "get_weather" { + t.Errorf(`Expected Name to be "get_weather", got %v`, reloaded.Name) + } +} + +// TestToolDispatchResultFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestToolDispatchResultFromJSONInvalid(t *testing.T) { + if _, err := prompty.ToolDispatchResultFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/tool_execution_complete_payload.go b/runtime/go/prompty/model/tool_execution_complete_payload.go index 9bd9d1b7..bee0b54b 100644 --- a/runtime/go/prompty/model/tool_execution_complete_payload.go +++ b/runtime/go/prompty/model/tool_execution_complete_payload.go @@ -99,7 +99,7 @@ func LoadToolExecutionCompletePayload(data interface{}, ctx *LoadContext) (ToolE } // Save serializes ToolExecutionCompletePayload to map[string]interface{} -func (obj *ToolExecutionCompletePayload) Save(ctx *SaveContext) map[string]interface{} { +func (obj ToolExecutionCompletePayload) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) if obj.RequestId != nil { result["requestId"] = *obj.RequestId @@ -146,11 +146,7 @@ func (obj *ToolExecutionCompletePayload) ToJSON() (string, error) { func (obj *ToolExecutionCompletePayload) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates ToolExecutionCompletePayload from JSON string diff --git a/runtime/go/prompty/model/tool_execution_complete_payload_test.go b/runtime/go/prompty/model/tool_execution_complete_payload_test.go index 67c89554..6f481ee3 100644 --- a/runtime/go/prompty/model/tool_execution_complete_payload_test.go +++ b/runtime/go/prompty/model/tool_execution_complete_payload_test.go @@ -103,6 +103,87 @@ errorKind: timeout } } +// TestToolExecutionCompletePayloadFromJSON tests loading ToolExecutionCompletePayload through the generated JSON helper +func TestToolExecutionCompletePayloadFromJSON(t *testing.T) { + jsonData := ` +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "success": true, + "exitCode": 0, + "durationMs": 250, + "errorKind": "timeout" +} +` + + instance, err := prompty.ToolExecutionCompletePayloadFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load ToolExecutionCompletePayload from JSON helper: %v", err) + } + if instance.RequestId == nil || *instance.RequestId != "exec_abc123" { + t.Errorf(`Expected RequestId to be "exec_abc123", got %v`, instance.RequestId) + } + if instance.ToolCallId == nil || *instance.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, instance.ToolCallId) + } + if instance.ToolName != "powershell" { + t.Errorf(`Expected ToolName to be "powershell", got %v`, instance.ToolName) + } + if instance.Success != true { + t.Errorf(`Expected Success to be true, got %v`, instance.Success) + } + if instance.ExitCode == nil || *instance.ExitCode != 0 { + t.Errorf(`Expected ExitCode to be 0, got %v`, instance.ExitCode) + } + if instance.DurationMs == nil || *instance.DurationMs != 250 { + t.Errorf(`Expected DurationMs to be 250, got %v`, instance.DurationMs) + } + if instance.ErrorKind == nil || *instance.ErrorKind != "timeout" { + t.Errorf(`Expected ErrorKind to be "timeout", got %v`, instance.ErrorKind) + } +} + +// TestToolExecutionCompletePayloadFromYAML tests loading ToolExecutionCompletePayload through the generated YAML helper +func TestToolExecutionCompletePayloadFromYAML(t *testing.T) { + yamlData := ` +requestId: exec_abc123 +toolCallId: call_abc123 +toolName: powershell +success: true +exitCode: 0 +durationMs: 250 +errorKind: timeout + +` + + instance, err := prompty.ToolExecutionCompletePayloadFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load ToolExecutionCompletePayload from YAML helper: %v", err) + } + if instance.RequestId == nil || *instance.RequestId != "exec_abc123" { + t.Errorf(`Expected RequestId to be "exec_abc123", got %v`, instance.RequestId) + } + if instance.ToolCallId == nil || *instance.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, instance.ToolCallId) + } + if instance.ToolName != "powershell" { + t.Errorf(`Expected ToolName to be "powershell", got %v`, instance.ToolName) + } + if instance.Success != true { + t.Errorf(`Expected Success to be true, got %v`, instance.Success) + } + if instance.ExitCode == nil || *instance.ExitCode != 0 { + t.Errorf(`Expected ExitCode to be 0, got %v`, instance.ExitCode) + } + if instance.DurationMs == nil || *instance.DurationMs != 250 { + t.Errorf(`Expected DurationMs to be 250, got %v`, instance.DurationMs) + } + if instance.ErrorKind == nil || *instance.ErrorKind != "timeout" { + t.Errorf(`Expected ErrorKind to be "timeout", got %v`, instance.ErrorKind) + } +} + // TestToolExecutionCompletePayloadRoundtrip tests load -> save -> load produces equivalent data func TestToolExecutionCompletePayloadRoundtrip(t *testing.T) { jsonData := ` @@ -188,6 +269,32 @@ func TestToolExecutionCompletePayloadToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadToolExecutionCompletePayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.RequestId == nil || *reloaded.RequestId != "exec_abc123" { + t.Errorf(`Expected RequestId to be "exec_abc123", got %v`, reloaded.RequestId) + } + if reloaded.ToolCallId == nil || *reloaded.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, reloaded.ToolCallId) + } + if reloaded.ToolName != "powershell" { + t.Errorf(`Expected ToolName to be "powershell", got %v`, reloaded.ToolName) + } + if reloaded.Success != true { + t.Errorf(`Expected Success to be true, got %v`, reloaded.Success) + } + if reloaded.ExitCode == nil || *reloaded.ExitCode != 0 { + t.Errorf(`Expected ExitCode to be 0, got %v`, reloaded.ExitCode) + } + if reloaded.DurationMs == nil || *reloaded.DurationMs != 250 { + t.Errorf(`Expected DurationMs to be 250, got %v`, reloaded.DurationMs) + } + if reloaded.ErrorKind == nil || *reloaded.ErrorKind != "timeout" { + t.Errorf(`Expected ErrorKind to be "timeout", got %v`, reloaded.ErrorKind) + } } // TestToolExecutionCompletePayloadToYAML tests that ToYAML produces valid YAML @@ -222,4 +329,37 @@ func TestToolExecutionCompletePayloadToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadToolExecutionCompletePayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.RequestId == nil || *reloaded.RequestId != "exec_abc123" { + t.Errorf(`Expected RequestId to be "exec_abc123", got %v`, reloaded.RequestId) + } + if reloaded.ToolCallId == nil || *reloaded.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, reloaded.ToolCallId) + } + if reloaded.ToolName != "powershell" { + t.Errorf(`Expected ToolName to be "powershell", got %v`, reloaded.ToolName) + } + if reloaded.Success != true { + t.Errorf(`Expected Success to be true, got %v`, reloaded.Success) + } + if reloaded.ExitCode == nil || *reloaded.ExitCode != 0 { + t.Errorf(`Expected ExitCode to be 0, got %v`, reloaded.ExitCode) + } + if reloaded.DurationMs == nil || *reloaded.DurationMs != 250 { + t.Errorf(`Expected DurationMs to be 250, got %v`, reloaded.DurationMs) + } + if reloaded.ErrorKind == nil || *reloaded.ErrorKind != "timeout" { + t.Errorf(`Expected ErrorKind to be "timeout", got %v`, reloaded.ErrorKind) + } +} + +// TestToolExecutionCompletePayloadFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestToolExecutionCompletePayloadFromJSONInvalid(t *testing.T) { + if _, err := prompty.ToolExecutionCompletePayloadFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/tool_execution_start_payload.go b/runtime/go/prompty/model/tool_execution_start_payload.go index 5ae0ebe9..a1e9c88a 100644 --- a/runtime/go/prompty/model/tool_execution_start_payload.go +++ b/runtime/go/prompty/model/tool_execution_start_payload.go @@ -62,7 +62,7 @@ func LoadToolExecutionStartPayload(data interface{}, ctx *LoadContext) (ToolExec } // Save serializes ToolExecutionStartPayload to map[string]interface{} -func (obj *ToolExecutionStartPayload) Save(ctx *SaveContext) map[string]interface{} { +func (obj ToolExecutionStartPayload) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) if obj.RequestId != nil { result["requestId"] = *obj.RequestId @@ -99,11 +99,7 @@ func (obj *ToolExecutionStartPayload) ToJSON() (string, error) { func (obj *ToolExecutionStartPayload) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates ToolExecutionStartPayload from JSON string diff --git a/runtime/go/prompty/model/tool_execution_start_payload_test.go b/runtime/go/prompty/model/tool_execution_start_payload_test.go index d9c425fc..48da0c52 100644 --- a/runtime/go/prompty/model/tool_execution_start_payload_test.go +++ b/runtime/go/prompty/model/tool_execution_start_payload_test.go @@ -79,6 +79,63 @@ workingDirectory: /workspace/project } } +// TestToolExecutionStartPayloadFromJSON tests loading ToolExecutionStartPayload through the generated JSON helper +func TestToolExecutionStartPayloadFromJSON(t *testing.T) { + jsonData := ` +{ + "requestId": "exec_abc123", + "toolCallId": "call_abc123", + "toolName": "powershell", + "workingDirectory": "/workspace/project" +} +` + + instance, err := prompty.ToolExecutionStartPayloadFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load ToolExecutionStartPayload from JSON helper: %v", err) + } + if instance.RequestId == nil || *instance.RequestId != "exec_abc123" { + t.Errorf(`Expected RequestId to be "exec_abc123", got %v`, instance.RequestId) + } + if instance.ToolCallId == nil || *instance.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, instance.ToolCallId) + } + if instance.ToolName != "powershell" { + t.Errorf(`Expected ToolName to be "powershell", got %v`, instance.ToolName) + } + if instance.WorkingDirectory == nil || *instance.WorkingDirectory != "/workspace/project" { + t.Errorf(`Expected WorkingDirectory to be "/workspace/project", got %v`, instance.WorkingDirectory) + } +} + +// TestToolExecutionStartPayloadFromYAML tests loading ToolExecutionStartPayload through the generated YAML helper +func TestToolExecutionStartPayloadFromYAML(t *testing.T) { + yamlData := ` +requestId: exec_abc123 +toolCallId: call_abc123 +toolName: powershell +workingDirectory: /workspace/project + +` + + instance, err := prompty.ToolExecutionStartPayloadFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load ToolExecutionStartPayload from YAML helper: %v", err) + } + if instance.RequestId == nil || *instance.RequestId != "exec_abc123" { + t.Errorf(`Expected RequestId to be "exec_abc123", got %v`, instance.RequestId) + } + if instance.ToolCallId == nil || *instance.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, instance.ToolCallId) + } + if instance.ToolName != "powershell" { + t.Errorf(`Expected ToolName to be "powershell", got %v`, instance.ToolName) + } + if instance.WorkingDirectory == nil || *instance.WorkingDirectory != "/workspace/project" { + t.Errorf(`Expected WorkingDirectory to be "/workspace/project", got %v`, instance.WorkingDirectory) + } +} + // TestToolExecutionStartPayloadRoundtrip tests load -> save -> load produces equivalent data func TestToolExecutionStartPayloadRoundtrip(t *testing.T) { jsonData := ` @@ -149,6 +206,23 @@ func TestToolExecutionStartPayloadToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadToolExecutionStartPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.RequestId == nil || *reloaded.RequestId != "exec_abc123" { + t.Errorf(`Expected RequestId to be "exec_abc123", got %v`, reloaded.RequestId) + } + if reloaded.ToolCallId == nil || *reloaded.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, reloaded.ToolCallId) + } + if reloaded.ToolName != "powershell" { + t.Errorf(`Expected ToolName to be "powershell", got %v`, reloaded.ToolName) + } + if reloaded.WorkingDirectory == nil || *reloaded.WorkingDirectory != "/workspace/project" { + t.Errorf(`Expected WorkingDirectory to be "/workspace/project", got %v`, reloaded.WorkingDirectory) + } } // TestToolExecutionStartPayloadToYAML tests that ToYAML produces valid YAML @@ -180,4 +254,28 @@ func TestToolExecutionStartPayloadToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadToolExecutionStartPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.RequestId == nil || *reloaded.RequestId != "exec_abc123" { + t.Errorf(`Expected RequestId to be "exec_abc123", got %v`, reloaded.RequestId) + } + if reloaded.ToolCallId == nil || *reloaded.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, reloaded.ToolCallId) + } + if reloaded.ToolName != "powershell" { + t.Errorf(`Expected ToolName to be "powershell", got %v`, reloaded.ToolName) + } + if reloaded.WorkingDirectory == nil || *reloaded.WorkingDirectory != "/workspace/project" { + t.Errorf(`Expected WorkingDirectory to be "/workspace/project", got %v`, reloaded.WorkingDirectory) + } +} + +// TestToolExecutionStartPayloadFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestToolExecutionStartPayloadFromJSONInvalid(t *testing.T) { + if _, err := prompty.ToolExecutionStartPayloadFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/tool_result.go b/runtime/go/prompty/model/tool_result.go index f5328808..9c91f409 100644 --- a/runtime/go/prompty/model/tool_result.go +++ b/runtime/go/prompty/model/tool_result.go @@ -86,7 +86,7 @@ func LoadToolResult(data interface{}, ctx *LoadContext) (ToolResult, error) { } // Save serializes ToolResult to map[string]interface{} -func (obj *ToolResult) Save(ctx *SaveContext) map[string]interface{} { +func (obj ToolResult) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) if obj.Parts != nil { arr := make([]interface{}, len(obj.Parts)) @@ -134,11 +134,7 @@ func (obj *ToolResult) ToJSON() (string, error) { func (obj *ToolResult) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates ToolResult from JSON string diff --git a/runtime/go/prompty/model/tool_result_payload.go b/runtime/go/prompty/model/tool_result_payload.go index 82b22b7e..3e5dfca5 100644 --- a/runtime/go/prompty/model/tool_result_payload.go +++ b/runtime/go/prompty/model/tool_result_payload.go @@ -38,7 +38,7 @@ func LoadToolResultPayload(data interface{}, ctx *LoadContext) (ToolResultPayloa } // Save serializes ToolResultPayload to map[string]interface{} -func (obj *ToolResultPayload) Save(ctx *SaveContext) map[string]interface{} { +func (obj ToolResultPayload) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["name"] = obj.Name @@ -62,11 +62,7 @@ func (obj *ToolResultPayload) ToJSON() (string, error) { func (obj *ToolResultPayload) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates ToolResultPayload from JSON string diff --git a/runtime/go/prompty/model/tool_result_payload_test.go b/runtime/go/prompty/model/tool_result_payload_test.go index 3052d58b..04670733 100644 --- a/runtime/go/prompty/model/tool_result_payload_test.go +++ b/runtime/go/prompty/model/tool_result_payload_test.go @@ -67,6 +67,51 @@ result: } } +// TestToolResultPayloadFromJSON tests loading ToolResultPayload through the generated JSON helper +func TestToolResultPayloadFromJSON(t *testing.T) { + jsonData := ` +{ + "name": "get_weather", + "result": { + "parts": [ + { + "kind": "text", + "value": "72°F and sunny" + } + ] + } +} +` + + instance, err := prompty.ToolResultPayloadFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load ToolResultPayload from JSON helper: %v", err) + } + if instance.Name != "get_weather" { + t.Errorf(`Expected Name to be "get_weather", got %v`, instance.Name) + } +} + +// TestToolResultPayloadFromYAML tests loading ToolResultPayload through the generated YAML helper +func TestToolResultPayloadFromYAML(t *testing.T) { + yamlData := ` +name: get_weather +result: + parts: + - kind: text + value: 72°F and sunny + +` + + instance, err := prompty.ToolResultPayloadFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load ToolResultPayload from YAML helper: %v", err) + } + if instance.Name != "get_weather" { + t.Errorf(`Expected Name to be "get_weather", got %v`, instance.Name) + } +} + // TestToolResultPayloadRoundtrip tests load -> save -> load produces equivalent data func TestToolResultPayloadRoundtrip(t *testing.T) { jsonData := ` @@ -138,6 +183,14 @@ func TestToolResultPayloadToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadToolResultPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Name != "get_weather" { + t.Errorf(`Expected Name to be "get_weather", got %v`, reloaded.Name) + } } // TestToolResultPayloadToYAML tests that ToYAML produces valid YAML @@ -174,4 +227,19 @@ func TestToolResultPayloadToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadToolResultPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Name != "get_weather" { + t.Errorf(`Expected Name to be "get_weather", got %v`, reloaded.Name) + } +} + +// TestToolResultPayloadFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestToolResultPayloadFromJSONInvalid(t *testing.T) { + if _, err := prompty.ToolResultPayloadFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/tool_result_test.go b/runtime/go/prompty/model/tool_result_test.go index dca5a445..5cf823fb 100644 --- a/runtime/go/prompty/model/tool_result_test.go +++ b/runtime/go/prompty/model/tool_result_test.go @@ -46,6 +46,19 @@ func TestToolResultLoadJSON(t *testing.T) { if instance.DurationMs == nil || *instance.DurationMs != 42 { t.Errorf(`Expected DurationMs to be 42, got %v`, instance.DurationMs) } + if len(instance.Parts) != 1 { + t.Fatalf("Expected Parts length to be 1, got %d", len(instance.Parts)) + } + parts0Value, ok := instance.Parts[0].(prompty.TextPart) + if !ok { + t.Fatalf("Expected Parts[0] to be prompty.TextPart, got %T", instance.Parts[0]) + } + if parts0Value.Kind != "text" { + t.Errorf(`Expected Kind to be "text", got %v`, parts0Value.Kind) + } + if parts0Value.Value != "72°F and sunny" { + t.Errorf(`Expected Value to be "72°F and sunny", got %v`, parts0Value.Value) + } } // TestToolResultLoadYAML tests loading ToolResult from YAML @@ -78,6 +91,103 @@ durationMs: 42 if instance.DurationMs == nil || *instance.DurationMs != 42 { t.Errorf(`Expected DurationMs to be 42, got %v`, instance.DurationMs) } + if len(instance.Parts) != 1 { + t.Fatalf("Expected Parts length to be 1, got %d", len(instance.Parts)) + } + parts0Value, ok := instance.Parts[0].(prompty.TextPart) + if !ok { + t.Fatalf("Expected Parts[0] to be prompty.TextPart, got %T", instance.Parts[0]) + } + if parts0Value.Kind != "text" { + t.Errorf(`Expected Kind to be "text", got %v`, parts0Value.Kind) + } + if parts0Value.Value != "72°F and sunny" { + t.Errorf(`Expected Value to be "72°F and sunny", got %v`, parts0Value.Value) + } +} + +// TestToolResultFromJSON tests loading ToolResult through the generated JSON helper +func TestToolResultFromJSON(t *testing.T) { + jsonData := ` +{ + "parts": [ + { + "kind": "text", + "value": "72°F and sunny" + } + ], + "errorKind": "missing_tool", + "errorMessage": "Tool 'get_weather' is not registered", + "durationMs": 42 +} +` + + instance, err := prompty.ToolResultFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load ToolResult from JSON helper: %v", err) + } + if instance.ErrorKind == nil || *instance.ErrorKind != "missing_tool" { + t.Errorf(`Expected ErrorKind to be "missing_tool", got %v`, instance.ErrorKind) + } + if instance.ErrorMessage == nil || *instance.ErrorMessage != "Tool 'get_weather' is not registered" { + t.Errorf(`Expected ErrorMessage to be "Tool 'get_weather' is not registered", got %v`, instance.ErrorMessage) + } + if instance.DurationMs == nil || *instance.DurationMs != 42 { + t.Errorf(`Expected DurationMs to be 42, got %v`, instance.DurationMs) + } + if len(instance.Parts) != 1 { + t.Fatalf("Expected Parts length to be 1, got %d", len(instance.Parts)) + } + parts0Value, ok := instance.Parts[0].(prompty.TextPart) + if !ok { + t.Fatalf("Expected Parts[0] to be prompty.TextPart, got %T", instance.Parts[0]) + } + if parts0Value.Kind != "text" { + t.Errorf(`Expected Kind to be "text", got %v`, parts0Value.Kind) + } + if parts0Value.Value != "72°F and sunny" { + t.Errorf(`Expected Value to be "72°F and sunny", got %v`, parts0Value.Value) + } +} + +// TestToolResultFromYAML tests loading ToolResult through the generated YAML helper +func TestToolResultFromYAML(t *testing.T) { + yamlData := ` +parts: + - kind: text + value: 72°F and sunny +errorKind: missing_tool +errorMessage: Tool 'get_weather' is not registered +durationMs: 42 + +` + + instance, err := prompty.ToolResultFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load ToolResult from YAML helper: %v", err) + } + if instance.ErrorKind == nil || *instance.ErrorKind != "missing_tool" { + t.Errorf(`Expected ErrorKind to be "missing_tool", got %v`, instance.ErrorKind) + } + if instance.ErrorMessage == nil || *instance.ErrorMessage != "Tool 'get_weather' is not registered" { + t.Errorf(`Expected ErrorMessage to be "Tool 'get_weather' is not registered", got %v`, instance.ErrorMessage) + } + if instance.DurationMs == nil || *instance.DurationMs != 42 { + t.Errorf(`Expected DurationMs to be 42, got %v`, instance.DurationMs) + } + if len(instance.Parts) != 1 { + t.Fatalf("Expected Parts length to be 1, got %d", len(instance.Parts)) + } + parts0Value, ok := instance.Parts[0].(prompty.TextPart) + if !ok { + t.Fatalf("Expected Parts[0] to be prompty.TextPart, got %T", instance.Parts[0]) + } + if parts0Value.Kind != "text" { + t.Errorf(`Expected Kind to be "text", got %v`, parts0Value.Kind) + } + if parts0Value.Value != "72°F and sunny" { + t.Errorf(`Expected Value to be "72°F and sunny", got %v`, parts0Value.Value) + } } // TestToolResultRoundtrip tests load -> save -> load produces equivalent data @@ -121,6 +231,19 @@ func TestToolResultRoundtrip(t *testing.T) { if reloaded.DurationMs == nil || *reloaded.DurationMs != 42 { t.Errorf(`Expected DurationMs to be 42, got %v`, reloaded.DurationMs) } + if len(reloaded.Parts) != 1 { + t.Fatalf("Expected Parts length to be 1, got %d", len(reloaded.Parts)) + } + parts0Value, ok := reloaded.Parts[0].(prompty.TextPart) + if !ok { + t.Fatalf("Expected Parts[0] to be prompty.TextPart, got %T", reloaded.Parts[0]) + } + if parts0Value.Kind != "text" { + t.Errorf(`Expected Kind to be "text", got %v`, parts0Value.Kind) + } + if parts0Value.Value != "72°F and sunny" { + t.Errorf(`Expected Value to be "72°F and sunny", got %v`, parts0Value.Value) + } } // TestToolResultToJSON tests that ToJSON produces valid JSON @@ -157,6 +280,33 @@ func TestToolResultToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadToolResult(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.ErrorKind == nil || *reloaded.ErrorKind != "missing_tool" { + t.Errorf(`Expected ErrorKind to be "missing_tool", got %v`, reloaded.ErrorKind) + } + if reloaded.ErrorMessage == nil || *reloaded.ErrorMessage != "Tool 'get_weather' is not registered" { + t.Errorf(`Expected ErrorMessage to be "Tool 'get_weather' is not registered", got %v`, reloaded.ErrorMessage) + } + if reloaded.DurationMs == nil || *reloaded.DurationMs != 42 { + t.Errorf(`Expected DurationMs to be 42, got %v`, reloaded.DurationMs) + } + if len(reloaded.Parts) != 1 { + t.Fatalf("Expected Parts length to be 1, got %d", len(reloaded.Parts)) + } + parts0Value, ok := reloaded.Parts[0].(prompty.TextPart) + if !ok { + t.Fatalf("Expected Parts[0] to be prompty.TextPart, got %T", reloaded.Parts[0]) + } + if parts0Value.Kind != "text" { + t.Errorf(`Expected Kind to be "text", got %v`, parts0Value.Kind) + } + if parts0Value.Value != "72°F and sunny" { + t.Errorf(`Expected Value to be "72°F and sunny", got %v`, parts0Value.Value) + } } // TestToolResultToYAML tests that ToYAML produces valid YAML @@ -193,4 +343,38 @@ func TestToolResultToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadToolResult(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.ErrorKind == nil || *reloaded.ErrorKind != "missing_tool" { + t.Errorf(`Expected ErrorKind to be "missing_tool", got %v`, reloaded.ErrorKind) + } + if reloaded.ErrorMessage == nil || *reloaded.ErrorMessage != "Tool 'get_weather' is not registered" { + t.Errorf(`Expected ErrorMessage to be "Tool 'get_weather' is not registered", got %v`, reloaded.ErrorMessage) + } + if reloaded.DurationMs == nil || *reloaded.DurationMs != 42 { + t.Errorf(`Expected DurationMs to be 42, got %v`, reloaded.DurationMs) + } + if len(reloaded.Parts) != 1 { + t.Fatalf("Expected Parts length to be 1, got %d", len(reloaded.Parts)) + } + parts0Value, ok := reloaded.Parts[0].(prompty.TextPart) + if !ok { + t.Fatalf("Expected Parts[0] to be prompty.TextPart, got %T", reloaded.Parts[0]) + } + if parts0Value.Kind != "text" { + t.Errorf(`Expected Kind to be "text", got %v`, parts0Value.Kind) + } + if parts0Value.Value != "72°F and sunny" { + t.Errorf(`Expected Value to be "72°F and sunny", got %v`, parts0Value.Value) + } +} + +// TestToolResultFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestToolResultFromJSONInvalid(t *testing.T) { + if _, err := prompty.ToolResultFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/tool_test.go b/runtime/go/prompty/model/tool_test.go index 8fd8866a..2c8f2653 100644 --- a/runtime/go/prompty/model/tool_test.go +++ b/runtime/go/prompty/model/tool_test.go @@ -64,6 +64,48 @@ bindings: // Note: Validation skipped for polymorphic base types - test child types directly } +// TestToolFromJSON tests loading Tool through the generated JSON helper +func TestToolFromJSON(t *testing.T) { + jsonData := ` +{ + "name": "my-tool", + "kind": "function", + "description": "A description of the tool", + "bindings": { + "input": "value" + } +} +` + + instance, err := prompty.ToolFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load Tool from JSON helper: %v", err) + } + // Polymorphic types return interface{}, extract common fields via reflection or type-specific access + _ = instance // Load succeeded, exact type depends on discriminator + // Note: Validation skipped for polymorphic base types - test child types directly +} + +// TestToolFromYAML tests loading Tool through the generated YAML helper +func TestToolFromYAML(t *testing.T) { + yamlData := ` +name: my-tool +kind: function +description: A description of the tool +bindings: + input: value + +` + + instance, err := prompty.ToolFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load Tool from YAML helper: %v", err) + } + // Polymorphic types return interface{}, extract common fields via reflection or type-specific access + _ = instance // Load succeeded, exact type depends on discriminator + // Note: Validation skipped for polymorphic base types - test child types directly +} + // TestToolRoundtrip tests load -> save -> load produces equivalent data func TestToolRoundtrip(t *testing.T) { jsonData := ` @@ -144,3 +186,10 @@ func TestToolToYAML(t *testing.T) { _ = instance // Load succeeded, exact type depends on discriminator // Note: ToYAML test skipped for polymorphic base types - test child types directly } + +// TestToolFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestToolFromJSONInvalid(t *testing.T) { + if _, err := prompty.ToolFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } +} diff --git a/runtime/go/prompty/model/trace_file.go b/runtime/go/prompty/model/trace_file.go index 829e85c6..2458a43c 100644 --- a/runtime/go/prompty/model/trace_file.go +++ b/runtime/go/prompty/model/trace_file.go @@ -42,7 +42,7 @@ func LoadTraceFile(data interface{}, ctx *LoadContext) (TraceFile, error) { } // Save serializes TraceFile to map[string]interface{} -func (obj *TraceFile) Save(ctx *SaveContext) map[string]interface{} { +func (obj TraceFile) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["runtime"] = obj.Runtime result["version"] = obj.Version @@ -67,11 +67,7 @@ func (obj *TraceFile) ToJSON() (string, error) { func (obj *TraceFile) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates TraceFile from JSON string diff --git a/runtime/go/prompty/model/trace_file_test.go b/runtime/go/prompty/model/trace_file_test.go index ca60fa81..4c10029e 100644 --- a/runtime/go/prompty/model/trace_file_test.go +++ b/runtime/go/prompty/model/trace_file_test.go @@ -63,6 +63,47 @@ version: 2.0.0 } } +// TestTraceFileFromJSON tests loading TraceFile through the generated JSON helper +func TestTraceFileFromJSON(t *testing.T) { + jsonData := ` +{ + "runtime": "python", + "version": "2.0.0" +} +` + + instance, err := prompty.TraceFileFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load TraceFile from JSON helper: %v", err) + } + if instance.Runtime != "python" { + t.Errorf(`Expected Runtime to be "python", got %v`, instance.Runtime) + } + if instance.Version != "2.0.0" { + t.Errorf(`Expected Version to be "2.0.0", got %v`, instance.Version) + } +} + +// TestTraceFileFromYAML tests loading TraceFile through the generated YAML helper +func TestTraceFileFromYAML(t *testing.T) { + yamlData := ` +runtime: python +version: 2.0.0 + +` + + instance, err := prompty.TraceFileFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load TraceFile from YAML helper: %v", err) + } + if instance.Runtime != "python" { + t.Errorf(`Expected Runtime to be "python", got %v`, instance.Runtime) + } + if instance.Version != "2.0.0" { + t.Errorf(`Expected Version to be "2.0.0", got %v`, instance.Version) + } +} + // TestTraceFileRoundtrip tests load -> save -> load produces equivalent data func TestTraceFileRoundtrip(t *testing.T) { jsonData := ` @@ -123,6 +164,17 @@ func TestTraceFileToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadTraceFile(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Runtime != "python" { + t.Errorf(`Expected Runtime to be "python", got %v`, reloaded.Runtime) + } + if reloaded.Version != "2.0.0" { + t.Errorf(`Expected Version to be "2.0.0", got %v`, reloaded.Version) + } } // TestTraceFileToYAML tests that ToYAML produces valid YAML @@ -152,4 +204,22 @@ func TestTraceFileToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadTraceFile(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Runtime != "python" { + t.Errorf(`Expected Runtime to be "python", got %v`, reloaded.Runtime) + } + if reloaded.Version != "2.0.0" { + t.Errorf(`Expected Version to be "2.0.0", got %v`, reloaded.Version) + } +} + +// TestTraceFileFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestTraceFileFromJSONInvalid(t *testing.T) { + if _, err := prompty.TraceFileFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/trace_span.go b/runtime/go/prompty/model/trace_span.go index 31ca0ca6..36210bf2 100644 --- a/runtime/go/prompty/model/trace_span.go +++ b/runtime/go/prompty/model/trace_span.go @@ -69,7 +69,8 @@ func LoadTraceSpan(data interface{}, ctx *LoadContext) (TraceSpan, error) { } } if val, ok := m["__frames"]; ok && val != nil { - if arr, ok := val.([]interface{}); ok { + switch arr := val.(type) { + case []interface{}: result._Frames = arr } } @@ -79,7 +80,7 @@ func LoadTraceSpan(data interface{}, ctx *LoadContext) (TraceSpan, error) { } // Save serializes TraceSpan to map[string]interface{} -func (obj *TraceSpan) Save(ctx *SaveContext) map[string]interface{} { +func (obj TraceSpan) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["name"] = obj.Name @@ -122,11 +123,7 @@ func (obj *TraceSpan) ToJSON() (string, error) { func (obj *TraceSpan) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates TraceSpan from JSON string diff --git a/runtime/go/prompty/model/trace_span_test.go b/runtime/go/prompty/model/trace_span_test.go index a1586656..530edfba 100644 --- a/runtime/go/prompty/model/trace_span_test.go +++ b/runtime/go/prompty/model/trace_span_test.go @@ -71,6 +71,55 @@ error: Connection refused } } +// TestTraceSpanFromJSON tests loading TraceSpan through the generated JSON helper +func TestTraceSpanFromJSON(t *testing.T) { + jsonData := ` +{ + "name": "prompty.core.pipeline.run", + "signature": "prompty.core.pipeline.run", + "error": "Connection refused" +} +` + + instance, err := prompty.TraceSpanFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load TraceSpan from JSON helper: %v", err) + } + if instance.Name != "prompty.core.pipeline.run" { + t.Errorf(`Expected Name to be "prompty.core.pipeline.run", got %v`, instance.Name) + } + if instance.Signature == nil || *instance.Signature != "prompty.core.pipeline.run" { + t.Errorf(`Expected Signature to be "prompty.core.pipeline.run", got %v`, instance.Signature) + } + if instance.Error == nil || *instance.Error != "Connection refused" { + t.Errorf(`Expected Error to be "Connection refused", got %v`, instance.Error) + } +} + +// TestTraceSpanFromYAML tests loading TraceSpan through the generated YAML helper +func TestTraceSpanFromYAML(t *testing.T) { + yamlData := ` +name: prompty.core.pipeline.run +signature: prompty.core.pipeline.run +error: Connection refused + +` + + instance, err := prompty.TraceSpanFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load TraceSpan from YAML helper: %v", err) + } + if instance.Name != "prompty.core.pipeline.run" { + t.Errorf(`Expected Name to be "prompty.core.pipeline.run", got %v`, instance.Name) + } + if instance.Signature == nil || *instance.Signature != "prompty.core.pipeline.run" { + t.Errorf(`Expected Signature to be "prompty.core.pipeline.run", got %v`, instance.Signature) + } + if instance.Error == nil || *instance.Error != "Connection refused" { + t.Errorf(`Expected Error to be "Connection refused", got %v`, instance.Error) + } +} + // TestTraceSpanRoundtrip tests load -> save -> load produces equivalent data func TestTraceSpanRoundtrip(t *testing.T) { jsonData := ` @@ -136,6 +185,20 @@ func TestTraceSpanToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadTraceSpan(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Name != "prompty.core.pipeline.run" { + t.Errorf(`Expected Name to be "prompty.core.pipeline.run", got %v`, reloaded.Name) + } + if reloaded.Signature == nil || *reloaded.Signature != "prompty.core.pipeline.run" { + t.Errorf(`Expected Signature to be "prompty.core.pipeline.run", got %v`, reloaded.Signature) + } + if reloaded.Error == nil || *reloaded.Error != "Connection refused" { + t.Errorf(`Expected Error to be "Connection refused", got %v`, reloaded.Error) + } } // TestTraceSpanToYAML tests that ToYAML produces valid YAML @@ -166,4 +229,25 @@ func TestTraceSpanToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadTraceSpan(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Name != "prompty.core.pipeline.run" { + t.Errorf(`Expected Name to be "prompty.core.pipeline.run", got %v`, reloaded.Name) + } + if reloaded.Signature == nil || *reloaded.Signature != "prompty.core.pipeline.run" { + t.Errorf(`Expected Signature to be "prompty.core.pipeline.run", got %v`, reloaded.Signature) + } + if reloaded.Error == nil || *reloaded.Error != "Connection refused" { + t.Errorf(`Expected Error to be "Connection refused", got %v`, reloaded.Error) + } +} + +// TestTraceSpanFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestTraceSpanFromJSONInvalid(t *testing.T) { + if _, err := prompty.TraceSpanFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/trace_time.go b/runtime/go/prompty/model/trace_time.go index e423b32a..ace3171c 100644 --- a/runtime/go/prompty/model/trace_time.go +++ b/runtime/go/prompty/model/trace_time.go @@ -52,7 +52,7 @@ func LoadTraceTime(data interface{}, ctx *LoadContext) (TraceTime, error) { } // Save serializes TraceTime to map[string]interface{} -func (obj *TraceTime) Save(ctx *SaveContext) map[string]interface{} { +func (obj TraceTime) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["start"] = obj.Start result["end"] = obj.End @@ -76,11 +76,7 @@ func (obj *TraceTime) ToJSON() (string, error) { func (obj *TraceTime) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates TraceTime from JSON string diff --git a/runtime/go/prompty/model/trace_time_test.go b/runtime/go/prompty/model/trace_time_test.go index dd9a91ac..3d303a28 100644 --- a/runtime/go/prompty/model/trace_time_test.go +++ b/runtime/go/prompty/model/trace_time_test.go @@ -71,6 +71,55 @@ duration: 1000 } } +// TestTraceTimeFromJSON tests loading TraceTime through the generated JSON helper +func TestTraceTimeFromJSON(t *testing.T) { + jsonData := ` +{ + "start": "2026-04-04T12:00:00Z", + "end": "2026-04-04T12:00:01Z", + "duration": 1000 +} +` + + instance, err := prompty.TraceTimeFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load TraceTime from JSON helper: %v", err) + } + if instance.Start != "2026-04-04T12:00:00Z" { + t.Errorf(`Expected Start to be "2026-04-04T12:00:00Z", got %v`, instance.Start) + } + if instance.End != "2026-04-04T12:00:01Z" { + t.Errorf(`Expected End to be "2026-04-04T12:00:01Z", got %v`, instance.End) + } + if instance.Duration != 1000 { + t.Errorf(`Expected Duration to be 1000, got %v`, instance.Duration) + } +} + +// TestTraceTimeFromYAML tests loading TraceTime through the generated YAML helper +func TestTraceTimeFromYAML(t *testing.T) { + yamlData := ` +start: "2026-04-04T12:00:00Z" +end: "2026-04-04T12:00:01Z" +duration: 1000 + +` + + instance, err := prompty.TraceTimeFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load TraceTime from YAML helper: %v", err) + } + if instance.Start != "2026-04-04T12:00:00Z" { + t.Errorf(`Expected Start to be "2026-04-04T12:00:00Z", got %v`, instance.Start) + } + if instance.End != "2026-04-04T12:00:01Z" { + t.Errorf(`Expected End to be "2026-04-04T12:00:01Z", got %v`, instance.End) + } + if instance.Duration != 1000 { + t.Errorf(`Expected Duration to be 1000, got %v`, instance.Duration) + } +} + // TestTraceTimeRoundtrip tests load -> save -> load produces equivalent data func TestTraceTimeRoundtrip(t *testing.T) { jsonData := ` @@ -136,6 +185,20 @@ func TestTraceTimeToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadTraceTime(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Start != "2026-04-04T12:00:00Z" { + t.Errorf(`Expected Start to be "2026-04-04T12:00:00Z", got %v`, reloaded.Start) + } + if reloaded.End != "2026-04-04T12:00:01Z" { + t.Errorf(`Expected End to be "2026-04-04T12:00:01Z", got %v`, reloaded.End) + } + if reloaded.Duration != 1000 { + t.Errorf(`Expected Duration to be 1000, got %v`, reloaded.Duration) + } } // TestTraceTimeToYAML tests that ToYAML produces valid YAML @@ -166,4 +229,25 @@ func TestTraceTimeToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadTraceTime(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Start != "2026-04-04T12:00:00Z" { + t.Errorf(`Expected Start to be "2026-04-04T12:00:00Z", got %v`, reloaded.Start) + } + if reloaded.End != "2026-04-04T12:00:01Z" { + t.Errorf(`Expected End to be "2026-04-04T12:00:01Z", got %v`, reloaded.End) + } + if reloaded.Duration != 1000 { + t.Errorf(`Expected Duration to be 1000, got %v`, reloaded.Duration) + } +} + +// TestTraceTimeFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestTraceTimeFromJSONInvalid(t *testing.T) { + if _, err := prompty.TraceTimeFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/trajectory_event.go b/runtime/go/prompty/model/trajectory_event.go index cb94c651..78c416c1 100644 --- a/runtime/go/prompty/model/trajectory_event.go +++ b/runtime/go/prompty/model/trajectory_event.go @@ -84,7 +84,7 @@ func LoadTrajectoryEvent(data interface{}, ctx *LoadContext) (TrajectoryEvent, e } // Save serializes TrajectoryEvent to map[string]interface{} -func (obj *TrajectoryEvent) Save(ctx *SaveContext) map[string]interface{} { +func (obj TrajectoryEvent) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) if obj.Id != nil { result["id"] = *obj.Id @@ -130,11 +130,7 @@ func (obj *TrajectoryEvent) ToJSON() (string, error) { func (obj *TrajectoryEvent) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates TrajectoryEvent from JSON string diff --git a/runtime/go/prompty/model/trajectory_event_test.go b/runtime/go/prompty/model/trajectory_event_test.go index ed874d5d..5a84002d 100644 --- a/runtime/go/prompty/model/trajectory_event_test.go +++ b/runtime/go/prompty/model/trajectory_event_test.go @@ -103,6 +103,87 @@ createdAt: "2026-06-09T20:00:00Z" } } +// TestTrajectoryEventFromJSON tests loading TrajectoryEvent through the generated JSON helper +func TestTrajectoryEventFromJSON(t *testing.T) { + jsonData := ` +{ + "id": "traj_abc123", + "sessionId": "sess_abc123", + "turnId": "turn_001", + "toolCallId": "call_abc123", + "turnIndex": 4, + "eventType": "command", + "createdAt": "2026-06-09T20:00:00Z" +} +` + + instance, err := prompty.TrajectoryEventFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load TrajectoryEvent from JSON helper: %v", err) + } + if instance.Id == nil || *instance.Id != "traj_abc123" { + t.Errorf(`Expected Id to be "traj_abc123", got %v`, instance.Id) + } + if instance.SessionId == nil || *instance.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, instance.SessionId) + } + if instance.TurnId == nil || *instance.TurnId != "turn_001" { + t.Errorf(`Expected TurnId to be "turn_001", got %v`, instance.TurnId) + } + if instance.ToolCallId == nil || *instance.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, instance.ToolCallId) + } + if instance.TurnIndex == nil || *instance.TurnIndex != 4 { + t.Errorf(`Expected TurnIndex to be 4, got %v`, instance.TurnIndex) + } + if instance.EventType != "command" { + t.Errorf(`Expected EventType to be "command", got %v`, instance.EventType) + } + if instance.CreatedAt == nil || *instance.CreatedAt != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected CreatedAt to be "2026-06-09T20:00:00Z", got %v`, instance.CreatedAt) + } +} + +// TestTrajectoryEventFromYAML tests loading TrajectoryEvent through the generated YAML helper +func TestTrajectoryEventFromYAML(t *testing.T) { + yamlData := ` +id: traj_abc123 +sessionId: sess_abc123 +turnId: turn_001 +toolCallId: call_abc123 +turnIndex: 4 +eventType: command +createdAt: "2026-06-09T20:00:00Z" + +` + + instance, err := prompty.TrajectoryEventFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load TrajectoryEvent from YAML helper: %v", err) + } + if instance.Id == nil || *instance.Id != "traj_abc123" { + t.Errorf(`Expected Id to be "traj_abc123", got %v`, instance.Id) + } + if instance.SessionId == nil || *instance.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, instance.SessionId) + } + if instance.TurnId == nil || *instance.TurnId != "turn_001" { + t.Errorf(`Expected TurnId to be "turn_001", got %v`, instance.TurnId) + } + if instance.ToolCallId == nil || *instance.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, instance.ToolCallId) + } + if instance.TurnIndex == nil || *instance.TurnIndex != 4 { + t.Errorf(`Expected TurnIndex to be 4, got %v`, instance.TurnIndex) + } + if instance.EventType != "command" { + t.Errorf(`Expected EventType to be "command", got %v`, instance.EventType) + } + if instance.CreatedAt == nil || *instance.CreatedAt != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected CreatedAt to be "2026-06-09T20:00:00Z", got %v`, instance.CreatedAt) + } +} + // TestTrajectoryEventRoundtrip tests load -> save -> load produces equivalent data func TestTrajectoryEventRoundtrip(t *testing.T) { jsonData := ` @@ -188,6 +269,32 @@ func TestTrajectoryEventToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadTrajectoryEvent(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Id == nil || *reloaded.Id != "traj_abc123" { + t.Errorf(`Expected Id to be "traj_abc123", got %v`, reloaded.Id) + } + if reloaded.SessionId == nil || *reloaded.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, reloaded.SessionId) + } + if reloaded.TurnId == nil || *reloaded.TurnId != "turn_001" { + t.Errorf(`Expected TurnId to be "turn_001", got %v`, reloaded.TurnId) + } + if reloaded.ToolCallId == nil || *reloaded.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, reloaded.ToolCallId) + } + if reloaded.TurnIndex == nil || *reloaded.TurnIndex != 4 { + t.Errorf(`Expected TurnIndex to be 4, got %v`, reloaded.TurnIndex) + } + if reloaded.EventType != "command" { + t.Errorf(`Expected EventType to be "command", got %v`, reloaded.EventType) + } + if reloaded.CreatedAt == nil || *reloaded.CreatedAt != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected CreatedAt to be "2026-06-09T20:00:00Z", got %v`, reloaded.CreatedAt) + } } // TestTrajectoryEventToYAML tests that ToYAML produces valid YAML @@ -222,4 +329,37 @@ func TestTrajectoryEventToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadTrajectoryEvent(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Id == nil || *reloaded.Id != "traj_abc123" { + t.Errorf(`Expected Id to be "traj_abc123", got %v`, reloaded.Id) + } + if reloaded.SessionId == nil || *reloaded.SessionId != "sess_abc123" { + t.Errorf(`Expected SessionId to be "sess_abc123", got %v`, reloaded.SessionId) + } + if reloaded.TurnId == nil || *reloaded.TurnId != "turn_001" { + t.Errorf(`Expected TurnId to be "turn_001", got %v`, reloaded.TurnId) + } + if reloaded.ToolCallId == nil || *reloaded.ToolCallId != "call_abc123" { + t.Errorf(`Expected ToolCallId to be "call_abc123", got %v`, reloaded.ToolCallId) + } + if reloaded.TurnIndex == nil || *reloaded.TurnIndex != 4 { + t.Errorf(`Expected TurnIndex to be 4, got %v`, reloaded.TurnIndex) + } + if reloaded.EventType != "command" { + t.Errorf(`Expected EventType to be "command", got %v`, reloaded.EventType) + } + if reloaded.CreatedAt == nil || *reloaded.CreatedAt != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected CreatedAt to be "2026-06-09T20:00:00Z", got %v`, reloaded.CreatedAt) + } +} + +// TestTrajectoryEventFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestTrajectoryEventFromJSONInvalid(t *testing.T) { + if _, err := prompty.TrajectoryEventFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/turn_end_payload.go b/runtime/go/prompty/model/turn_end_payload.go index 6ce17dcd..21ac0027 100644 --- a/runtime/go/prompty/model/turn_end_payload.go +++ b/runtime/go/prompty/model/turn_end_payload.go @@ -77,7 +77,7 @@ func LoadTurnEndPayload(data interface{}, ctx *LoadContext) (TurnEndPayload, err } // Save serializes TurnEndPayload to map[string]interface{} -func (obj *TurnEndPayload) Save(ctx *SaveContext) map[string]interface{} { +func (obj TurnEndPayload) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) if obj.Iterations != nil { result["iterations"] = *obj.Iterations @@ -110,11 +110,7 @@ func (obj *TurnEndPayload) ToJSON() (string, error) { func (obj *TurnEndPayload) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates TurnEndPayload from JSON string diff --git a/runtime/go/prompty/model/turn_end_payload_test.go b/runtime/go/prompty/model/turn_end_payload_test.go index e33a8cd0..30d77b89 100644 --- a/runtime/go/prompty/model/turn_end_payload_test.go +++ b/runtime/go/prompty/model/turn_end_payload_test.go @@ -63,6 +63,47 @@ durationMs: 1500 } } +// TestTurnEndPayloadFromJSON tests loading TurnEndPayload through the generated JSON helper +func TestTurnEndPayloadFromJSON(t *testing.T) { + jsonData := ` +{ + "iterations": 2, + "durationMs": 1500 +} +` + + instance, err := prompty.TurnEndPayloadFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load TurnEndPayload from JSON helper: %v", err) + } + if instance.Iterations == nil || *instance.Iterations != 2 { + t.Errorf(`Expected Iterations to be 2, got %v`, instance.Iterations) + } + if instance.DurationMs == nil || *instance.DurationMs != 1500 { + t.Errorf(`Expected DurationMs to be 1500, got %v`, instance.DurationMs) + } +} + +// TestTurnEndPayloadFromYAML tests loading TurnEndPayload through the generated YAML helper +func TestTurnEndPayloadFromYAML(t *testing.T) { + yamlData := ` +iterations: 2 +durationMs: 1500 + +` + + instance, err := prompty.TurnEndPayloadFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load TurnEndPayload from YAML helper: %v", err) + } + if instance.Iterations == nil || *instance.Iterations != 2 { + t.Errorf(`Expected Iterations to be 2, got %v`, instance.Iterations) + } + if instance.DurationMs == nil || *instance.DurationMs != 1500 { + t.Errorf(`Expected DurationMs to be 1500, got %v`, instance.DurationMs) + } +} + // TestTurnEndPayloadRoundtrip tests load -> save -> load produces equivalent data func TestTurnEndPayloadRoundtrip(t *testing.T) { jsonData := ` @@ -123,6 +164,17 @@ func TestTurnEndPayloadToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadTurnEndPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Iterations == nil || *reloaded.Iterations != 2 { + t.Errorf(`Expected Iterations to be 2, got %v`, reloaded.Iterations) + } + if reloaded.DurationMs == nil || *reloaded.DurationMs != 1500 { + t.Errorf(`Expected DurationMs to be 1500, got %v`, reloaded.DurationMs) + } } // TestTurnEndPayloadToYAML tests that ToYAML produces valid YAML @@ -152,4 +204,22 @@ func TestTurnEndPayloadToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadTurnEndPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Iterations == nil || *reloaded.Iterations != 2 { + t.Errorf(`Expected Iterations to be 2, got %v`, reloaded.Iterations) + } + if reloaded.DurationMs == nil || *reloaded.DurationMs != 1500 { + t.Errorf(`Expected DurationMs to be 1500, got %v`, reloaded.DurationMs) + } +} + +// TestTurnEndPayloadFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestTurnEndPayloadFromJSONInvalid(t *testing.T) { + if _, err := prompty.TurnEndPayloadFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/turn_event.go b/runtime/go/prompty/model/turn_event.go index 56a00b79..e8e7eede 100644 --- a/runtime/go/prompty/model/turn_event.go +++ b/runtime/go/prompty/model/turn_event.go @@ -107,7 +107,7 @@ func LoadTurnEvent(data interface{}, ctx *LoadContext) (TurnEvent, error) { } // Save serializes TurnEvent to map[string]interface{} -func (obj *TurnEvent) Save(ctx *SaveContext) map[string]interface{} { +func (obj TurnEvent) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["id"] = obj.Id result["type"] = string(obj.Type) @@ -144,11 +144,7 @@ func (obj *TurnEvent) ToJSON() (string, error) { func (obj *TurnEvent) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates TurnEvent from JSON string diff --git a/runtime/go/prompty/model/turn_event_test.go b/runtime/go/prompty/model/turn_event_test.go index 5212da43..50b96d1a 100644 --- a/runtime/go/prompty/model/turn_event_test.go +++ b/runtime/go/prompty/model/turn_event_test.go @@ -95,6 +95,79 @@ spanId: span_tool_001 } } +// TestTurnEventFromJSON tests loading TurnEvent through the generated JSON helper +func TestTurnEventFromJSON(t *testing.T) { + jsonData := ` +{ + "id": "evt_abc123", + "timestamp": "2026-06-09T20:00:00Z", + "turnId": "turn_001", + "iteration": 0, + "parentId": "evt_parent", + "spanId": "span_tool_001" +} +` + + instance, err := prompty.TurnEventFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load TurnEvent from JSON helper: %v", err) + } + if instance.Id != "evt_abc123" { + t.Errorf(`Expected Id to be "evt_abc123", got %v`, instance.Id) + } + if instance.Timestamp != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected Timestamp to be "2026-06-09T20:00:00Z", got %v`, instance.Timestamp) + } + if instance.TurnId == nil || *instance.TurnId != "turn_001" { + t.Errorf(`Expected TurnId to be "turn_001", got %v`, instance.TurnId) + } + if instance.Iteration == nil || *instance.Iteration != 0 { + t.Errorf(`Expected Iteration to be 0, got %v`, instance.Iteration) + } + if instance.ParentId == nil || *instance.ParentId != "evt_parent" { + t.Errorf(`Expected ParentId to be "evt_parent", got %v`, instance.ParentId) + } + if instance.SpanId == nil || *instance.SpanId != "span_tool_001" { + t.Errorf(`Expected SpanId to be "span_tool_001", got %v`, instance.SpanId) + } +} + +// TestTurnEventFromYAML tests loading TurnEvent through the generated YAML helper +func TestTurnEventFromYAML(t *testing.T) { + yamlData := ` +id: evt_abc123 +timestamp: "2026-06-09T20:00:00Z" +turnId: turn_001 +iteration: 0 +parentId: evt_parent +spanId: span_tool_001 + +` + + instance, err := prompty.TurnEventFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load TurnEvent from YAML helper: %v", err) + } + if instance.Id != "evt_abc123" { + t.Errorf(`Expected Id to be "evt_abc123", got %v`, instance.Id) + } + if instance.Timestamp != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected Timestamp to be "2026-06-09T20:00:00Z", got %v`, instance.Timestamp) + } + if instance.TurnId == nil || *instance.TurnId != "turn_001" { + t.Errorf(`Expected TurnId to be "turn_001", got %v`, instance.TurnId) + } + if instance.Iteration == nil || *instance.Iteration != 0 { + t.Errorf(`Expected Iteration to be 0, got %v`, instance.Iteration) + } + if instance.ParentId == nil || *instance.ParentId != "evt_parent" { + t.Errorf(`Expected ParentId to be "evt_parent", got %v`, instance.ParentId) + } + if instance.SpanId == nil || *instance.SpanId != "span_tool_001" { + t.Errorf(`Expected SpanId to be "span_tool_001", got %v`, instance.SpanId) + } +} + // TestTurnEventRoundtrip tests load -> save -> load produces equivalent data func TestTurnEventRoundtrip(t *testing.T) { jsonData := ` @@ -175,6 +248,29 @@ func TestTurnEventToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadTurnEvent(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Id != "evt_abc123" { + t.Errorf(`Expected Id to be "evt_abc123", got %v`, reloaded.Id) + } + if reloaded.Timestamp != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected Timestamp to be "2026-06-09T20:00:00Z", got %v`, reloaded.Timestamp) + } + if reloaded.TurnId == nil || *reloaded.TurnId != "turn_001" { + t.Errorf(`Expected TurnId to be "turn_001", got %v`, reloaded.TurnId) + } + if reloaded.Iteration == nil || *reloaded.Iteration != 0 { + t.Errorf(`Expected Iteration to be 0, got %v`, reloaded.Iteration) + } + if reloaded.ParentId == nil || *reloaded.ParentId != "evt_parent" { + t.Errorf(`Expected ParentId to be "evt_parent", got %v`, reloaded.ParentId) + } + if reloaded.SpanId == nil || *reloaded.SpanId != "span_tool_001" { + t.Errorf(`Expected SpanId to be "span_tool_001", got %v`, reloaded.SpanId) + } } // TestTurnEventToYAML tests that ToYAML produces valid YAML @@ -208,4 +304,34 @@ func TestTurnEventToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadTurnEvent(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Id != "evt_abc123" { + t.Errorf(`Expected Id to be "evt_abc123", got %v`, reloaded.Id) + } + if reloaded.Timestamp != "2026-06-09T20:00:00Z" { + t.Errorf(`Expected Timestamp to be "2026-06-09T20:00:00Z", got %v`, reloaded.Timestamp) + } + if reloaded.TurnId == nil || *reloaded.TurnId != "turn_001" { + t.Errorf(`Expected TurnId to be "turn_001", got %v`, reloaded.TurnId) + } + if reloaded.Iteration == nil || *reloaded.Iteration != 0 { + t.Errorf(`Expected Iteration to be 0, got %v`, reloaded.Iteration) + } + if reloaded.ParentId == nil || *reloaded.ParentId != "evt_parent" { + t.Errorf(`Expected ParentId to be "evt_parent", got %v`, reloaded.ParentId) + } + if reloaded.SpanId == nil || *reloaded.SpanId != "span_tool_001" { + t.Errorf(`Expected SpanId to be "span_tool_001", got %v`, reloaded.SpanId) + } +} + +// TestTurnEventFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestTurnEventFromJSONInvalid(t *testing.T) { + if _, err := prompty.TurnEventFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/turn_options.go b/runtime/go/prompty/model/turn_options.go index 47876a43..aacb1588 100644 --- a/runtime/go/prompty/model/turn_options.go +++ b/runtime/go/prompty/model/turn_options.go @@ -109,7 +109,7 @@ func LoadTurnOptions(data interface{}, ctx *LoadContext) (TurnOptions, error) { } // Save serializes TurnOptions to map[string]interface{} -func (obj *TurnOptions) Save(ctx *SaveContext) map[string]interface{} { +func (obj TurnOptions) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) if obj.MaxIterations != nil { result["maxIterations"] = *obj.MaxIterations @@ -151,11 +151,7 @@ func (obj *TurnOptions) ToJSON() (string, error) { func (obj *TurnOptions) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates TurnOptions from JSON string diff --git a/runtime/go/prompty/model/turn_options_test.go b/runtime/go/prompty/model/turn_options_test.go index c25ed2fe..f4017cb6 100644 --- a/runtime/go/prompty/model/turn_options_test.go +++ b/runtime/go/prompty/model/turn_options_test.go @@ -55,6 +55,9 @@ func TestTurnOptionsLoadJSON(t *testing.T) { if instance.Turn == nil || *instance.Turn != 1 { t.Errorf(`Expected Turn to be 1, got %v`, instance.Turn) } + if instance.Compaction.Strategy == nil || *instance.Compaction.Strategy != "summarize" { + t.Errorf(`Expected Compaction.Strategy to be "summarize", got %v`, instance.Compaction.Strategy) + } } // TestTurnOptionsLoadYAML tests loading TurnOptions from YAML @@ -98,6 +101,93 @@ compaction: if instance.Turn == nil || *instance.Turn != 1 { t.Errorf(`Expected Turn to be 1, got %v`, instance.Turn) } + if instance.Compaction.Strategy == nil || *instance.Compaction.Strategy != "summarize" { + t.Errorf(`Expected Compaction.Strategy to be "summarize", got %v`, instance.Compaction.Strategy) + } +} + +// TestTurnOptionsFromJSON tests loading TurnOptions through the generated JSON helper +func TestTurnOptionsFromJSON(t *testing.T) { + jsonData := ` +{ + "maxIterations": 10, + "maxLlmRetries": 3, + "contextBudget": 100000, + "parallelToolCalls": true, + "raw": false, + "turn": 1, + "compaction": { + "strategy": "summarize" + } +} +` + + instance, err := prompty.TurnOptionsFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load TurnOptions from JSON helper: %v", err) + } + if instance.MaxIterations == nil || *instance.MaxIterations != 10 { + t.Errorf(`Expected MaxIterations to be 10, got %v`, instance.MaxIterations) + } + if instance.MaxLlmRetries == nil || *instance.MaxLlmRetries != 3 { + t.Errorf(`Expected MaxLlmRetries to be 3, got %v`, instance.MaxLlmRetries) + } + if instance.ContextBudget == nil || *instance.ContextBudget != 100000 { + t.Errorf(`Expected ContextBudget to be 100000, got %v`, instance.ContextBudget) + } + if instance.ParallelToolCalls == nil || *instance.ParallelToolCalls != true { + t.Errorf(`Expected ParallelToolCalls to be true, got %v`, instance.ParallelToolCalls) + } + if instance.Raw == nil || *instance.Raw != false { + t.Errorf(`Expected Raw to be false, got %v`, instance.Raw) + } + if instance.Turn == nil || *instance.Turn != 1 { + t.Errorf(`Expected Turn to be 1, got %v`, instance.Turn) + } + if instance.Compaction.Strategy == nil || *instance.Compaction.Strategy != "summarize" { + t.Errorf(`Expected Compaction.Strategy to be "summarize", got %v`, instance.Compaction.Strategy) + } +} + +// TestTurnOptionsFromYAML tests loading TurnOptions through the generated YAML helper +func TestTurnOptionsFromYAML(t *testing.T) { + yamlData := ` +maxIterations: 10 +maxLlmRetries: 3 +contextBudget: 100000 +parallelToolCalls: true +raw: false +turn: 1 +compaction: + strategy: summarize + +` + + instance, err := prompty.TurnOptionsFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load TurnOptions from YAML helper: %v", err) + } + if instance.MaxIterations == nil || *instance.MaxIterations != 10 { + t.Errorf(`Expected MaxIterations to be 10, got %v`, instance.MaxIterations) + } + if instance.MaxLlmRetries == nil || *instance.MaxLlmRetries != 3 { + t.Errorf(`Expected MaxLlmRetries to be 3, got %v`, instance.MaxLlmRetries) + } + if instance.ContextBudget == nil || *instance.ContextBudget != 100000 { + t.Errorf(`Expected ContextBudget to be 100000, got %v`, instance.ContextBudget) + } + if instance.ParallelToolCalls == nil || *instance.ParallelToolCalls != true { + t.Errorf(`Expected ParallelToolCalls to be true, got %v`, instance.ParallelToolCalls) + } + if instance.Raw == nil || *instance.Raw != false { + t.Errorf(`Expected Raw to be false, got %v`, instance.Raw) + } + if instance.Turn == nil || *instance.Turn != 1 { + t.Errorf(`Expected Turn to be 1, got %v`, instance.Turn) + } + if instance.Compaction.Strategy == nil || *instance.Compaction.Strategy != "summarize" { + t.Errorf(`Expected Compaction.Strategy to be "summarize", got %v`, instance.Compaction.Strategy) + } } // TestTurnOptionsRoundtrip tests load -> save -> load produces equivalent data @@ -150,6 +240,9 @@ func TestTurnOptionsRoundtrip(t *testing.T) { if reloaded.Turn == nil || *reloaded.Turn != 1 { t.Errorf(`Expected Turn to be 1, got %v`, reloaded.Turn) } + if reloaded.Compaction.Strategy == nil || *reloaded.Compaction.Strategy != "summarize" { + t.Errorf(`Expected Compaction.Strategy to be "summarize", got %v`, reloaded.Compaction.Strategy) + } } // TestTurnOptionsToJSON tests that ToJSON produces valid JSON @@ -186,6 +279,32 @@ func TestTurnOptionsToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadTurnOptions(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.MaxIterations == nil || *reloaded.MaxIterations != 10 { + t.Errorf(`Expected MaxIterations to be 10, got %v`, reloaded.MaxIterations) + } + if reloaded.MaxLlmRetries == nil || *reloaded.MaxLlmRetries != 3 { + t.Errorf(`Expected MaxLlmRetries to be 3, got %v`, reloaded.MaxLlmRetries) + } + if reloaded.ContextBudget == nil || *reloaded.ContextBudget != 100000 { + t.Errorf(`Expected ContextBudget to be 100000, got %v`, reloaded.ContextBudget) + } + if reloaded.ParallelToolCalls == nil || *reloaded.ParallelToolCalls != true { + t.Errorf(`Expected ParallelToolCalls to be true, got %v`, reloaded.ParallelToolCalls) + } + if reloaded.Raw == nil || *reloaded.Raw != false { + t.Errorf(`Expected Raw to be false, got %v`, reloaded.Raw) + } + if reloaded.Turn == nil || *reloaded.Turn != 1 { + t.Errorf(`Expected Turn to be 1, got %v`, reloaded.Turn) + } + if reloaded.Compaction.Strategy == nil || *reloaded.Compaction.Strategy != "summarize" { + t.Errorf(`Expected Compaction.Strategy to be "summarize", got %v`, reloaded.Compaction.Strategy) + } } // TestTurnOptionsToYAML tests that ToYAML produces valid YAML @@ -222,4 +341,37 @@ func TestTurnOptionsToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadTurnOptions(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.MaxIterations == nil || *reloaded.MaxIterations != 10 { + t.Errorf(`Expected MaxIterations to be 10, got %v`, reloaded.MaxIterations) + } + if reloaded.MaxLlmRetries == nil || *reloaded.MaxLlmRetries != 3 { + t.Errorf(`Expected MaxLlmRetries to be 3, got %v`, reloaded.MaxLlmRetries) + } + if reloaded.ContextBudget == nil || *reloaded.ContextBudget != 100000 { + t.Errorf(`Expected ContextBudget to be 100000, got %v`, reloaded.ContextBudget) + } + if reloaded.ParallelToolCalls == nil || *reloaded.ParallelToolCalls != true { + t.Errorf(`Expected ParallelToolCalls to be true, got %v`, reloaded.ParallelToolCalls) + } + if reloaded.Raw == nil || *reloaded.Raw != false { + t.Errorf(`Expected Raw to be false, got %v`, reloaded.Raw) + } + if reloaded.Turn == nil || *reloaded.Turn != 1 { + t.Errorf(`Expected Turn to be 1, got %v`, reloaded.Turn) + } + if reloaded.Compaction.Strategy == nil || *reloaded.Compaction.Strategy != "summarize" { + t.Errorf(`Expected Compaction.Strategy to be "summarize", got %v`, reloaded.Compaction.Strategy) + } +} + +// TestTurnOptionsFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestTurnOptionsFromJSONInvalid(t *testing.T) { + if _, err := prompty.TurnOptionsFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/turn_start_payload.go b/runtime/go/prompty/model/turn_start_payload.go index b913b5bf..f9c156d9 100644 --- a/runtime/go/prompty/model/turn_start_payload.go +++ b/runtime/go/prompty/model/turn_start_payload.go @@ -53,7 +53,7 @@ func LoadTurnStartPayload(data interface{}, ctx *LoadContext) (TurnStartPayload, } // Save serializes TurnStartPayload to map[string]interface{} -func (obj *TurnStartPayload) Save(ctx *SaveContext) map[string]interface{} { +func (obj TurnStartPayload) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) if obj.Agent != nil { result["agent"] = *obj.Agent @@ -83,11 +83,7 @@ func (obj *TurnStartPayload) ToJSON() (string, error) { func (obj *TurnStartPayload) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates TurnStartPayload from JSON string diff --git a/runtime/go/prompty/model/turn_start_payload_test.go b/runtime/go/prompty/model/turn_start_payload_test.go index deb0fef2..9b23774b 100644 --- a/runtime/go/prompty/model/turn_start_payload_test.go +++ b/runtime/go/prompty/model/turn_start_payload_test.go @@ -63,6 +63,47 @@ maxIterations: 10 } } +// TestTurnStartPayloadFromJSON tests loading TurnStartPayload through the generated JSON helper +func TestTurnStartPayloadFromJSON(t *testing.T) { + jsonData := ` +{ + "agent": "weather-agent", + "maxIterations": 10 +} +` + + instance, err := prompty.TurnStartPayloadFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load TurnStartPayload from JSON helper: %v", err) + } + if instance.Agent == nil || *instance.Agent != "weather-agent" { + t.Errorf(`Expected Agent to be "weather-agent", got %v`, instance.Agent) + } + if instance.MaxIterations == nil || *instance.MaxIterations != 10 { + t.Errorf(`Expected MaxIterations to be 10, got %v`, instance.MaxIterations) + } +} + +// TestTurnStartPayloadFromYAML tests loading TurnStartPayload through the generated YAML helper +func TestTurnStartPayloadFromYAML(t *testing.T) { + yamlData := ` +agent: weather-agent +maxIterations: 10 + +` + + instance, err := prompty.TurnStartPayloadFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load TurnStartPayload from YAML helper: %v", err) + } + if instance.Agent == nil || *instance.Agent != "weather-agent" { + t.Errorf(`Expected Agent to be "weather-agent", got %v`, instance.Agent) + } + if instance.MaxIterations == nil || *instance.MaxIterations != 10 { + t.Errorf(`Expected MaxIterations to be 10, got %v`, instance.MaxIterations) + } +} + // TestTurnStartPayloadRoundtrip tests load -> save -> load produces equivalent data func TestTurnStartPayloadRoundtrip(t *testing.T) { jsonData := ` @@ -123,6 +164,17 @@ func TestTurnStartPayloadToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadTurnStartPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Agent == nil || *reloaded.Agent != "weather-agent" { + t.Errorf(`Expected Agent to be "weather-agent", got %v`, reloaded.Agent) + } + if reloaded.MaxIterations == nil || *reloaded.MaxIterations != 10 { + t.Errorf(`Expected MaxIterations to be 10, got %v`, reloaded.MaxIterations) + } } // TestTurnStartPayloadToYAML tests that ToYAML produces valid YAML @@ -152,4 +204,22 @@ func TestTurnStartPayloadToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadTurnStartPayload(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Agent == nil || *reloaded.Agent != "weather-agent" { + t.Errorf(`Expected Agent to be "weather-agent", got %v`, reloaded.Agent) + } + if reloaded.MaxIterations == nil || *reloaded.MaxIterations != 10 { + t.Errorf(`Expected MaxIterations to be 10, got %v`, reloaded.MaxIterations) + } +} + +// TestTurnStartPayloadFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestTurnStartPayloadFromJSONInvalid(t *testing.T) { + if _, err := prompty.TurnStartPayloadFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/turn_summary.go b/runtime/go/prompty/model/turn_summary.go index f59e8818..9260eee3 100644 --- a/runtime/go/prompty/model/turn_summary.go +++ b/runtime/go/prompty/model/turn_summary.go @@ -119,7 +119,7 @@ func LoadTurnSummary(data interface{}, ctx *LoadContext) (TurnSummary, error) { } // Save serializes TurnSummary to map[string]interface{} -func (obj *TurnSummary) Save(ctx *SaveContext) map[string]interface{} { +func (obj TurnSummary) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["turnId"] = obj.TurnId result["status"] = obj.Status @@ -158,11 +158,7 @@ func (obj *TurnSummary) ToJSON() (string, error) { func (obj *TurnSummary) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates TurnSummary from JSON string diff --git a/runtime/go/prompty/model/turn_summary_test.go b/runtime/go/prompty/model/turn_summary_test.go index 5a58f518..9c719d3a 100644 --- a/runtime/go/prompty/model/turn_summary_test.go +++ b/runtime/go/prompty/model/turn_summary_test.go @@ -103,6 +103,87 @@ durationMs: 2500 } } +// TestTurnSummaryFromJSON tests loading TurnSummary through the generated JSON helper +func TestTurnSummaryFromJSON(t *testing.T) { + jsonData := ` +{ + "turnId": "turn_001", + "status": "success", + "iterations": 2, + "llmCalls": 3, + "toolCalls": 2, + "retries": 1, + "durationMs": 2500 +} +` + + instance, err := prompty.TurnSummaryFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load TurnSummary from JSON helper: %v", err) + } + if instance.TurnId != "turn_001" { + t.Errorf(`Expected TurnId to be "turn_001", got %v`, instance.TurnId) + } + if instance.Status != "success" { + t.Errorf(`Expected Status to be "success", got %v`, instance.Status) + } + if instance.Iterations != 2 { + t.Errorf(`Expected Iterations to be 2, got %v`, instance.Iterations) + } + if instance.LlmCalls == nil || *instance.LlmCalls != 3 { + t.Errorf(`Expected LlmCalls to be 3, got %v`, instance.LlmCalls) + } + if instance.ToolCalls == nil || *instance.ToolCalls != 2 { + t.Errorf(`Expected ToolCalls to be 2, got %v`, instance.ToolCalls) + } + if instance.Retries == nil || *instance.Retries != 1 { + t.Errorf(`Expected Retries to be 1, got %v`, instance.Retries) + } + if instance.DurationMs == nil || *instance.DurationMs != 2500 { + t.Errorf(`Expected DurationMs to be 2500, got %v`, instance.DurationMs) + } +} + +// TestTurnSummaryFromYAML tests loading TurnSummary through the generated YAML helper +func TestTurnSummaryFromYAML(t *testing.T) { + yamlData := ` +turnId: turn_001 +status: success +iterations: 2 +llmCalls: 3 +toolCalls: 2 +retries: 1 +durationMs: 2500 + +` + + instance, err := prompty.TurnSummaryFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load TurnSummary from YAML helper: %v", err) + } + if instance.TurnId != "turn_001" { + t.Errorf(`Expected TurnId to be "turn_001", got %v`, instance.TurnId) + } + if instance.Status != "success" { + t.Errorf(`Expected Status to be "success", got %v`, instance.Status) + } + if instance.Iterations != 2 { + t.Errorf(`Expected Iterations to be 2, got %v`, instance.Iterations) + } + if instance.LlmCalls == nil || *instance.LlmCalls != 3 { + t.Errorf(`Expected LlmCalls to be 3, got %v`, instance.LlmCalls) + } + if instance.ToolCalls == nil || *instance.ToolCalls != 2 { + t.Errorf(`Expected ToolCalls to be 2, got %v`, instance.ToolCalls) + } + if instance.Retries == nil || *instance.Retries != 1 { + t.Errorf(`Expected Retries to be 1, got %v`, instance.Retries) + } + if instance.DurationMs == nil || *instance.DurationMs != 2500 { + t.Errorf(`Expected DurationMs to be 2500, got %v`, instance.DurationMs) + } +} + // TestTurnSummaryRoundtrip tests load -> save -> load produces equivalent data func TestTurnSummaryRoundtrip(t *testing.T) { jsonData := ` @@ -188,6 +269,32 @@ func TestTurnSummaryToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadTurnSummary(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.TurnId != "turn_001" { + t.Errorf(`Expected TurnId to be "turn_001", got %v`, reloaded.TurnId) + } + if reloaded.Status != "success" { + t.Errorf(`Expected Status to be "success", got %v`, reloaded.Status) + } + if reloaded.Iterations != 2 { + t.Errorf(`Expected Iterations to be 2, got %v`, reloaded.Iterations) + } + if reloaded.LlmCalls == nil || *reloaded.LlmCalls != 3 { + t.Errorf(`Expected LlmCalls to be 3, got %v`, reloaded.LlmCalls) + } + if reloaded.ToolCalls == nil || *reloaded.ToolCalls != 2 { + t.Errorf(`Expected ToolCalls to be 2, got %v`, reloaded.ToolCalls) + } + if reloaded.Retries == nil || *reloaded.Retries != 1 { + t.Errorf(`Expected Retries to be 1, got %v`, reloaded.Retries) + } + if reloaded.DurationMs == nil || *reloaded.DurationMs != 2500 { + t.Errorf(`Expected DurationMs to be 2500, got %v`, reloaded.DurationMs) + } } // TestTurnSummaryToYAML tests that ToYAML produces valid YAML @@ -222,4 +329,37 @@ func TestTurnSummaryToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadTurnSummary(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.TurnId != "turn_001" { + t.Errorf(`Expected TurnId to be "turn_001", got %v`, reloaded.TurnId) + } + if reloaded.Status != "success" { + t.Errorf(`Expected Status to be "success", got %v`, reloaded.Status) + } + if reloaded.Iterations != 2 { + t.Errorf(`Expected Iterations to be 2, got %v`, reloaded.Iterations) + } + if reloaded.LlmCalls == nil || *reloaded.LlmCalls != 3 { + t.Errorf(`Expected LlmCalls to be 3, got %v`, reloaded.LlmCalls) + } + if reloaded.ToolCalls == nil || *reloaded.ToolCalls != 2 { + t.Errorf(`Expected ToolCalls to be 2, got %v`, reloaded.ToolCalls) + } + if reloaded.Retries == nil || *reloaded.Retries != 1 { + t.Errorf(`Expected Retries to be 1, got %v`, reloaded.Retries) + } + if reloaded.DurationMs == nil || *reloaded.DurationMs != 2500 { + t.Errorf(`Expected DurationMs to be 2500, got %v`, reloaded.DurationMs) + } +} + +// TestTurnSummaryFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestTurnSummaryFromJSONInvalid(t *testing.T) { + if _, err := prompty.TurnSummaryFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/turn_trace.go b/runtime/go/prompty/model/turn_trace.go index 56f573c8..8c409389 100644 --- a/runtime/go/prompty/model/turn_trace.go +++ b/runtime/go/prompty/model/turn_trace.go @@ -60,7 +60,7 @@ func LoadTurnTrace(data interface{}, ctx *LoadContext) (TurnTrace, error) { } // Save serializes TurnTrace to map[string]interface{} -func (obj *TurnTrace) Save(ctx *SaveContext) map[string]interface{} { +func (obj TurnTrace) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["version"] = obj.Version if obj.Runtime != nil { @@ -98,11 +98,7 @@ func (obj *TurnTrace) ToJSON() (string, error) { func (obj *TurnTrace) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates TurnTrace from JSON string diff --git a/runtime/go/prompty/model/turn_trace_test.go b/runtime/go/prompty/model/turn_trace_test.go index 1bf580f2..6a3816a8 100644 --- a/runtime/go/prompty/model/turn_trace_test.go +++ b/runtime/go/prompty/model/turn_trace_test.go @@ -71,6 +71,55 @@ promptyVersion: 2.0.0 } } +// TestTurnTraceFromJSON tests loading TurnTrace through the generated JSON helper +func TestTurnTraceFromJSON(t *testing.T) { + jsonData := ` +{ + "version": "1", + "runtime": "typescript", + "promptyVersion": "2.0.0" +} +` + + instance, err := prompty.TurnTraceFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load TurnTrace from JSON helper: %v", err) + } + if instance.Version != "1" { + t.Errorf(`Expected Version to be "1", got %v`, instance.Version) + } + if instance.Runtime == nil || *instance.Runtime != "typescript" { + t.Errorf(`Expected Runtime to be "typescript", got %v`, instance.Runtime) + } + if instance.PromptyVersion == nil || *instance.PromptyVersion != "2.0.0" { + t.Errorf(`Expected PromptyVersion to be "2.0.0", got %v`, instance.PromptyVersion) + } +} + +// TestTurnTraceFromYAML tests loading TurnTrace through the generated YAML helper +func TestTurnTraceFromYAML(t *testing.T) { + yamlData := ` +version: "1" +runtime: typescript +promptyVersion: 2.0.0 + +` + + instance, err := prompty.TurnTraceFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load TurnTrace from YAML helper: %v", err) + } + if instance.Version != "1" { + t.Errorf(`Expected Version to be "1", got %v`, instance.Version) + } + if instance.Runtime == nil || *instance.Runtime != "typescript" { + t.Errorf(`Expected Runtime to be "typescript", got %v`, instance.Runtime) + } + if instance.PromptyVersion == nil || *instance.PromptyVersion != "2.0.0" { + t.Errorf(`Expected PromptyVersion to be "2.0.0", got %v`, instance.PromptyVersion) + } +} + // TestTurnTraceRoundtrip tests load -> save -> load produces equivalent data func TestTurnTraceRoundtrip(t *testing.T) { jsonData := ` @@ -136,6 +185,20 @@ func TestTurnTraceToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadTurnTrace(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Version != "1" { + t.Errorf(`Expected Version to be "1", got %v`, reloaded.Version) + } + if reloaded.Runtime == nil || *reloaded.Runtime != "typescript" { + t.Errorf(`Expected Runtime to be "typescript", got %v`, reloaded.Runtime) + } + if reloaded.PromptyVersion == nil || *reloaded.PromptyVersion != "2.0.0" { + t.Errorf(`Expected PromptyVersion to be "2.0.0", got %v`, reloaded.PromptyVersion) + } } // TestTurnTraceToYAML tests that ToYAML produces valid YAML @@ -166,4 +229,25 @@ func TestTurnTraceToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadTurnTrace(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Version != "1" { + t.Errorf(`Expected Version to be "1", got %v`, reloaded.Version) + } + if reloaded.Runtime == nil || *reloaded.Runtime != "typescript" { + t.Errorf(`Expected Runtime to be "typescript", got %v`, reloaded.Runtime) + } + if reloaded.PromptyVersion == nil || *reloaded.PromptyVersion != "2.0.0" { + t.Errorf(`Expected PromptyVersion to be "2.0.0", got %v`, reloaded.PromptyVersion) + } +} + +// TestTurnTraceFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestTurnTraceFromJSONInvalid(t *testing.T) { + if _, err := prompty.TurnTraceFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/validation_error.go b/runtime/go/prompty/model/validation_error.go index f5556045..25386ef3 100644 --- a/runtime/go/prompty/model/validation_error.go +++ b/runtime/go/prompty/model/validation_error.go @@ -40,7 +40,7 @@ func LoadValidationError(data interface{}, ctx *LoadContext) (ValidationError, e } // Save serializes ValidationError to map[string]interface{} -func (obj *ValidationError) Save(ctx *SaveContext) map[string]interface{} { +func (obj ValidationError) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["message"] = obj.Message result["property"] = obj.Property @@ -64,11 +64,7 @@ func (obj *ValidationError) ToJSON() (string, error) { func (obj *ValidationError) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates ValidationError from JSON string diff --git a/runtime/go/prompty/model/validation_error_test.go b/runtime/go/prompty/model/validation_error_test.go index 61bf8ad2..4e1baaa5 100644 --- a/runtime/go/prompty/model/validation_error_test.go +++ b/runtime/go/prompty/model/validation_error_test.go @@ -71,6 +71,55 @@ constraint: required } } +// TestValidationErrorFromJSON tests loading ValidationError through the generated JSON helper +func TestValidationErrorFromJSON(t *testing.T) { + jsonData := ` +{ + "message": "Missing required input: firstName", + "property": "firstName", + "constraint": "required" +} +` + + instance, err := prompty.ValidationErrorFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load ValidationError from JSON helper: %v", err) + } + if instance.Message != "Missing required input: firstName" { + t.Errorf(`Expected Message to be "Missing required input: firstName", got %v`, instance.Message) + } + if instance.Property != "firstName" { + t.Errorf(`Expected Property to be "firstName", got %v`, instance.Property) + } + if instance.Constraint != "required" { + t.Errorf(`Expected Constraint to be "required", got %v`, instance.Constraint) + } +} + +// TestValidationErrorFromYAML tests loading ValidationError through the generated YAML helper +func TestValidationErrorFromYAML(t *testing.T) { + yamlData := ` +message: "Missing required input: firstName" +property: firstName +constraint: required + +` + + instance, err := prompty.ValidationErrorFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load ValidationError from YAML helper: %v", err) + } + if instance.Message != "Missing required input: firstName" { + t.Errorf(`Expected Message to be "Missing required input: firstName", got %v`, instance.Message) + } + if instance.Property != "firstName" { + t.Errorf(`Expected Property to be "firstName", got %v`, instance.Property) + } + if instance.Constraint != "required" { + t.Errorf(`Expected Constraint to be "required", got %v`, instance.Constraint) + } +} + // TestValidationErrorRoundtrip tests load -> save -> load produces equivalent data func TestValidationErrorRoundtrip(t *testing.T) { jsonData := ` @@ -136,6 +185,20 @@ func TestValidationErrorToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadValidationError(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Message != "Missing required input: firstName" { + t.Errorf(`Expected Message to be "Missing required input: firstName", got %v`, reloaded.Message) + } + if reloaded.Property != "firstName" { + t.Errorf(`Expected Property to be "firstName", got %v`, reloaded.Property) + } + if reloaded.Constraint != "required" { + t.Errorf(`Expected Constraint to be "required", got %v`, reloaded.Constraint) + } } // TestValidationErrorToYAML tests that ToYAML produces valid YAML @@ -166,4 +229,25 @@ func TestValidationErrorToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadValidationError(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Message != "Missing required input: firstName" { + t.Errorf(`Expected Message to be "Missing required input: firstName", got %v`, reloaded.Message) + } + if reloaded.Property != "firstName" { + t.Errorf(`Expected Property to be "firstName", got %v`, reloaded.Property) + } + if reloaded.Constraint != "required" { + t.Errorf(`Expected Constraint to be "required", got %v`, reloaded.Constraint) + } +} + +// TestValidationErrorFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestValidationErrorFromJSONInvalid(t *testing.T) { + if _, err := prompty.ValidationErrorFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/runtime/go/prompty/model/validation_result.go b/runtime/go/prompty/model/validation_result.go index 23ab233e..09ab9b6c 100644 --- a/runtime/go/prompty/model/validation_result.go +++ b/runtime/go/prompty/model/validation_result.go @@ -45,7 +45,7 @@ func LoadValidationResult(data interface{}, ctx *LoadContext) (ValidationResult, } // Save serializes ValidationResult to map[string]interface{} -func (obj *ValidationResult) Save(ctx *SaveContext) map[string]interface{} { +func (obj ValidationResult) Save(ctx *SaveContext) map[string]interface{} { result := make(map[string]interface{}) result["valid"] = obj.Valid if obj.Errors != nil { @@ -74,11 +74,7 @@ func (obj *ValidationResult) ToJSON() (string, error) { func (obj *ValidationResult) ToYAML() (string, error) { ctx := NewSaveContext() data := obj.Save(ctx) - bytes, err := yaml.Marshal(data) - if err != nil { - return "", err - } - return string(bytes), nil + return marshalYAMLDocument(data) } // FromJSON creates ValidationResult from JSON string diff --git a/runtime/go/prompty/model/validation_result_test.go b/runtime/go/prompty/model/validation_result_test.go index b259ea22..b102496f 100644 --- a/runtime/go/prompty/model/validation_result_test.go +++ b/runtime/go/prompty/model/validation_result_test.go @@ -33,6 +33,9 @@ func TestValidationResultLoadJSON(t *testing.T) { if instance.Valid != true { t.Errorf(`Expected Valid to be true, got %v`, instance.Valid) } + if len(instance.Errors) != 0 { + t.Fatalf("Expected Errors length to be 0, got %d", len(instance.Errors)) + } } // TestValidationResultLoadYAML tests loading ValidationResult from YAML @@ -55,6 +58,50 @@ errors: [] if instance.Valid != true { t.Errorf(`Expected Valid to be true, got %v`, instance.Valid) } + if len(instance.Errors) != 0 { + t.Fatalf("Expected Errors length to be 0, got %d", len(instance.Errors)) + } +} + +// TestValidationResultFromJSON tests loading ValidationResult through the generated JSON helper +func TestValidationResultFromJSON(t *testing.T) { + jsonData := ` +{ + "valid": true, + "errors": [] +} +` + + instance, err := prompty.ValidationResultFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to load ValidationResult from JSON helper: %v", err) + } + if instance.Valid != true { + t.Errorf(`Expected Valid to be true, got %v`, instance.Valid) + } + if len(instance.Errors) != 0 { + t.Fatalf("Expected Errors length to be 0, got %d", len(instance.Errors)) + } +} + +// TestValidationResultFromYAML tests loading ValidationResult through the generated YAML helper +func TestValidationResultFromYAML(t *testing.T) { + yamlData := ` +valid: true +errors: [] + +` + + instance, err := prompty.ValidationResultFromYAML(yamlData) + if err != nil { + t.Fatalf("Failed to load ValidationResult from YAML helper: %v", err) + } + if instance.Valid != true { + t.Errorf(`Expected Valid to be true, got %v`, instance.Valid) + } + if len(instance.Errors) != 0 { + t.Fatalf("Expected Errors length to be 0, got %d", len(instance.Errors)) + } } // TestValidationResultRoundtrip tests load -> save -> load produces equivalent data @@ -85,6 +132,9 @@ func TestValidationResultRoundtrip(t *testing.T) { if reloaded.Valid != true { t.Errorf(`Expected Valid to be true, got %v`, reloaded.Valid) } + if len(reloaded.Errors) != 0 { + t.Fatalf("Expected Errors length to be 0, got %d", len(reloaded.Errors)) + } } // TestValidationResultToJSON tests that ToJSON produces valid JSON @@ -114,6 +164,17 @@ func TestValidationResultToJSON(t *testing.T) { if err := json.Unmarshal([]byte(jsonOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated JSON: %v", err) } + + reloaded, err := prompty.LoadValidationResult(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated JSON: %v", err) + } + if reloaded.Valid != true { + t.Errorf(`Expected Valid to be true, got %v`, reloaded.Valid) + } + if len(reloaded.Errors) != 0 { + t.Fatalf("Expected Errors length to be 0, got %d", len(reloaded.Errors)) + } } // TestValidationResultToYAML tests that ToYAML produces valid YAML @@ -143,4 +204,22 @@ func TestValidationResultToYAML(t *testing.T) { if err := yaml.Unmarshal([]byte(yamlOutput), &parsed); err != nil { t.Fatalf("Failed to parse generated YAML: %v", err) } + + reloaded, err := prompty.LoadValidationResult(parsed, ctx) + if err != nil { + t.Fatalf("Failed to reload generated YAML: %v", err) + } + if reloaded.Valid != true { + t.Errorf(`Expected Valid to be true, got %v`, reloaded.Valid) + } + if len(reloaded.Errors) != 0 { + t.Fatalf("Expected Errors length to be 0, got %d", len(reloaded.Errors)) + } +} + +// TestValidationResultFromJSONInvalid rejects malformed JSON instead of silently defaulting +func TestValidationResultFromJSONInvalid(t *testing.T) { + if _, err := prompty.ValidationResultFromJSON("{"); err == nil { + t.Fatalf("Expected malformed JSON to fail") + } } diff --git a/schema/package-lock.json b/schema/package-lock.json index 488182dd..ff9c8918 100644 --- a/schema/package-lock.json +++ b/schema/package-lock.json @@ -8,7 +8,7 @@ "dependencies": { "@typespec/compiler": "1.10.0", "@typespec/json-schema": "1.10.0", - "@typra/emitter": "0.2.7" + "@typra/emitter": "0.3.0" } }, "node_modules/@babel/code-frame": { @@ -476,9 +476,9 @@ } }, "node_modules/@typra/emitter": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/@typra/emitter/-/emitter-0.2.7.tgz", - "integrity": "sha512-L3k7U3AYVhYtcuwboGHUpvawRZyGt3/zjeljx5jkx6xL8CyC+J2Eg7EzYroQEaWuIuTU/tEk7vkWIfJp+U1xUw==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@typra/emitter/-/emitter-0.3.0.tgz", + "integrity": "sha512-bOne4GCTLBV8pbRus73yvEs3UGBrffspYUg5DLIdkGwgu0gMY6nNAVLi6rTLrjutdoMAgYBR0Fi6hy+11PtZhw==", "license": "MIT", "dependencies": { "xml-formatter": "^3.6.7", diff --git a/schema/package.json b/schema/package.json index 334111fc..8ac3a31f 100644 --- a/schema/package.json +++ b/schema/package.json @@ -10,8 +10,8 @@ "build": "npm run format:tsp && npm run generate && npm run format:rust" }, "dependencies": { - "@typra/emitter": "0.2.7", "@typespec/compiler": "1.10.0", - "@typespec/json-schema": "1.10.0" + "@typespec/json-schema": "1.10.0", + "@typra/emitter": "0.3.0" } } From 949a4e11102a40e089fbb56f044cde1f49c33f76 Mon Sep 17 00:00:00 2001 From: Seth Juarez Date: Sat, 27 Jun 2026 23:31:43 -0700 Subject: [PATCH 11/22] Add OpenAI-compatible endpoint example Document how to route the existing OpenAI provider through compatible endpoints such as Tuning Engines. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- README.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/README.md b/README.md index 214a5466..3a7c2dfd 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,46 @@ console.log(result); **VS Code** — open the `.prompty` file and press **F5**. +### Use an OpenAI-compatible endpoint + +Prompty's `openai` provider can also target OpenAI-compatible control planes, +gateways, or self-hosted model servers by setting `model.connection.endpoint`. +The prompt asset stays portable: switch the endpoint and key at runtime without +changing the prompt body. + +```prompty +--- +name: governed-greeting +model: + id: gpt-4o-mini + provider: openai + connection: + kind: key + endpoint: ${env:OPENAI_BASE_URL:https://api.openai.com/v1} + apiKey: ${env:OPENAI_API_KEY} +template: + format: + kind: jinja2 + parser: + kind: prompty +--- +system: +You are a careful assistant. + +user: +Say hello to {{name}}. +``` + +For example, to route through Tuning Engines: + +```bash +export OPENAI_BASE_URL=https://api.tuningengines.com/v1 +export OPENAI_API_KEY=sk-te-your-inference-key +``` + +This keeps the `.prompty` file unchanged while the endpoint provides routing, +policy, usage tracking, or trace correlation around OpenAI-compatible calls. + ## Contributor hygiene Prompty normalizes text files to LF line endings via `.gitattributes`. Enable the From c3a85622f0eaf685aa1176f9826d4d6fe30e54e2 Mon Sep 17 00:00:00 2001 From: Seth Juarez Date: Sat, 27 Jun 2026 23:33:48 -0700 Subject: [PATCH 12/22] Add OpenAI-compatible endpoint docs example Mirror the README example in the public OpenAI how-to docs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- web/src/content/docs/how-to/openai.mdx | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/web/src/content/docs/how-to/openai.mdx b/web/src/content/docs/how-to/openai.mdx index ba61cc63..442856b5 100644 --- a/web/src/content/docs/how-to/openai.mdx +++ b/web/src/content/docs/how-to/openai.mdx @@ -77,6 +77,27 @@ user: To target a direct OpenAI-compatible endpoint or proxy, keep `provider: openai` and add `endpoint` under `connection`. +```yaml +model: + id: gpt-4o-mini + provider: openai + apiType: chat + connection: + kind: key + endpoint: ${env:OPENAI_BASE_URL:https://api.openai.com/v1} + apiKey: ${env:OPENAI_API_KEY} +``` + +For example, to route through Tuning Engines: + +```bash +export OPENAI_BASE_URL=https://api.tuningengines.com/v1 +export OPENAI_API_KEY=sk-te-your-inference-key +``` + +The `.prompty` file stays unchanged while the endpoint provides routing, +policy, usage tracking, or trace correlation around OpenAI-compatible calls. +