agentengine-sdk-python 0.8.5__py3-none-any.whl → 0.8.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {agentengine_sdk_python-0.8.5.dist-info → agentengine_sdk_python-0.8.6.dist-info}/METADATA +12 -8
- {agentengine_sdk_python-0.8.5.dist-info → agentengine_sdk_python-0.8.6.dist-info}/RECORD +823 -388
- ksadk/_async_iterators.py +79 -0
- ksadk/_build_provenance.json +1 -1
- ksadk/_model_anthropic.py +49 -0
- ksadk/_model_input.py +86 -0
- ksadk/_model_json.py +40 -0
- ksadk/_model_reasoning.py +17 -0
- ksadk/_model_refusal.py +20 -0
- ksadk/_model_sse.py +163 -0
- ksadk/a2a/__init__.py +157 -167
- ksadk/a2a/_invocation_state.py +86 -0
- ksadk/a2a/_space_client_events.py +33 -22
- ksadk/a2a/adk.py +194 -0
- ksadk/a2a/adk_invocation_context.py +242 -0
- ksadk/a2a/adk_runtime.py +126 -0
- ksadk/a2a/adk_tools.py +319 -0
- ksadk/a2a/bootstrap.py +149 -23
- ksadk/a2a/build_validation.py +147 -0
- ksadk/a2a/card.py +23 -15
- ksadk/a2a/codex.py +160 -0
- ksadk/a2a/codex_checkpoint.py +111 -0
- ksadk/a2a/codex_recovery.py +96 -0
- ksadk/a2a/codex_recovery_events.py +123 -0
- ksadk/a2a/codex_runtime.py +198 -0
- ksadk/a2a/codex_session_checkpoint.py +162 -0
- ksadk/a2a/composition.py +88 -0
- ksadk/a2a/context_store.py +118 -19
- ksadk/a2a/control_plane.py +108 -106
- ksadk/a2a/event_adapter.py +92 -193
- ksadk/a2a/executor.py +257 -85
- ksadk/a2a/exposure.py +106 -0
- ksadk/a2a/external_transport.py +3 -4
- ksadk/a2a/identity.py +106 -12
- ksadk/a2a/ids.py +14 -3
- ksadk/a2a/inbound_kernel.py +133 -0
- ksadk/a2a/interaction_wire.py +76 -0
- ksadk/a2a/invocation_checkpoint.py +274 -0
- ksadk/a2a/invocation_policy.py +87 -0
- ksadk/a2a/invocation_publication.py +210 -0
- ksadk/a2a/invocation_service.py +972 -0
- ksadk/a2a/invocation_types.py +459 -0
- ksadk/a2a/kernel_task_adapter.py +259 -0
- ksadk/a2a/langgraph.py +20 -7
- ksadk/a2a/langgraph_invocation_context.py +136 -0
- ksadk/a2a/langgraph_managed.py +150 -0
- ksadk/a2a/langgraph_recovery.py +32 -0
- ksadk/a2a/langgraph_runtime.py +89 -0
- ksadk/a2a/langgraph_tool_runtime.py +132 -0
- ksadk/a2a/langgraph_tools.py +63 -0
- ksadk/a2a/message_digest.py +40 -0
- ksadk/a2a/platform.py +389 -0
- ksadk/a2a/policy_refs.py +13 -0
- ksadk/a2a/presentation.py +402 -0
- ksadk/a2a/product_kernel_facts.py +177 -0
- ksadk/a2a/product_key.py +99 -0
- ksadk/a2a/protocol_errors.py +116 -0
- ksadk/a2a/result_text.py +49 -0
- ksadk/a2a/resume_store.py +93 -3
- ksadk/a2a/routes.py +6 -1
- ksadk/a2a/runtime_approval.py +198 -0
- ksadk/a2a/runtime_input.py +151 -0
- ksadk/a2a/server.py +16 -7
- ksadk/a2a/space_client.py +101 -16
- ksadk/a2a/task_adapter.py +19 -5
- ksadk/a2a/task_event_dispatcher.py +39 -2
- ksadk/a2a/task_event_outbox.py +215 -0
- ksadk/a2a/task_event_outbox_owned.py +130 -0
- ksadk/a2a/task_store.py +37 -0
- ksadk/a2a/tool_activity.py +176 -0
- ksadk/a2a/workload_tokens.py +134 -0
- ksadk/api/client.py +32 -79
- ksadk/api/sse_stream.py +96 -0
- ksadk/builders/code_builder.py +83 -106
- ksadk/builders/container_builder.py +11 -29
- ksadk/builders/framework_requirements.py +2 -0
- ksadk/builders/managed_runtime_builder.py +12 -0
- ksadk/builders/source_provenance.py +87 -0
- ksadk/cli/cmd_a2a.py +43 -0
- ksadk/cli/cmd_build.py +9 -0
- ksadk/cli/cmd_deploy.py +27 -2
- ksadk/cli/cmd_invoke.py +45 -92
- ksadk/cli/cmd_studio.py +5 -1
- ksadk/cli/cmd_web.py +2 -0
- ksadk/cli/hosted_invoke.py +206 -0
- ksadk/cli/invoke_content.py +60 -0
- ksadk/cli/runtime_bootstrap.py +27 -5
- ksadk/codex/_expert_request_reader.py +48 -0
- ksadk/codex/a2a_tools.py +140 -0
- ksadk/codex/async_approval.py +169 -0
- ksadk/codex/async_client.py +938 -0
- ksadk/codex/async_proxy.py +216 -0
- ksadk/codex/base_runtime.py +25 -0
- ksadk/codex/client.py +3 -1048
- ksadk/codex/client_payloads.py +85 -0
- ksadk/codex/rollout_checkpoint.py +264 -0
- ksadk/codex/runtime.py +290 -54
- ksadk/common/auth.py +2 -2
- ksadk/common/cloud_headers.py +36 -0
- ksadk/common/diagnostics.py +34 -0
- ksadk/common/kop_client.py +2 -1
- ksadk/configs/env_registry.py +106 -127
- ksadk/configs/env_registry_a2a.py +173 -0
- ksadk/configs/env_registry_studio.py +53 -5
- ksadk/configs/global_config.py +1 -0
- ksadk/configs/settings.py +6 -0
- ksadk/context_engine/assembler.py +9 -0
- ksadk/context_engine/contributors.py +80 -17
- ksadk/context_engine/instruction_authority.py +18 -0
- ksadk/conversations/attachments.py +53 -15
- ksadk/conversations/contracts.py +28 -9
- ksadk/conversations/message_projection.py +30 -125
- ksadk/conversations/message_projection_blocks.py +137 -0
- ksadk/conversations/model_context.py +11 -3
- ksadk/conversations/projector.py +63 -0
- ksadk/conversations/runtime_compaction.py +7 -2
- ksadk/conversations/runtime_input.py +16 -4
- ksadk/conversations/runtime_payloads.py +4 -0
- ksadk/conversations/runtime_persistence.py +192 -24
- ksadk/conversations/runtime_preparation.py +85 -6
- ksadk/conversations/runtime_projection.py +217 -0
- ksadk/conversations/runtime_resume.py +141 -70
- ksadk/conversations/tool_receipt_resume.py +387 -0
- ksadk/conversations/tool_receipts.py +32 -0
- ksadk/deployment/env_forward.py +5 -0
- ksadk/deployment/manager.py +15 -6
- ksadk/deployment/providers/serverless.py +76 -136
- ksadk/deployment/providers/serverless_payloads.py +122 -0
- ksadk/evaluation/agent_eval_client.py +2 -1
- ksadk/evaluation/contracts.py +78 -3
- ksadk/evaluation/evaluators.py +166 -1
- ksadk/evaluation/evidence.py +271 -4
- ksadk/evaluation/local_adapter.py +76 -12
- ksadk/evaluation/studio_build_adapter.py +73 -9
- ksadk/events/adapters/_a2a_checkpoint.py +151 -0
- ksadk/events/adapters/_a2a_snapshot.py +18 -14
- ksadk/events/adapters/_a2a_support.py +15 -3
- ksadk/events/adapters/_a2a_tool_activity.py +123 -0
- ksadk/events/adapters/_codex_errors.py +49 -0
- ksadk/events/adapters/_langgraph_support.py +12 -1
- ksadk/events/adapters/a2a.py +54 -26
- ksadk/events/adapters/adk.py +188 -30
- ksadk/events/adapters/codex.py +33 -7
- ksadk/events/adapters/langgraph.py +16 -6
- ksadk/events/canonical.py +5 -0
- ksadk/events/canonical_store.py +200 -4
- ksadk/events/reducer.py +82 -0
- ksadk/events/run_authority.py +176 -0
- ksadk/harness/__init__.py +4 -0
- ksadk/harness/artifact_adapters/__init__.py +1 -0
- ksadk/harness/artifact_adapters/native_page_budget.py +172 -0
- ksadk/harness/artifact_adapters/native_search.py +249 -0
- ksadk/harness/artifact_adapters/native_search_budget.py +134 -0
- ksadk/harness/artifact_adapters/native_store.py +115 -0
- ksadk/harness/artifact_adapters/native_tool.py +222 -0
- ksadk/harness/artifact_store.py +26 -9
- ksadk/harness/browser_adapters/__init__.py +6 -0
- ksadk/harness/browser_adapters/native_browser_tool.py +92 -0
- ksadk/harness/browser_adapters/native_dom_snapshot.py +187 -0
- ksadk/harness/browser_adapters/native_playwright.py +953 -0
- ksadk/harness/browser_adapters/native_vision.py +295 -0
- ksadk/harness/capability_adapters/__init__.py +1 -0
- ksadk/harness/capability_adapters/native_dsh.py +289 -0
- ksadk/harness/capability_runtime.py +104 -9
- ksadk/harness/compaction_record.py +31 -0
- ksadk/harness/compiler.py +3 -3
- ksadk/harness/config.py +28 -5
- ksadk/harness/conformance/contract.py +9 -11
- ksadk/harness/context_engine.py +18 -33
- ksadk/harness/context_sections.py +397 -0
- ksadk/harness/diagnostic_adapters/__init__.py +1 -0
- ksadk/harness/diagnostic_adapters/contracts.py +70 -0
- ksadk/harness/diagnostic_adapters/lsp_rpc.py +210 -0
- ksadk/harness/diagnostic_adapters/native_lsp.py +286 -0
- ksadk/harness/engine/completion_guard.py +16 -1
- ksadk/harness/engine/context_pipeline.py +864 -92
- ksadk/harness/engine/graph_builder.py +123 -630
- ksadk/harness/engine/hooked_reasoner.py +380 -0
- ksadk/harness/engine/langgraph.py +126 -8
- ksadk/harness/engine/mcp_disclosure.py +65 -114
- ksadk/harness/engine/phases/__init__.py +6 -0
- ksadk/harness/engine/phases/context.py +48 -0
- ksadk/harness/engine/phases/interaction.py +31 -0
- ksadk/harness/engine/phases/reason.py +552 -0
- ksadk/harness/engine/phases/tools.py +638 -0
- ksadk/harness/engine/policy_runtime.py +21 -10
- ksadk/harness/engine/postgres_checkpointer.py +325 -2
- ksadk/harness/engine/run_control_bridge.py +21 -1
- ksadk/harness/engine/run_types.py +10 -0
- ksadk/harness/engine/skill_disclosure.py +98 -12
- ksadk/harness/engine/steering.py +177 -0
- ksadk/harness/engine/subagents.py +18 -1
- ksadk/harness/engine/tool_dispatch.py +112 -7
- ksadk/harness/events.py +39 -2
- ksadk/harness/execution_policy.py +10 -0
- ksadk/harness/hooks.py +259 -0
- ksadk/harness/loop/reason.py +281 -36
- ksadk/harness/loop/tools.py +157 -12
- ksadk/harness/managed_runtime.py +254 -94
- ksadk/harness/mcp_disclosure_contract.py +85 -0
- ksadk/harness/mcp_result_policy.py +44 -0
- ksadk/harness/mcp_runtime.py +33 -0
- ksadk/harness/micro_compact.py +69 -0
- ksadk/harness/model_adapters/__init__.py +1 -0
- ksadk/harness/model_adapters/native_mcp_media.py +100 -0
- ksadk/harness/model_adapters/native_mcp_result.py +36 -0
- ksadk/harness/model_adapters/native_openai.py +703 -0
- ksadk/harness/model_capability.py +223 -8
- ksadk/harness/model_provider.py +214 -4
- ksadk/harness/multimodal.py +57 -0
- ksadk/harness/native/__init__.py +1 -0
- ksadk/harness/native/activation_contract.py +25 -0
- ksadk/harness/native/activation_recovery.py +29 -0
- ksadk/harness/native/adapters.py +291 -0
- ksadk/harness/native/artifact_contract.py +14 -0
- ksadk/harness/native/artifact_partial_read_capacity.py +171 -0
- ksadk/harness/native/artifact_read_capacity.py +182 -0
- ksadk/harness/native/artifact_read_contract.py +27 -0
- ksadk/harness/native/artifact_runtime.py +408 -0
- ksadk/harness/native/artifact_search_capacity.py +206 -0
- ksadk/harness/native/artifact_search_contract.py +40 -0
- ksadk/harness/native/artifact_single_read_capacity.py +170 -0
- ksadk/harness/native/browser_contract.py +229 -0
- ksadk/harness/native/browser_recovery.py +183 -0
- ksadk/harness/native/capabilities.py +204 -0
- ksadk/harness/native/child_approval.py +60 -0
- ksadk/harness/native/child_budget.py +136 -0
- ksadk/harness/native/child_cancellation.py +80 -0
- ksadk/harness/native/child_input.py +98 -0
- ksadk/harness/native/child_input_runtime.py +59 -0
- ksadk/harness/native/child_interruption.py +81 -0
- ksadk/harness/native/child_lifecycle.py +246 -0
- ksadk/harness/native/child_lifecycle_contract.py +91 -0
- ksadk/harness/native/child_notifications.py +75 -0
- ksadk/harness/native/child_promotion.py +66 -0
- ksadk/harness/native/command_runtime.py +99 -0
- ksadk/harness/native/completion.py +302 -0
- ksadk/harness/native/completion_text.py +116 -0
- ksadk/harness/native/context.py +358 -0
- ksadk/harness/native/context_artifact_page.py +75 -0
- ksadk/harness/native/context_compaction_projection.py +131 -0
- ksadk/harness/native/context_contributions.py +320 -0
- ksadk/harness/native/context_contributor_contract.py +133 -0
- ksadk/harness/native/context_driver.py +820 -0
- ksadk/harness/native/context_fresh_tools.py +49 -0
- ksadk/harness/native/context_history.py +272 -0
- ksadk/harness/native/context_microcompact.py +61 -0
- ksadk/harness/native/context_partial_summary.py +58 -0
- ksadk/harness/native/context_partition.py +492 -0
- ksadk/harness/native/context_pruning.py +275 -0
- ksadk/harness/native/context_reduction.py +60 -0
- ksadk/harness/native/context_replay.py +148 -0
- ksadk/harness/native/context_request_projection.py +526 -0
- ksadk/harness/native/context_runtime.py +976 -0
- ksadk/harness/native/context_runtime_contracts.py +409 -0
- ksadk/harness/native/context_search.py +112 -0
- ksadk/harness/native/context_source_fragments.py +188 -0
- ksadk/harness/native/context_source_progress.py +119 -0
- ksadk/harness/native/context_summary_planning.py +788 -0
- ksadk/harness/native/context_summary_recovery.py +105 -0
- ksadk/harness/native/delivery_review.py +331 -0
- ksadk/harness/native/delivery_review_contract.py +54 -0
- ksadk/harness/native/effect_admission.py +82 -0
- ksadk/harness/native/effect_control.py +318 -0
- ksadk/harness/native/effect_receipts.py +729 -0
- ksadk/harness/native/effect_runtime.py +303 -0
- ksadk/harness/native/effective_configuration.py +28 -0
- ksadk/harness/native/engine.py +945 -0
- ksadk/harness/native/final_output.py +34 -0
- ksadk/harness/native/final_submission.py +58 -0
- ksadk/harness/native/finalization_workspace.py +96 -0
- ksadk/harness/native/fork.py +151 -0
- ksadk/harness/native/guidance.py +91 -0
- ksadk/harness/native/history.py +381 -0
- ksadk/harness/native/hook_executor.py +205 -0
- ksadk/harness/native/hook_runtime_contract.py +282 -0
- ksadk/harness/native/interaction_observation.py +117 -0
- ksadk/harness/native/lease.py +103 -0
- ksadk/harness/native/machine.py +974 -0
- ksadk/harness/native/mcp_result_governance.py +156 -0
- ksadk/harness/native/model.py +570 -0
- ksadk/harness/native/model_feedback.py +63 -0
- ksadk/harness/native/model_input.py +30 -0
- ksadk/harness/native/model_recovery_contract.py +35 -0
- ksadk/harness/native/model_replay.py +128 -0
- ksadk/harness/native/model_request.py +133 -0
- ksadk/harness/native/model_runtime.py +196 -0
- ksadk/harness/native/model_takeover.py +419 -0
- ksadk/harness/native/model_tool_batch.py +40 -0
- ksadk/harness/native/observed_progress.py +46 -0
- ksadk/harness/native/operator_guidance.py +201 -0
- ksadk/harness/native/output_contract.py +80 -0
- ksadk/harness/native/output_recovery.py +24 -0
- ksadk/harness/native/ports.py +749 -0
- ksadk/harness/native/precompact_hook_runtime.py +171 -0
- ksadk/harness/native/replay_context.py +149 -0
- ksadk/harness/native/request_media.py +112 -0
- ksadk/harness/native/restore_contract.py +16 -0
- ksadk/harness/native/run_clock.py +120 -0
- ksadk/harness/native/state.py +436 -0
- ksadk/harness/native/steering.py +170 -0
- ksadk/harness/native/stop_hook_runtime.py +151 -0
- ksadk/harness/native/studio_admission.py +29 -0
- ksadk/harness/native/subagents.py +86 -0
- ksadk/harness/native/task_policy.py +99 -0
- ksadk/harness/native/task_progress.py +86 -0
- ksadk/harness/native/terminal_verification.py +43 -0
- ksadk/harness/native/tool_argument_feedback.py +178 -0
- ksadk/harness/native/tool_budget.py +253 -0
- ksadk/harness/native/tool_error_streak.py +89 -0
- ksadk/harness/native/tool_hook_runtime.py +343 -0
- ksadk/harness/native/tool_input_validation.py +58 -0
- ksadk/harness/native/tool_interruption.py +96 -0
- ksadk/harness/native/tool_observation.py +259 -0
- ksadk/harness/native/tool_progress.py +223 -0
- ksadk/harness/native/tool_recovery.py +25 -0
- ksadk/harness/native/tool_scheduling.py +33 -0
- ksadk/harness/native/tool_schema.py +126 -0
- ksadk/harness/native/transitions.py +151 -0
- ksadk/harness/native/turn_control.py +98 -0
- ksadk/harness/native/user_document.py +98 -0
- ksadk/harness/native/user_document_capture.py +49 -0
- ksadk/harness/native/user_input.py +87 -0
- ksadk/harness/native/verification.py +432 -0
- ksadk/harness/native/verification_binding.py +40 -0
- ksadk/harness/native/verification_runtime.py +233 -0
- ksadk/harness/native/verification_workspace.py +67 -0
- ksadk/harness/native_driver_failure.py +123 -0
- ksadk/harness/native_facade.py +977 -0
- ksadk/harness/native_factory.py +244 -0
- ksadk/harness/native_projection.py +503 -0
- ksadk/harness/native_runtime.py +621 -0
- ksadk/harness/native_shadow.py +250 -0
- ksadk/harness/native_shadow_inputs.py +146 -0
- ksadk/harness/progress_adapters/__init__.py +5 -0
- ksadk/harness/progress_adapters/native_todo.py +75 -0
- ksadk/harness/prompt_cache.py +65 -3
- ksadk/harness/public_activity.py +59 -0
- ksadk/harness/public_output.py +30 -0
- ksadk/harness/public_summary.py +36 -0
- ksadk/harness/reasoner.py +331 -22
- ksadk/harness/rpc.py +200 -0
- ksadk/harness/run_control.py +107 -2
- ksadk/harness/runtime.py +11 -2
- ksadk/harness/runtime_capabilities.py +71 -1
- ksadk/harness/sandbox_backend.py +203 -0
- ksadk/harness/sdk.py +153 -0
- ksadk/harness/session_store.py +370 -24
- ksadk/harness/skill_adapters/__init__.py +1 -0
- ksadk/harness/skill_adapters/native_bundle.py +148 -0
- ksadk/harness/skill_adapters/native_disclosure.py +306 -0
- ksadk/harness/skill_intent.py +47 -0
- ksadk/harness/skill_runtime.py +74 -16
- ksadk/harness/spec.py +20 -10
- ksadk/harness/state.py +2 -0
- ksadk/harness/stores/__init__.py +14 -0
- ksadk/harness/stores/native_command_settlement.py +65 -0
- ksadk/harness/stores/native_contract.py +311 -0
- ksadk/harness/stores/native_memory.py +326 -0
- ksadk/harness/stores/native_memory_archive.py +70 -0
- ksadk/harness/stores/native_migration_cli.py +91 -0
- ksadk/harness/stores/native_outbox.py +56 -0
- ksadk/harness/stores/native_sqlite.py +782 -0
- ksadk/harness/stores/native_sqlite_audit.py +29 -0
- ksadk/harness/stores/native_sqlite_migration.py +252 -0
- ksadk/harness/subagent.py +12 -2
- ksadk/harness/subagent_adapters/checkpoint_recovery.py +120 -0
- ksadk/harness/subagent_adapters/native_background_child.py +803 -0
- ksadk/harness/subagent_adapters/native_child.py +819 -0
- ksadk/harness/subagent_adapters/native_child_approval.py +128 -0
- ksadk/harness/subagent_adapters/native_child_continuation.py +51 -0
- ksadk/harness/subagent_adapters/native_child_result.py +392 -0
- ksadk/harness/subagent_adapters/prepared_recovery.py +120 -0
- ksadk/harness/tool_display.py +75 -0
- ksadk/harness/tool_display_contract.py +134 -0
- ksadk/harness/tool_output.py +141 -0
- ksadk/harness/tool_policy.py +3 -0
- ksadk/harness/tool_result_policy.py +216 -0
- ksadk/harness/tools.py +52 -0
- ksadk/harness/workspace_adapters/__init__.py +6 -0
- ksadk/harness/workspace_adapters/native_directory.py +180 -0
- ksadk/harness/workspace_adapters/native_git.py +208 -0
- ksadk/harness/workspace_adapters/native_isolation.py +350 -0
- ksadk/interaction/providers/langgraph.py +8 -1
- ksadk/kernel/bootstrap.py +144 -160
- ksadk/kernel/contract_fingerprints.py +45 -1
- ksadk/kernel/contracts.py +25 -0
- ksadk/kernel/control.py +153 -33
- ksadk/kernel/execution_grants.py +209 -2
- ksadk/kernel/execution_grants_memory.py +127 -8
- ksadk/kernel/execution_grants_postgres.py +188 -10
- ksadk/kernel/execution_grants_sqlite.py +235 -9
- ksadk/kernel/execution_host_ingress.py +1071 -0
- ksadk/kernel/history_projection.py +120 -0
- ksadk/kernel/ingress.py +117 -204
- ksadk/kernel/ingress_bootstrap.py +268 -0
- ksadk/kernel/legacy_history.py +179 -0
- ksadk/kernel/memory_store.py +38 -48
- ksadk/kernel/memory_store_projection.py +63 -0
- ksadk/kernel/postgres_event_log.py +181 -0
- ksadk/kernel/postgres_store.py +167 -198
- ksadk/kernel/readiness.py +125 -0
- ksadk/kernel/recovery.py +89 -3
- ksadk/kernel/recovery_projection.py +124 -0
- ksadk/kernel/runtime_checkpoint.py +34 -0
- ksadk/kernel/sql/001_agent_kernel.sql +5 -0
- ksadk/kernel/sqlite_schema.py +100 -0
- ksadk/kernel/sqlite_store.py +147 -216
- ksadk/kernel/store.py +47 -15
- ksadk/kernel/teams_artifact_tools.py +392 -0
- ksadk/kernel/teams_effects.py +851 -0
- ksadk/kernel/teams_execution_context.py +408 -0
- ksadk/kernel/teams_host_http.py +237 -0
- ksadk/kernel/teams_material_transport.py +245 -0
- ksadk/kernel/teams_materials.py +318 -0
- ksadk/kernel/teams_runtime_bootstrap.py +604 -0
- ksadk/kernel/teams_tool_runtime.py +273 -0
- ksadk/kernel/teams_workspace.py +259 -0
- ksadk/kernel/worker.py +323 -332
- ksadk/kernel/worker_controls.py +454 -0
- ksadk/kernel/worker_identity.py +27 -0
- ksadk/kernel/worker_interactions.py +197 -0
- ksadk/knowledge_base/client.py +15 -1
- ksadk/managed_runtime.py +29 -2
- ksadk/memory/adk/backends/http_ltm_backend.py +2 -1
- ksadk/memory/adk/backends/sdk_ltm_backend.py +15 -1
- ksadk/memory/adk/bounded_database_session_service.py +232 -0
- ksadk/memory/adk/resilient_session_service.py +115 -15
- ksadk/memory/adk/short_term_memory.py +8 -9
- ksadk/memory/extraction.py +120 -7
- ksadk/memory/providers/local_candidates.py +183 -0
- ksadk/memory/providers/local_sqlite.py +252 -78
- ksadk/memory/resolved_policy.py +12 -7
- ksadk/model_gateway/__init__.py +29 -0
- ksadk/model_gateway/client.py +253 -0
- ksadk/model_gateway/events.py +113 -0
- ksadk/model_gateway/matrix.py +297 -0
- ksadk/model_proxy/compat.py +670 -0
- ksadk/model_proxy/server.py +10 -7
- ksadk/model_proxy/transform.py +37 -9
- ksadk/plugins/bridges/dsh.py +18 -20
- ksadk/plugins/bridges/dsh_profile_manifest.py +36 -0
- ksadk/plugins/builtin_resources.py +199 -0
- ksadk/plugins/builtins.py +380 -186
- ksadk/plugins/context_contributor.py +15 -4
- ksadk/plugins/dsh_dependency_policy.py +41 -0
- ksadk/plugins/dsh_toolchain.py +24 -35
- ksadk/plugins/execution_host.py +8 -0
- ksadk/plugins/host.py +73 -5
- ksadk/plugins/kernel_adapter.py +44 -1
- ksadk/plugins/memory_provider.py +180 -0
- ksadk/plugins/providers/_process_group.py +50 -0
- ksadk/plugins/providers/bundles/dsh-knowledge/index.mjs +24 -2
- ksadk/plugins/providers/bundles/dsh-knowledge/package.json +1 -1
- ksadk/plugins/providers/bundles/dsh-memory/package.json +1 -1
- ksadk/plugins/providers/bundles/dsh-skill-center/package.json +1 -1
- ksadk/plugins/providers/bundles/dsh-teams-tools/package.json +1 -1
- ksadk/plugins/providers/bundles/ksadk-dsh-capability-host/package.json +1 -1
- ksadk/plugins/providers/codex.py +42 -38
- ksadk/plugins/providers/codex_native.py +20 -0
- ksadk/plugins/providers/codex_skills.py +46 -0
- ksadk/plugins/providers/dsh_capabilities.py +16 -171
- ksadk/plugins/providers/dsh_connector_lease.py +225 -0
- ksadk/plugins/providers/dsh_mcp.py +163 -1
- ksadk/plugins/providers/harness.py +247 -34
- ksadk/plugins/providers/harness_context.py +61 -0
- ksadk/plugins/providers/harness_contributions.py +241 -0
- ksadk/plugins/providers/harness_delegation.py +91 -14
- ksadk/plugins/providers/harness_hooks.py +121 -0
- ksadk/plugins/providers/harness_managed.py +269 -175
- ksadk/plugins/providers/harness_tools.py +165 -36
- ksadk/plugins/providers/legacy_catalog.py +1 -1
- ksadk/plugins/providers/mcp_projection.py +100 -3
- ksadk/plugins/providers/platform_resources.py +16 -6
- ksadk/plugins/teams/application.py +3 -143
- ksadk/plugins/teams/build_artifacts.py +460 -0
- ksadk/plugins/teams/cloud_contract_fingerprints.py +22 -0
- ksadk/plugins/teams/cloud_contracts.py +928 -0
- ksadk/plugins/teams/cloud_permits.py +250 -0
- ksadk/plugins/teams/domain.py +201 -148
- ksadk/plugins/teams/effect_contracts.py +255 -0
- ksadk/plugins/teams/execution_projection.py +255 -0
- ksadk/plugins/teams/leader_decisions.py +106 -0
- ksadk/plugins/teams/postgres_store.py +299 -85
- ksadk/plugins/teams/release_contracts.py +60 -0
- ksadk/plugins/teams/runtime.py +116 -40
- ksadk/plugins/teams/store.py +214 -6
- ksadk/plugins/teams/task_decisions.py +21 -8
- ksadk/plugins/teams/tool_service.py +152 -0
- ksadk/plugins/teams/transport.py +8 -3
- ksadk/resource_runtime/skill_runtime.py +3 -0
- ksadk/resource_runtime/socket_server.py +11 -0
- ksadk/resource_runtime/worker.py +28 -4
- ksadk/runners/_adk_a2a_stream.py +122 -0
- ksadk/runners/_adk_canonical_stream.py +474 -0
- ksadk/runners/_langgraph_canonical_streams.py +527 -0
- ksadk/runners/_langgraph_runner_streams.py +6 -400
- ksadk/runners/_langgraph_tool_projection.py +86 -0
- ksadk/runners/_langgraph_tools_transformer.py +27 -0
- ksadk/runners/adk_runner.py +195 -290
- ksadk/runners/base_runner.py +6 -5
- ksadk/runners/langgraph_runner.py +82 -86
- ksadk/runners/utils/loader.py +28 -14
- ksadk/runtime/_runner_adapter/a2ui_surface.py +145 -0
- ksadk/runtime/_runner_adapter/gateway_approvals.py +93 -0
- ksadk/runtime/_runner_adapter/stream_mapping.py +83 -128
- ksadk/runtime/adapter.py +40 -3
- ksadk/runtime/conversation_execution.py +4 -2
- ksadk/runtime/executor.py +97 -7
- ksadk/runtime/factory.py +13 -6
- ksadk/runtime/framework_adapters.py +184 -10
- ksadk/runtime/hosted_finalizer.py +4 -6
- ksadk/runtime/launch.py +2 -0
- ksadk/runtime/runner_adapter.py +123 -13
- ksadk/runtime_context.py +2 -0
- ksadk/sandbox/backends/e2b.py +30 -4
- ksadk/sandbox/backends/local_process.py +10 -0
- ksadk/sandbox/e2b_connection.py +9 -1
- ksadk/sandbox/local_controls.py +32 -2
- ksadk/sandbox/local_launcher.py +34 -0
- ksadk/server/factory.py +178 -25
- ksadk/server/history_deadline.py +158 -0
- ksadk/server/history_page_cache.py +129 -0
- ksadk/server/routes/checkpoint_audit.py +88 -0
- ksadk/server/routes/checkpoint_listing.py +294 -0
- ksadk/server/routes/checkpoint_resolution.py +73 -20
- ksadk/server/routes/control.py +51 -3
- ksadk/server/routes/display_projection.py +154 -0
- ksadk/server/routes/kernel_ingress.py +17 -2
- ksadk/server/routes/misc.py +102 -12
- ksadk/server/routes/models.py +25 -1
- ksadk/server/routes/openai_compat.py +6 -0
- ksadk/server/routes/projection.py +159 -216
- ksadk/server/routes/run.py +6 -2
- ksadk/server/routes/sessions.py +301 -342
- ksadk/server/routes/streaming.py +68 -15
- ksadk/server/routes/tool_receipt_claim_routes.py +107 -0
- ksadk/server/routes/workspace.py +5 -2
- ksadk/server/static/assets/{ArtifactsPanel-C1YoaKhx.js → ArtifactsPanel-CILaW-fC.js} +1 -1
- ksadk/server/static/assets/{CodeBlock-DHuAWfr5.js → CodeBlock-BVrNVtJC.js} +1 -1
- ksadk/server/static/assets/{MathMessageMarkdown-cvdrBwYr.js → MathMessageMarkdown-Dp7c4wWD.js} +1 -1
- ksadk/server/static/assets/{MermaidBlock-DeBkbJvI.js → MermaidBlock-Dxop8Rd7.js} +6 -6
- ksadk/server/static/assets/{NativeTerminalPanel-oJj44_sV.js → NativeTerminalPanel-Cjjz8B30.js} +1 -1
- ksadk/server/static/assets/{abnfDiagram-VCTEODGH-Dhfv25o2.js → abnfDiagram-VCTEODGH-ckWDmOzw.js} +1 -1
- ksadk/server/static/assets/{arc-C35w-pn1.js → arc-DqxJede-.js} +1 -1
- ksadk/server/static/assets/architecture-7GRP2DOG-pn_DuLy6.js +1 -0
- ksadk/server/static/assets/{architectureDiagram-5GKGNRK7-FoMY_u6D.js → architectureDiagram-5GKGNRK7-SEQA4bVi.js} +1 -1
- ksadk/server/static/assets/{blockDiagram-NRAW4CY4-zD4Rt7oE.js → blockDiagram-NRAW4CY4-pM0B-6NJ.js} +1 -1
- ksadk/server/static/assets/{c4Diagram-UCG6FXSJ-BCtGGkhN.js → c4Diagram-UCG6FXSJ-m2tuCNVq.js} +1 -1
- ksadk/server/static/assets/channel-fySsnkft.js +1 -0
- ksadk/server/static/assets/chunk-2Q5K7J3B-BheGxKRQ.js +1 -0
- ksadk/server/static/assets/{chunk-5VM5RSS4-C2Ms13_k.js → chunk-5VM5RSS4-GJHDr9Ww.js} +1 -1
- ksadk/server/static/assets/{chunk-F27PBJKO-BoTj-qgx.js → chunk-F27PBJKO-CbAN45AV.js} +1 -1
- ksadk/server/static/assets/{chunk-G27WJ6UU-DOMyyjHH.js → chunk-G27WJ6UU-D5ngbbzF.js} +1 -1
- ksadk/server/static/assets/{chunk-JWPE2WC7-DbJJqDli.js → chunk-JWPE2WC7-Cc5IwuYC.js} +1 -1
- ksadk/server/static/assets/{chunk-LCL6LL3I-CLuRCt_W.js → chunk-LCL6LL3I-CprgDDdJ.js} +1 -1
- ksadk/server/static/assets/{chunk-POPQ4Y6H-D0Dz847e.js → chunk-POPQ4Y6H-CDZhSy82.js} +1 -1
- ksadk/server/static/assets/{chunk-RHFEMEQ7-BWSRzEcd.js → chunk-RHFEMEQ7-CZchUNro.js} +1 -1
- ksadk/server/static/assets/{chunk-SVP7TREG-CPoHqkCY.js → chunk-SVP7TREG-BVruqk6T.js} +1 -1
- ksadk/server/static/assets/{chunk-XXDRQBXY-Bx1jS-X-.js → chunk-XXDRQBXY-4ld9SxPN.js} +1 -1
- ksadk/server/static/assets/classDiagram-DTDB5LWJ-DSfLtNYm.js +1 -0
- ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-DSfLtNYm.js +1 -0
- ksadk/server/static/assets/{cose-bilkent-JH36ORCC-LzyWm4m0.js → cose-bilkent-JH36ORCC-Dmyyk_Vp.js} +1 -1
- ksadk/server/static/assets/cynefin-OW5HDTMX-PFWIGtvA.js +1 -0
- ksadk/server/static/assets/{cynefinDiagram-5FMLGOSQ-BlW_bHED.js → cynefinDiagram-5FMLGOSQ-BIyq3EJb.js} +1 -1
- ksadk/server/static/assets/{dagre-3AP2YEHR-Bu_S86_i.js → dagre-3AP2YEHR-eBw08Qdk.js} +1 -1
- ksadk/server/static/assets/{dagre-B7nCawed.js → dagre-DfvnEf45.js} +1 -1
- ksadk/server/static/assets/{diagram-S7CK7UJ4-W_Zow2Km.js → diagram-S7CK7UJ4-CUSrE3Mg.js} +1 -1
- ksadk/server/static/assets/{diagram-UQ7AKVKN-CLIKAHON.js → diagram-UQ7AKVKN-Dq5Zw2gy.js} +1 -1
- ksadk/server/static/assets/{diagram-VSXAHHWV-Dv6_QAlN.js → diagram-VSXAHHWV-DyUHfNwT.js} +1 -1
- ksadk/server/static/assets/{diagram-VX7I27RA-BWAWRDtZ.js → diagram-VX7I27RA-CREmM89O.js} +1 -1
- ksadk/server/static/assets/{diagram-Z3DM3KII-XA_rWMss.js → diagram-Z3DM3KII-Dw9zhHUK.js} +1 -1
- ksadk/server/static/assets/{dist-CGt_UGeO.js → dist-0uJ4tdx6.js} +1 -1
- ksadk/server/static/assets/{dist-C0J5_3qM.js → dist-AEv-vXf-.js} +1 -1
- ksadk/server/static/assets/{dist-CIpWk_5f.js → dist-B49GzZDb.js} +1 -1
- ksadk/server/static/assets/{dist-B3bA05-e.js → dist-B8Myiet9.js} +1 -1
- ksadk/server/static/assets/{dist-DWfdmz9s.js → dist-BBsYarrI.js} +1 -1
- ksadk/server/static/assets/{dist-BLpRy_Yx.js → dist-BQMrUwdI.js} +1 -1
- ksadk/server/static/assets/{dist-CIRMvUM4.js → dist-BX_-FENW.js} +1 -1
- ksadk/server/static/assets/{dist-BdNFAney.js → dist-CD4L6ymH.js} +1 -1
- ksadk/server/static/assets/{dist-n3n6t_FO.js → dist-CHpW1BHj.js} +1 -1
- ksadk/server/static/assets/{dist-DppE_r-D.js → dist-CVPau3tn.js} +1 -1
- ksadk/server/static/assets/{dist-qe8xjesy.js → dist-C_qdxcSH.js} +1 -1
- ksadk/server/static/assets/{dist-2vL2sAdF.js → dist-Co68Apq4.js} +1 -1
- ksadk/server/static/assets/{dist-1nXCdsej.js → dist-Cp2PaOMY.js} +1 -1
- ksadk/server/static/assets/{dist-DNKuMzWc.js → dist-CuR5Bgme.js} +1 -1
- ksadk/server/static/assets/{dist-t6MzE0jU.js → dist-DDSyLEOX.js} +1 -1
- ksadk/server/static/assets/{dist-CPyieXEf.js → dist-DUxO0R99.js} +1 -1
- ksadk/server/static/assets/{dist-DyG6Ya-z.js → dist-QzbGrED_.js} +1 -1
- ksadk/server/static/assets/{dist-0X_j2Rcc.js → dist-bupkyEBZ.js} +1 -1
- ksadk/server/static/assets/{dist-mqD5TZup.js → dist-cxTGfdqx.js} +1 -1
- ksadk/server/static/assets/{dist-M-SrdhhZ.js → dist-hL5p1til.js} +1 -1
- ksadk/server/static/assets/{dist-D-92S-Fd.js → dist-lOy23y43.js} +1 -1
- ksadk/server/static/assets/{dist-BO_UwatH.js → dist-pq-nD33R.js} +1 -1
- ksadk/server/static/assets/{ebnfDiagram-PWID7BFC-BfCzF1Xi.js → ebnfDiagram-PWID7BFC-BS5LdNoR.js} +1 -1
- ksadk/server/static/assets/{erDiagram-SSCWMZ5O-Dpz9_0zn.js → erDiagram-SSCWMZ5O-Bv1QtiY-.js} +1 -1
- ksadk/server/static/assets/eventmodeling-NTZA5JFV-DsM4upQX.js +1 -0
- ksadk/server/static/assets/flowDiagram-A5DVABFB-D5NA16k9.js +1 -0
- ksadk/server/static/assets/{ganttDiagram-EL5Y4UJY-DDaG1f4_.js → ganttDiagram-EL5Y4UJY-musi-e0G.js} +1 -1
- ksadk/server/static/assets/gitGraph-4MIJSDKK-DUCVz-ih.js +1 -0
- ksadk/server/static/assets/{gitGraphDiagram-WWUBYQGX-DcxzRwYC.js → gitGraphDiagram-WWUBYQGX-DH37EGkG.js} +1 -1
- ksadk/server/static/assets/index-CZdkAvsv.js +244 -0
- ksadk/server/static/assets/index-CvXdHgF3.css +2 -0
- ksadk/server/static/assets/info-A6RAGUB7-rw0ZNHZp.js +1 -0
- ksadk/server/static/assets/{infoDiagram-RXCK75RN-CYMdn6lQ.js → infoDiagram-RXCK75RN-C1kEtv2y.js} +1 -1
- ksadk/server/static/assets/{ishikawaDiagram-5VMMS53U-CLHFAD6c.js → ishikawaDiagram-5VMMS53U-BCNPyMka.js} +1 -1
- ksadk/server/static/assets/{journeyDiagram-EYS64GPL-BHSKQGAl.js → journeyDiagram-EYS64GPL--cDbKnjP.js} +1 -1
- ksadk/server/static/assets/{kanban-definition-3QL26DDD-D5W3tjTT.js → kanban-definition-3QL26DDD-R1rAVw2f.js} +1 -1
- ksadk/server/static/assets/{katex-mtjOi4KM.js → katex-BT-X-V7U.js} +1 -1
- ksadk/server/static/assets/{linear-BETqsxE_.js → linear-DTR631iG.js} +1 -1
- ksadk/server/static/assets/{mermaid-parser.core-DPWrvs90.js → mermaid-parser.core-DfFzJhX8.js} +2 -2
- ksadk/server/static/assets/{mindmap-definition-FBJOCRG2-CJG2mfBP.js → mindmap-definition-FBJOCRG2-D4by_rmk.js} +1 -1
- ksadk/server/static/assets/packet-AYTQ26CC-Ca4Hvki9.js +1 -0
- ksadk/server/static/assets/{pegDiagram-XKGWAZYB-GjAPNaqn.js → pegDiagram-XKGWAZYB-xWXPEh0c.js} +1 -1
- ksadk/server/static/assets/pie-WAS4IAKB-hwiz6fbw.js +1 -0
- ksadk/server/static/assets/{pieDiagram-E7YTZNPT-ToIewrqr.js → pieDiagram-E7YTZNPT-BudBDlCI.js} +1 -1
- ksadk/server/static/assets/{quadrantDiagram-AXDQQJYC-4d78KiEY.js → quadrantDiagram-AXDQQJYC-DXZ0PCJF.js} +1 -1
- ksadk/server/static/assets/radar-RG4KPBEZ-BR1oZXLM.js +1 -0
- ksadk/server/static/assets/railroad-74A4TZTK-DfgEISfX.js +1 -0
- ksadk/server/static/assets/railroad-abnf-HS5TGJTU-CWOC3rdk.js +1 -0
- ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-CiRvHCLY.js +1 -0
- ksadk/server/static/assets/railroad-peg-WCYAUIDC-DSDDyJ2f.js +1 -0
- ksadk/server/static/assets/{railroadDiagram-O6MQD6OU-DKzx4xfv.js → railroadDiagram-O6MQD6OU-BdAYRYB8.js} +1 -1
- ksadk/server/static/assets/{requirementDiagram-EFPCY7ZU-CJYljxQS.js → requirementDiagram-EFPCY7ZU-CBBmaL70.js} +1 -1
- ksadk/server/static/assets/{sankeyDiagram-P5KCCOFB-DLU2fV1w.js → sankeyDiagram-P5KCCOFB-Doc3rdwp.js} +1 -1
- ksadk/server/static/assets/{sequenceDiagram-WJ2MYXX4-CVqysrA9.js → sequenceDiagram-WJ2MYXX4-0J8R8hWW.js} +1 -1
- ksadk/server/static/assets/{sizeCapture-X5ZJPWSS-BUxfmTHc.js → sizeCapture-X5ZJPWSS-CfFLlWsK.js} +1 -1
- ksadk/server/static/assets/{stateDiagram-HBIQ2CUA-CNFgYI9E.js → stateDiagram-HBIQ2CUA-jBwkjtTy.js} +1 -1
- ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-Cw1fPb5w.js +1 -0
- ksadk/server/static/assets/{swimlanes-XN3QIQJK-B6qCMe8N.js → swimlanes-XN3QIQJK-B0WxTQf8.js} +1 -1
- ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-Cc3JMBAF.js +8 -0
- ksadk/server/static/assets/{timeline-definition-24CTP7MA-CMD3x_U_.js → timeline-definition-24CTP7MA-BfCT_75A.js} +1 -1
- ksadk/server/static/assets/treeView-Q6P3EWNA-C05SJHxo.js +1 -0
- ksadk/server/static/assets/treemap-WGGIJYW6-BqNLAhc3.js +1 -0
- ksadk/server/static/assets/{vennDiagram-4TSXK5OY-BqtUqvXM.js → vennDiagram-4TSXK5OY-9gX1VMDC.js} +1 -1
- ksadk/server/static/assets/wardley-WFR3VGLG-DokNktqB.js +1 -0
- ksadk/server/static/assets/{wardleyDiagram-VM6X3IG4-B5KfDjI-.js → wardleyDiagram-VM6X3IG4-sEs_BP6O.js} +1 -1
- ksadk/server/static/assets/{xychartDiagram-S5SC5T6Z-BaUlSZrn.js → xychartDiagram-S5SC5T6Z-Ll4jvUN9.js} +1 -1
- ksadk/server/static/index.html +2 -2
- ksadk/sessions/__init__.py +8 -1
- ksadk/sessions/_checkpoint_resume_audit.py +44 -0
- ksadk/sessions/_in_memory_query.py +112 -0
- ksadk/sessions/_local_service_sync.py +157 -156
- ksadk/sessions/_local_state_sync.py +152 -0
- ksadk/sessions/_local_tables.py +2 -0
- ksadk/sessions/_postgres_checkpoint_read.py +323 -0
- ksadk/sessions/_postgres_checkpoint_stats.py +330 -0
- ksadk/sessions/_postgres_history_read.py +678 -0
- ksadk/sessions/_postgres_schema.py +44 -2
- ksadk/sessions/_postgres_tables.py +2 -0
- ksadk/sessions/_postgres_tool_receipts.py +169 -0
- ksadk/sessions/_resilient_read.py +630 -0
- ksadk/sessions/_tool_receipt_sync.py +119 -0
- ksadk/sessions/agent_identity.py +16 -0
- ksadk/sessions/base.py +278 -0
- ksadk/sessions/db_budget.py +332 -0
- ksadk/sessions/errors.py +12 -0
- ksadk/sessions/history_budget.py +36 -0
- ksadk/sessions/history_identity.py +27 -0
- ksadk/sessions/in_memory.py +376 -113
- ksadk/sessions/local_service.py +345 -0
- ksadk/sessions/postgres_service.py +515 -549
- ksadk/sessions/resilience.py +21 -14
- ksadk/sessions/resilient.py +611 -504
- ksadk/skills/loader.py +44 -2
- ksadk/skills/runtime/backends/e2b.py +17 -14
- ksadk/skills/service_client.py +6 -1
- ksadk/studio/a2a_bindings.py +407 -0
- ksadk/studio/a2a_orchestration.py +178 -0
- ksadk/studio/active_run_output.py +92 -0
- ksadk/studio/activity_records.py +542 -0
- ksadk/studio/agent_configuration.py +173 -0
- ksadk/studio/api.py +219 -389
- ksadk/studio/api_a2a_routes.py +93 -0
- ksadk/studio/api_catalog_routes.py +13 -0
- ksadk/studio/api_cloud_chat_routes.py +382 -0
- ksadk/studio/api_contracts.py +23 -0
- ksadk/studio/attachment_store.py +14 -2
- ksadk/studio/build_resolution.py +117 -0
- ksadk/studio/build_singleflight.py +37 -0
- ksadk/studio/builder.py +20 -2
- ksadk/studio/capabilities.py +8 -3
- ksadk/studio/cloud.py +83 -377
- ksadk/studio/cloud_gateways.py +424 -0
- ksadk/studio/cloud_shared_web.py +7 -0
- ksadk/studio/codex_agent_service.py +17 -0
- ksadk/studio/codex_manifest.py +5 -1
- ksadk/studio/codex_provider_build.py +65 -0
- ksadk/studio/compiler.py +102 -6
- ksadk/studio/contract_base.py +19 -0
- ksadk/studio/contracts.py +231 -201
- ksadk/studio/dsh_application.py +58 -12
- ksadk/studio/dsh_capability_service.py +17 -171
- ksadk/studio/dsh_mcp_transport.py +191 -0
- ksadk/studio/event_store.py +17 -0
- ksadk/studio/execution_host.py +84 -11
- ksadk/studio/framework_run.py +18 -0
- ksadk/studio/interaction_submission.py +265 -0
- ksadk/studio/kernel_registry.py +12 -1
- ksadk/studio/lifecycle_status.py +43 -0
- ksadk/studio/model_buffered_wire.py +227 -0
- ksadk/studio/model_chat_tools.py +143 -0
- ksadk/studio/model_client.py +1241 -761
- ksadk/studio/model_content_stream.py +129 -0
- ksadk/studio/model_credentials.py +196 -0
- ksadk/studio/model_profile_service.py +65 -31
- ksadk/studio/model_request_projection.py +284 -0
- ksadk/studio/model_responses_content.py +296 -0
- ksadk/studio/model_usage.py +109 -0
- ksadk/studio/model_wire_failure.py +110 -0
- ksadk/studio/model_wire_identity.py +138 -0
- ksadk/studio/model_wire_snapshot.py +45 -0
- ksadk/studio/model_wire_tools.py +283 -0
- ksadk/studio/native_acceptance.py +68 -0
- ksadk/studio/native_approval.py +111 -0
- ksadk/studio/native_browser_port.py +861 -0
- ksadk/studio/native_child_mcp.py +87 -0
- ksadk/studio/native_child_publication.py +68 -0
- ksadk/studio/native_child_skills.py +72 -0
- ksadk/studio/native_child_workspace.py +176 -0
- ksadk/studio/native_command_policy.py +53 -0
- ksadk/studio/native_context_port.py +326 -0
- ksadk/studio/native_context_registration.py +54 -0
- ksadk/studio/native_document_input.py +88 -0
- ksadk/studio/native_final_shape.py +852 -0
- ksadk/studio/native_gateway_stream.py +69 -0
- ksadk/studio/native_hook_port.py +145 -0
- ksadk/studio/native_hook_registration.py +70 -0
- ksadk/studio/native_inventory_disclosure.py +223 -0
- ksadk/studio/native_kernel_admission.py +84 -0
- ksadk/studio/native_language_diagnostics.py +320 -0
- ksadk/studio/native_mcp_disclosure.py +198 -0
- ksadk/studio/native_mcp_tool_port.py +219 -0
- ksadk/studio/native_memory_acceptance.py +362 -0
- ksadk/studio/native_memory_context.py +266 -0
- ksadk/studio/native_memory_flush.py +174 -0
- ksadk/studio/native_memory_sources.py +80 -0
- ksadk/studio/native_memory_tool_port.py +360 -0
- ksadk/studio/native_memory_turn.py +183 -0
- ksadk/studio/native_model_port.py +765 -0
- ksadk/studio/native_model_recovery.py +126 -0
- ksadk/studio/native_options.py +75 -0
- ksadk/studio/native_output_fields.py +58 -0
- ksadk/studio/native_planning.py +156 -0
- ksadk/studio/native_product.py +988 -0
- ksadk/studio/native_read_budget.py +426 -0
- ksadk/studio/native_recovery.py +171 -0
- ksadk/studio/native_scope.py +35 -0
- ksadk/studio/native_session_context_port.py +141 -0
- ksadk/studio/native_session_engine.py +14 -0
- ksadk/studio/native_skill_source.py +74 -0
- ksadk/studio/native_subagent_port.py +700 -0
- ksadk/studio/native_terminal_recovery.py +95 -0
- ksadk/studio/native_test_action.py +610 -0
- ksadk/studio/native_tool_port.py +477 -0
- ksadk/studio/native_user_input.py +60 -0
- ksadk/studio/native_verification_presentation.py +65 -0
- ksadk/studio/native_workspace_diagnostics.py +183 -0
- ksadk/studio/native_workspace_port.py +43 -0
- ksadk/studio/operations.py +34 -9
- ksadk/studio/plugin_composition.py +26 -10
- ksadk/studio/plugin_kernel_adapter.py +75 -1
- ksadk/studio/plugin_native_activation.py +163 -0
- ksadk/studio/plugin_runtime.py +639 -119
- ksadk/studio/plugin_runtime_admission.py +57 -0
- ksadk/studio/presentation.py +92 -0
- ksadk/studio/public_output_store.py +69 -0
- ksadk/studio/resource_authority.py +11 -3
- ksadk/studio/resource_catalog.py +8 -12
- ksadk/studio/run_activity.py +338 -385
- ksadk/studio/run_controls.py +185 -0
- ksadk/studio/run_service.py +908 -319
- ksadk/studio/run_submission_receipts.py +68 -0
- ksadk/studio/runtime_catalog.py +23 -4
- ksadk/studio/runtime_prewarm.py +22 -0
- ksadk/studio/scheduler_assistant.py +4 -1
- ksadk/studio/service.py +356 -282
- ksadk/studio/service_settings.py +229 -0
- ksadk/studio/shared_web.py +393 -169
- ksadk/studio/shared_web_response_events.py +180 -0
- ksadk/studio/shared_web_run_state.py +133 -0
- ksadk/studio/skill_discovery.py +305 -3
- ksadk/studio/static/assets/ChannelsPage-xX5HlMId.js +8 -0
- ksadk/studio/static/assets/{CodeBlock-DMIf4h33-UIqo-BPW.js → CodeBlock-DMIf4h33-CkufcPYo.js} +3 -3
- ksadk/studio/static/assets/{MathMessageMarkdown-BesSeCYl-OhNwH4K9.js → MathMessageMarkdown-BesSeCYl-DYG1Wzbx.js} +1 -1
- ksadk/studio/static/assets/{MessageMarkdown-CwMTvgFj-g0I-I4dD.js → MessageMarkdown-CwMTvgFj-BeyLyQHu.js} +2 -2
- ksadk/studio/static/assets/TeamsPage-CCaaGaVp.js +3 -0
- ksadk/studio/static/assets/index-C7DNDik2.css +2 -0
- ksadk/studio/static/assets/index-Cy68gTlH.js +265 -0
- ksadk/studio/static/index.html +3 -3
- ksadk/studio/teams_catalog.py +33 -0
- ksadk/studio/teams_installation.py +4 -1
- ksadk/studio/teams_node.py +4 -0
- ksadk/studio/teams_node_factory.py +558 -0
- ksadk/studio/teams_node_runner.py +3 -0
- ksadk/studio/teams_node_v1.py +935 -0
- ksadk/studio/teams_remote.py +259 -37
- ksadk/studio/templates.py +1 -0
- ksadk/studio/workspace_plugins.py +3 -1
- ksadk/tools/a2a_policy.py +5 -0
- ksadk/tools/artifact_observation.py +53 -0
- ksadk/tools/captured_source_artifact.py +68 -0
- ksadk/tools/schema.py +34 -0
- ksadk/toolsets/__init__.py +82 -88
- ksadk/toolsets/a2a.py +89 -89
- ksadk/toolsets/sandbox.py +377 -6
- ksadk/toolsets/skill_management.py +315 -0
- ksadk/toolsets/tool_selection.py +94 -0
- ksadk/toolsets/workspace.py +342 -324
- ksadk/toolsets/workspace_editing.py +291 -0
- ksadk/toolsets/workspace_model_observation.py +104 -0
- ksadk/toolsets/workspace_mutation.py +75 -0
- ksadk/toolsets/workspace_read_budget.py +216 -0
- ksadk/toolsets/workspace_search.py +192 -0
- ksadk/toolsets/workspace_search_process.py +129 -0
- ksadk/toolsets/workspace_state.py +6 -0
- ksadk/version.py +1 -1
- ksadk_runtime_common/http_headers.py +18 -0
- ksadk_runtime_common/workspace_files/router.py +2 -1
- ksadk/server/static/assets/architecture-7GRP2DOG-BCsa26zi.js +0 -1
- ksadk/server/static/assets/channel-_KDifNys.js +0 -1
- ksadk/server/static/assets/chunk-2Q5K7J3B-HdVkJ9F0.js +0 -1
- ksadk/server/static/assets/classDiagram-DTDB5LWJ-BVCW3ZqZ.js +0 -1
- ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-BVCW3ZqZ.js +0 -1
- ksadk/server/static/assets/cynefin-OW5HDTMX-CNXjFctL.js +0 -1
- ksadk/server/static/assets/eventmodeling-NTZA5JFV-B5-8RH9c.js +0 -1
- ksadk/server/static/assets/flowDiagram-A5DVABFB-BppFxEKw.js +0 -1
- ksadk/server/static/assets/gitGraph-4MIJSDKK-B-AhYj4C.js +0 -1
- ksadk/server/static/assets/index-BMd2mucF.css +0 -2
- ksadk/server/static/assets/index-D5qyyhTH.js +0 -244
- ksadk/server/static/assets/info-A6RAGUB7-0uiKrC35.js +0 -1
- ksadk/server/static/assets/packet-AYTQ26CC-BVTmZ_cw.js +0 -1
- ksadk/server/static/assets/pie-WAS4IAKB-DyfxBU7V.js +0 -1
- ksadk/server/static/assets/radar-RG4KPBEZ-FFontjL2.js +0 -1
- ksadk/server/static/assets/railroad-74A4TZTK-D0Uidzen.js +0 -1
- ksadk/server/static/assets/railroad-abnf-HS5TGJTU-BOo_9T2h.js +0 -1
- ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-D6-BjW7Z.js +0 -1
- ksadk/server/static/assets/railroad-peg-WCYAUIDC-CXx__yMm.js +0 -1
- ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-BXAFScz8.js +0 -1
- ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-uIQ2lJKH.js +0 -8
- ksadk/server/static/assets/treeView-Q6P3EWNA-CK5GgucZ.js +0 -1
- ksadk/server/static/assets/treemap-WGGIJYW6-Bq1u1SpG.js +0 -1
- ksadk/server/static/assets/wardley-WFR3VGLG-QAt06uEz.js +0 -1
- ksadk/studio/static/assets/ChannelsPage-D_PGmKVq.js +0 -8
- ksadk/studio/static/assets/TeamsPage-DqX4HWKQ.js +0 -3
- ksadk/studio/static/assets/index-CfEnms6Y.css +0 -2
- ksadk/studio/static/assets/index-Dp61rOWZ.js +0 -0
- {agentengine_sdk_python-0.8.5.dist-info → agentengine_sdk_python-0.8.6.dist-info}/WHEEL +0 -0
- {agentengine_sdk_python-0.8.5.dist-info → agentengine_sdk_python-0.8.6.dist-info}/entry_points.txt +0 -0
- {agentengine_sdk_python-0.8.5.dist-info → agentengine_sdk_python-0.8.6.dist-info}/licenses/LICENSE +0 -0
- {agentengine_sdk_python-0.8.5.dist-info → agentengine_sdk_python-0.8.6.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,703 @@
|
|
|
1
|
+
"""OpenAI-compatible ModelPort with sealed SSE turns and host-owned transport.
|
|
2
|
+
|
|
3
|
+
HTTP protocol fixtures exercise this adapter; they do not establish model quality
|
|
4
|
+
or endpoint compatibility beyond the covered chat protocol fixtures.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import math
|
|
10
|
+
from collections.abc import AsyncIterator
|
|
11
|
+
from datetime import datetime, timezone
|
|
12
|
+
from email.utils import parsedate_to_datetime
|
|
13
|
+
|
|
14
|
+
import httpx
|
|
15
|
+
from pydantic import ValidationError
|
|
16
|
+
|
|
17
|
+
from ksadk._async_iterators import owning_async_context
|
|
18
|
+
from ksadk._model_json import load_model_json as _load_json
|
|
19
|
+
from ksadk._model_reasoning import chat_reasoning
|
|
20
|
+
from ksadk._model_refusal import chat_refusal
|
|
21
|
+
from ksadk._model_sse import ModelSSEIdleTimeout, model_sse_frames
|
|
22
|
+
from ksadk.model_proxy import compat as provider_compat
|
|
23
|
+
|
|
24
|
+
from ..native.adapters import _project_messages, _snapshot
|
|
25
|
+
from ..native.context_history import text_only_tool_message
|
|
26
|
+
from ..native.model import (
|
|
27
|
+
ModelFailureKind,
|
|
28
|
+
ModelImageContent,
|
|
29
|
+
ModelResponseKind,
|
|
30
|
+
ModelStreamEvent,
|
|
31
|
+
ModelTextContent,
|
|
32
|
+
ModelTurnResult,
|
|
33
|
+
ModelUsage,
|
|
34
|
+
normalize_response,
|
|
35
|
+
)
|
|
36
|
+
from ..native.model_replay import seal_model_replay
|
|
37
|
+
from ..native.ports import ModelRequest
|
|
38
|
+
from ..native.state import RunScope
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _usage(value: object) -> ModelUsage | None:
|
|
42
|
+
if value is None or value == {}:
|
|
43
|
+
return None
|
|
44
|
+
if not isinstance(value, dict):
|
|
45
|
+
raise ValueError("invalid usage report")
|
|
46
|
+
# The standard chat usage envelope reports both counters. Do not turn an
|
|
47
|
+
# incomplete report into fabricated zero usage; reject the protocol envelope.
|
|
48
|
+
if "prompt_tokens" not in value or "completion_tokens" not in value:
|
|
49
|
+
raise ValueError("incomplete usage report")
|
|
50
|
+
prompt_details = value.get("prompt_tokens_details")
|
|
51
|
+
completion_details = value.get("completion_tokens_details")
|
|
52
|
+
if prompt_details is None:
|
|
53
|
+
prompt_details = {}
|
|
54
|
+
if completion_details is None:
|
|
55
|
+
completion_details = {}
|
|
56
|
+
if not isinstance(prompt_details, dict) or not isinstance(completion_details, dict):
|
|
57
|
+
raise ValueError("invalid usage details")
|
|
58
|
+
return ModelUsage(
|
|
59
|
+
input_tokens=value["prompt_tokens"],
|
|
60
|
+
output_tokens=value["completion_tokens"],
|
|
61
|
+
cached_input_tokens=prompt_details.get("cached_tokens", 0),
|
|
62
|
+
reasoning_tokens=completion_details.get("reasoning_tokens", 0),
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _tools(value: object) -> tuple[dict[str, object], ...]:
|
|
67
|
+
if value is None:
|
|
68
|
+
return ()
|
|
69
|
+
if not isinstance(value, list):
|
|
70
|
+
raise ValueError("tool_calls must be an array")
|
|
71
|
+
calls = []
|
|
72
|
+
for raw in value:
|
|
73
|
+
if not isinstance(raw, dict) or raw.get("type") != "function":
|
|
74
|
+
raise ValueError("unsupported tool call envelope")
|
|
75
|
+
function = raw.get("function")
|
|
76
|
+
if not isinstance(function, dict) or not isinstance(function.get("arguments"), str):
|
|
77
|
+
raise ValueError("function arguments must be encoded JSON")
|
|
78
|
+
try:
|
|
79
|
+
arguments = _load_json(function["arguments"])
|
|
80
|
+
invalid = not isinstance(arguments, dict)
|
|
81
|
+
except (TypeError, ValueError):
|
|
82
|
+
arguments, invalid = None, True
|
|
83
|
+
calls.append(
|
|
84
|
+
{
|
|
85
|
+
"call_id": raw.get("id"),
|
|
86
|
+
"name": function.get("name"),
|
|
87
|
+
"arguments": {} if invalid else arguments,
|
|
88
|
+
"wire_arguments_invalid": invalid,
|
|
89
|
+
}
|
|
90
|
+
)
|
|
91
|
+
return tuple(calls)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _result(
|
|
95
|
+
request: ModelRequest,
|
|
96
|
+
kind: ModelResponseKind,
|
|
97
|
+
*,
|
|
98
|
+
finish_reason: str | None = None,
|
|
99
|
+
usage: ModelUsage | None = None,
|
|
100
|
+
text: str = "",
|
|
101
|
+
retry_after_seconds: float | None = None,
|
|
102
|
+
failure_kind: ModelFailureKind | None = None,
|
|
103
|
+
) -> ModelTurnResult:
|
|
104
|
+
return ModelTurnResult(
|
|
105
|
+
response_kind=kind,
|
|
106
|
+
request_id=request.request_id,
|
|
107
|
+
attempt_id=request.attempt_id,
|
|
108
|
+
finish_reason=finish_reason,
|
|
109
|
+
usage=usage,
|
|
110
|
+
text=text,
|
|
111
|
+
retry_after_seconds=retry_after_seconds,
|
|
112
|
+
failure_kind=failure_kind,
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def _parse_response(
|
|
117
|
+
request: ModelRequest,
|
|
118
|
+
content: bytes,
|
|
119
|
+
*,
|
|
120
|
+
compat_profile: provider_compat.CompatProfile | None = None,
|
|
121
|
+
) -> ModelTurnResult:
|
|
122
|
+
finish: str | None = None
|
|
123
|
+
usage: ModelUsage | None = None
|
|
124
|
+
try:
|
|
125
|
+
payload = _load_json(content)
|
|
126
|
+
if not isinstance(payload, dict) or "error" in payload:
|
|
127
|
+
raise ValueError("invalid response envelope")
|
|
128
|
+
choices = payload.get("choices")
|
|
129
|
+
if not isinstance(choices, list) or len(choices) > 1:
|
|
130
|
+
raise ValueError("expected one completion choice")
|
|
131
|
+
if not choices:
|
|
132
|
+
return _result(request, "empty_response", usage=_usage(payload.get("usage")))
|
|
133
|
+
choice = choices[0]
|
|
134
|
+
if not isinstance(choice, dict):
|
|
135
|
+
raise ValueError("invalid completion choice")
|
|
136
|
+
raw_finish = choice.get("finish_reason")
|
|
137
|
+
if raw_finish is not None and not isinstance(raw_finish, str):
|
|
138
|
+
raise ValueError("invalid finish reason")
|
|
139
|
+
finish = raw_finish
|
|
140
|
+
usage = _usage(payload.get("usage"))
|
|
141
|
+
message = choice.get("message")
|
|
142
|
+
if not isinstance(message, dict) or message.get("role") != "assistant":
|
|
143
|
+
raise ValueError("invalid assistant message")
|
|
144
|
+
if chat_refusal(message.get("refusal")):
|
|
145
|
+
finish = "content_filter"
|
|
146
|
+
text = message.get("content")
|
|
147
|
+
if text is None:
|
|
148
|
+
text = ""
|
|
149
|
+
if not isinstance(text, str):
|
|
150
|
+
raise ValueError("unsupported assistant content")
|
|
151
|
+
if compat_profile is not None:
|
|
152
|
+
text = provider_compat.project_inline_reasoning(text, compat_profile)
|
|
153
|
+
raw_calls = message.get("tool_calls")
|
|
154
|
+
try:
|
|
155
|
+
calls = _tools(raw_calls)
|
|
156
|
+
if "function_call" in message:
|
|
157
|
+
raise ValueError("legacy function_call protocol is not supported")
|
|
158
|
+
except (ValueError, TypeError):
|
|
159
|
+
# The normalizer owns precedence: e.g. length/content_filter must
|
|
160
|
+
# still win over a half-built tool batch. {} is a malformed envelope.
|
|
161
|
+
calls = ({},)
|
|
162
|
+
if finish is None and (text.strip() or raw_calls or calls):
|
|
163
|
+
return _result(
|
|
164
|
+
request,
|
|
165
|
+
"provider_retryable_error",
|
|
166
|
+
usage=usage,
|
|
167
|
+
text=text,
|
|
168
|
+
failure_kind="incomplete_response",
|
|
169
|
+
)
|
|
170
|
+
result = normalize_response(
|
|
171
|
+
request_id=request.request_id,
|
|
172
|
+
attempt_id=request.attempt_id,
|
|
173
|
+
finish_reason=finish,
|
|
174
|
+
text=text,
|
|
175
|
+
tool_calls=calls,
|
|
176
|
+
usage=usage,
|
|
177
|
+
)
|
|
178
|
+
return seal_model_replay(result, request.profile, chat_reasoning(message))
|
|
179
|
+
except (ValueError, TypeError, UnicodeError, ValidationError, RecursionError):
|
|
180
|
+
return _result(
|
|
181
|
+
request,
|
|
182
|
+
"provider_terminal_error",
|
|
183
|
+
finish_reason=finish,
|
|
184
|
+
usage=usage,
|
|
185
|
+
failure_kind="invalid_response",
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def _native_messages(request: ModelRequest) -> list[dict]:
|
|
190
|
+
"""Project host-supplied media without reading files or fetching remote URLs.
|
|
191
|
+
|
|
192
|
+
Chat tool messages carry textual receipts. Images are emitted in a user
|
|
193
|
+
observation only after every receipt in the assistant tool batch is present.
|
|
194
|
+
Plain paths stay plain text; only explicit image_url blocks are media.
|
|
195
|
+
"""
|
|
196
|
+
projected: list[dict] = []
|
|
197
|
+
pending: set[str] = set()
|
|
198
|
+
images: list[dict] = []
|
|
199
|
+
for message in _project_messages(request):
|
|
200
|
+
role = message["role"]
|
|
201
|
+
if role != "tool" and pending:
|
|
202
|
+
raise ValueError("incomplete assistant tool batch before next message")
|
|
203
|
+
if role == "assistant" and message.get("tool_calls"):
|
|
204
|
+
calls = message["tool_calls"]
|
|
205
|
+
if not isinstance(calls, list):
|
|
206
|
+
raise ValueError("assistant tool calls must be a list")
|
|
207
|
+
ids = [call.get("id") if isinstance(call, dict) else None for call in calls]
|
|
208
|
+
if any(not isinstance(identity, str) or not identity for identity in ids):
|
|
209
|
+
raise ValueError("assistant tool calls require stable IDs")
|
|
210
|
+
if len(set(ids)) != len(ids):
|
|
211
|
+
raise ValueError("duplicate assistant tool IDs")
|
|
212
|
+
pending = set(ids)
|
|
213
|
+
if role == "tool":
|
|
214
|
+
identity = message.get("tool_call_id")
|
|
215
|
+
if identity not in pending:
|
|
216
|
+
raise ValueError("tool receipt does not match the pending assistant batch")
|
|
217
|
+
pending.remove(identity)
|
|
218
|
+
content = message.get("content")
|
|
219
|
+
if isinstance(content, list):
|
|
220
|
+
blocks = []
|
|
221
|
+
for block in content:
|
|
222
|
+
if not isinstance(block, dict):
|
|
223
|
+
raise ValueError("chat content requires typed blocks")
|
|
224
|
+
model = ModelImageContent if block.get("type") == "image_url" else ModelTextContent
|
|
225
|
+
blocks.append(model.model_validate(block).model_dump(mode="json"))
|
|
226
|
+
media = [block for block in blocks if block["type"] == "image_url"]
|
|
227
|
+
if media and role == "tool":
|
|
228
|
+
text = "\n".join(block["text"] for block in blocks if block["type"] == "text")
|
|
229
|
+
if request.profile.image_input_mode == "text_only":
|
|
230
|
+
message = text_only_tool_message(message)
|
|
231
|
+
else:
|
|
232
|
+
message["content"] = text or "Image observation follows the tool batch."
|
|
233
|
+
images.extend(
|
|
234
|
+
[
|
|
235
|
+
{
|
|
236
|
+
"type": "text",
|
|
237
|
+
"text": f"Image observation for tool call {identity}:",
|
|
238
|
+
},
|
|
239
|
+
*media,
|
|
240
|
+
]
|
|
241
|
+
)
|
|
242
|
+
elif media and role != "user":
|
|
243
|
+
raise ValueError("image observations require user or tool content")
|
|
244
|
+
elif media and request.profile.image_input_mode == "text_only":
|
|
245
|
+
raise ValueError("model profile does not accept user image input")
|
|
246
|
+
else:
|
|
247
|
+
message["content"] = blocks
|
|
248
|
+
elif content is not None and not isinstance(content, str):
|
|
249
|
+
raise ValueError("chat content must be text or typed content blocks")
|
|
250
|
+
projected.append(message)
|
|
251
|
+
if role == "tool" and not pending and images:
|
|
252
|
+
projected.append({"role": "user", "content": images})
|
|
253
|
+
images = []
|
|
254
|
+
if pending:
|
|
255
|
+
raise ValueError("assistant tool batch is missing receipts")
|
|
256
|
+
return projected
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def _retry_after(value: str | None) -> float | None:
|
|
260
|
+
if value is None:
|
|
261
|
+
return None
|
|
262
|
+
try:
|
|
263
|
+
seconds = float(value)
|
|
264
|
+
except ValueError:
|
|
265
|
+
try:
|
|
266
|
+
instant = parsedate_to_datetime(value)
|
|
267
|
+
if instant.tzinfo is None:
|
|
268
|
+
instant = instant.replace(tzinfo=timezone.utc)
|
|
269
|
+
seconds = max(0.0, (instant - datetime.now(timezone.utc)).total_seconds())
|
|
270
|
+
except (ValueError, TypeError, OverflowError):
|
|
271
|
+
return None
|
|
272
|
+
return seconds if math.isfinite(seconds) and seconds >= 0 else None
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def _http_failure(request: ModelRequest, response: httpx.Response) -> ModelTurnResult | None:
|
|
276
|
+
status = response.status_code
|
|
277
|
+
if status in {408, 429} or 500 <= status <= 599:
|
|
278
|
+
return _result(
|
|
279
|
+
request,
|
|
280
|
+
"provider_retryable_error",
|
|
281
|
+
retry_after_seconds=_retry_after(response.headers.get("retry-after")),
|
|
282
|
+
failure_kind=(
|
|
283
|
+
"request_timeout"
|
|
284
|
+
if status == 408
|
|
285
|
+
else "rate_limit"
|
|
286
|
+
if status == 429
|
|
287
|
+
else "server_error"
|
|
288
|
+
),
|
|
289
|
+
)
|
|
290
|
+
if status == 403:
|
|
291
|
+
return _result(request, "policy_abort")
|
|
292
|
+
if status == 400:
|
|
293
|
+
try:
|
|
294
|
+
body = _load_json(response.content)
|
|
295
|
+
error = body.get("error") if isinstance(body, dict) else None
|
|
296
|
+
if isinstance(error, dict) and error.get("code") == "context_length_exceeded":
|
|
297
|
+
return _result(request, "context_overflow")
|
|
298
|
+
except (ValueError, TypeError, UnicodeError):
|
|
299
|
+
pass
|
|
300
|
+
if not 200 <= status <= 299:
|
|
301
|
+
return _result(request, "provider_terminal_error", failure_kind="client_error")
|
|
302
|
+
return None
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
class _StreamTurn:
|
|
306
|
+
def __init__(self, *, capture_replay: bool = False) -> None:
|
|
307
|
+
self.text = ""
|
|
308
|
+
self.capture_replay = capture_replay
|
|
309
|
+
self.reasoning = ""
|
|
310
|
+
self.finish: str | None = None
|
|
311
|
+
self.usage: ModelUsage | None = None
|
|
312
|
+
self.completion_id: str | None = None
|
|
313
|
+
self.tools: dict[int, dict] = {}
|
|
314
|
+
self.malformed_tools = False
|
|
315
|
+
self.refused = False
|
|
316
|
+
self.done = False
|
|
317
|
+
|
|
318
|
+
def consume(self, data: str) -> str:
|
|
319
|
+
if data.strip() == "[DONE]":
|
|
320
|
+
self.done = True
|
|
321
|
+
return ""
|
|
322
|
+
payload = _load_json(data)
|
|
323
|
+
if not isinstance(payload, dict) or "error" in payload:
|
|
324
|
+
raise ValueError("invalid stream envelope")
|
|
325
|
+
identity = payload.get("id")
|
|
326
|
+
if identity is not None:
|
|
327
|
+
if not isinstance(identity, str) or not identity:
|
|
328
|
+
raise ValueError("invalid completion ID")
|
|
329
|
+
if self.completion_id is not None and identity != self.completion_id:
|
|
330
|
+
raise ValueError("stream mixed completion identities")
|
|
331
|
+
self.completion_id = identity
|
|
332
|
+
usage = _usage(payload.get("usage"))
|
|
333
|
+
if usage is not None:
|
|
334
|
+
if self.usage is not None and self.usage != usage:
|
|
335
|
+
raise ValueError("conflicting usage reports in one attempt")
|
|
336
|
+
self.usage = usage
|
|
337
|
+
choices = payload.get("choices")
|
|
338
|
+
if not isinstance(choices, list) or len(choices) > 1:
|
|
339
|
+
raise ValueError("stream requires one choice")
|
|
340
|
+
if not choices:
|
|
341
|
+
return ""
|
|
342
|
+
choice = choices[0]
|
|
343
|
+
if (
|
|
344
|
+
not isinstance(choice, dict)
|
|
345
|
+
or type(choice.get("index")) is not int
|
|
346
|
+
or choice["index"] != 0
|
|
347
|
+
or "message" in choice
|
|
348
|
+
):
|
|
349
|
+
raise ValueError("snapshot or alternate choice cannot be merged into a delta stream")
|
|
350
|
+
delta = choice.get("delta")
|
|
351
|
+
if delta is None:
|
|
352
|
+
delta = {}
|
|
353
|
+
# Some OpenAI-compatible providers emit role:null on continuation
|
|
354
|
+
# chunks, including tool-call deltas. It means no new role declaration;
|
|
355
|
+
# an actual alternate role must still fail closed.
|
|
356
|
+
if not isinstance(delta, dict) or delta.get("role") not in {None, "assistant"}:
|
|
357
|
+
raise ValueError("invalid stream delta")
|
|
358
|
+
refusal = chat_refusal(delta.get("refusal"))
|
|
359
|
+
if self.finish is not None and refusal:
|
|
360
|
+
raise ValueError("refusal continued after finish")
|
|
361
|
+
self.refused = refusal or self.refused
|
|
362
|
+
content = delta.get("content")
|
|
363
|
+
if content is None:
|
|
364
|
+
content = ""
|
|
365
|
+
if not isinstance(content, str):
|
|
366
|
+
raise ValueError("invalid visible content delta")
|
|
367
|
+
reasoning = chat_reasoning(delta)
|
|
368
|
+
if self.finish is not None and reasoning:
|
|
369
|
+
raise ValueError("private reasoning continued after finish")
|
|
370
|
+
if self.capture_replay:
|
|
371
|
+
self.reasoning += reasoning
|
|
372
|
+
if self.finish is not None and (content or delta.get("tool_calls")):
|
|
373
|
+
raise ValueError("content continued after finish")
|
|
374
|
+
finish = choice.get("finish_reason")
|
|
375
|
+
if finish is not None:
|
|
376
|
+
if not isinstance(finish, str) or (self.finish is not None and finish != self.finish):
|
|
377
|
+
raise ValueError("conflicting finish reasons")
|
|
378
|
+
self.finish = finish
|
|
379
|
+
self.text += content
|
|
380
|
+
try:
|
|
381
|
+
if "function_call" in delta:
|
|
382
|
+
raise ValueError("legacy function calls are unsupported")
|
|
383
|
+
self._add_tools(delta.get("tool_calls"))
|
|
384
|
+
except (ValueError, TypeError):
|
|
385
|
+
self.malformed_tools = True
|
|
386
|
+
# reasoning_content, reasoning, signatures and provider analysis are
|
|
387
|
+
# private protocol material: never project or concatenate them to text.
|
|
388
|
+
return content
|
|
389
|
+
|
|
390
|
+
def _add_tools(self, fragments: object) -> None:
|
|
391
|
+
if fragments is None:
|
|
392
|
+
return
|
|
393
|
+
if not isinstance(fragments, list):
|
|
394
|
+
raise ValueError("tool deltas require a list")
|
|
395
|
+
for fragment in fragments:
|
|
396
|
+
if (
|
|
397
|
+
not isinstance(fragment, dict)
|
|
398
|
+
or type(fragment.get("index")) is not int
|
|
399
|
+
or fragment["index"] < 0
|
|
400
|
+
):
|
|
401
|
+
raise ValueError("invalid tool fragment index")
|
|
402
|
+
call = self.tools.setdefault(
|
|
403
|
+
fragment["index"],
|
|
404
|
+
{"id": None, "type": None, "function": {"name": "", "arguments": ""}},
|
|
405
|
+
)
|
|
406
|
+
for field in ("id", "type"):
|
|
407
|
+
if field in fragment:
|
|
408
|
+
value = fragment[field]
|
|
409
|
+
if (
|
|
410
|
+
not isinstance(value, str)
|
|
411
|
+
or not value
|
|
412
|
+
or (call[field] is not None and call[field] != value)
|
|
413
|
+
):
|
|
414
|
+
raise ValueError("conflicting tool identity")
|
|
415
|
+
call[field] = value
|
|
416
|
+
function = fragment.get("function", {})
|
|
417
|
+
if not isinstance(function, dict):
|
|
418
|
+
raise ValueError("invalid function delta")
|
|
419
|
+
for field in ("name", "arguments"):
|
|
420
|
+
if field in function:
|
|
421
|
+
if not isinstance(function[field], str):
|
|
422
|
+
raise ValueError("function fragment must be text")
|
|
423
|
+
call["function"][field] += function[field]
|
|
424
|
+
|
|
425
|
+
def result(
|
|
426
|
+
self,
|
|
427
|
+
request: ModelRequest,
|
|
428
|
+
error: ModelResponseKind | None = None,
|
|
429
|
+
failure_kind: ModelFailureKind | None = None,
|
|
430
|
+
) -> ModelTurnResult:
|
|
431
|
+
finish = "content_filter" if self.refused else self.finish
|
|
432
|
+
if error is not None and error != "provider_retryable_error":
|
|
433
|
+
return _result(
|
|
434
|
+
request,
|
|
435
|
+
error,
|
|
436
|
+
finish_reason=finish,
|
|
437
|
+
usage=self.usage,
|
|
438
|
+
text=self.text,
|
|
439
|
+
failure_kind=failure_kind,
|
|
440
|
+
)
|
|
441
|
+
if error == "provider_retryable_error" or not self.done:
|
|
442
|
+
# An observed abort/limit is authoritative even when [DONE] or the
|
|
443
|
+
# usage tail is lost. The shared normalizer preserves those causes
|
|
444
|
+
# before transport incompleteness; successful finishes still become
|
|
445
|
+
# retryable. No unsealed tool fragments cross this boundary.
|
|
446
|
+
result = normalize_response(
|
|
447
|
+
request_id=request.request_id,
|
|
448
|
+
attempt_id=request.attempt_id,
|
|
449
|
+
finish_reason=finish,
|
|
450
|
+
text=self.text,
|
|
451
|
+
stream_complete=False,
|
|
452
|
+
usage=self.usage,
|
|
453
|
+
)
|
|
454
|
+
if result.response_kind == "provider_retryable_error":
|
|
455
|
+
return ModelTurnResult.model_validate(
|
|
456
|
+
{**result.model_dump(), "failure_kind": failure_kind or "incomplete_response"}
|
|
457
|
+
)
|
|
458
|
+
return result
|
|
459
|
+
if not self.refused and self.finish is None and (
|
|
460
|
+
self.text.strip() or self.tools or self.malformed_tools
|
|
461
|
+
):
|
|
462
|
+
return _result(
|
|
463
|
+
request,
|
|
464
|
+
"provider_retryable_error",
|
|
465
|
+
finish_reason=finish,
|
|
466
|
+
usage=self.usage,
|
|
467
|
+
text=self.text,
|
|
468
|
+
failure_kind="incomplete_response",
|
|
469
|
+
)
|
|
470
|
+
try:
|
|
471
|
+
if self.malformed_tools:
|
|
472
|
+
raise ValueError("malformed tool fragments")
|
|
473
|
+
calls = _tools([self.tools[index] for index in sorted(self.tools)])
|
|
474
|
+
except (ValueError, TypeError):
|
|
475
|
+
calls = ({},)
|
|
476
|
+
return normalize_response(
|
|
477
|
+
request_id=request.request_id,
|
|
478
|
+
attempt_id=request.attempt_id,
|
|
479
|
+
finish_reason=finish,
|
|
480
|
+
text=self.text,
|
|
481
|
+
tool_calls=calls,
|
|
482
|
+
usage=self.usage,
|
|
483
|
+
)
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
class OpenAICompatibleModelPort:
|
|
487
|
+
"""Perform exactly one HTTP request per model attempt, with optional SSE.
|
|
488
|
+
|
|
489
|
+
The host owns authentication, base URL, network policy, TLS, timeout and the
|
|
490
|
+
AsyncClient lifetime. The host must configure transport/auth without hidden
|
|
491
|
+
retries. This adapter creates no client, follows no redirects, and retries
|
|
492
|
+
nothing. Kernel policy owns backoff/budget; Retry-After is bounded there and
|
|
493
|
+
is never disguised as finish_reason. Streaming mode is pinned in the Profile.
|
|
494
|
+
"""
|
|
495
|
+
|
|
496
|
+
def __init__(
|
|
497
|
+
self,
|
|
498
|
+
client: httpx.AsyncClient,
|
|
499
|
+
*,
|
|
500
|
+
scope: RunScope,
|
|
501
|
+
model: str,
|
|
502
|
+
profile_digest: str,
|
|
503
|
+
streaming: bool = False,
|
|
504
|
+
) -> None:
|
|
505
|
+
if not model.strip() or not profile_digest.strip():
|
|
506
|
+
raise ValueError("host model mapping and profile digest are required")
|
|
507
|
+
if not client.base_url.is_absolute_url or client.base_url.scheme not in {"http", "https"}:
|
|
508
|
+
raise ValueError("host client requires an absolute HTTP base URL")
|
|
509
|
+
self._client = client
|
|
510
|
+
self._scope = _snapshot(scope)
|
|
511
|
+
self._model = model
|
|
512
|
+
self._profile_digest = profile_digest
|
|
513
|
+
self._compat_profile = provider_compat.compat_profile(
|
|
514
|
+
base_url=str(client.base_url), model=model
|
|
515
|
+
)
|
|
516
|
+
if type(streaming) is not bool:
|
|
517
|
+
raise ValueError("streaming must be a host-selected boolean")
|
|
518
|
+
self._streaming = streaming
|
|
519
|
+
|
|
520
|
+
def _request(self, request: ModelRequest, *, streaming: bool) -> tuple[ModelRequest, dict]:
|
|
521
|
+
if request.profile.provider_replay_mode == "anthropic_content":
|
|
522
|
+
raise ValueError("Anthropic replay requires its declared wire adapter")
|
|
523
|
+
sealed = _snapshot(request)
|
|
524
|
+
if sealed.scope != self._scope:
|
|
525
|
+
raise ValueError("model request scope mismatch")
|
|
526
|
+
if sealed.profile.digest != self._profile_digest:
|
|
527
|
+
raise ValueError("model request profile mismatch")
|
|
528
|
+
if sealed.profile.compatibility_digest is not None and (
|
|
529
|
+
sealed.profile.compatibility_digest
|
|
530
|
+
!= provider_compat.compat_profile_digest(self._compat_profile)
|
|
531
|
+
):
|
|
532
|
+
raise ValueError("model compatibility policy differs from the pinned profile")
|
|
533
|
+
if sealed.profile.streaming != streaming:
|
|
534
|
+
raise ValueError("streaming mode differs from the pinned profile")
|
|
535
|
+
payload: dict[str, object] = {
|
|
536
|
+
"model": self._model,
|
|
537
|
+
"messages": _native_messages(sealed),
|
|
538
|
+
"stream": streaming,
|
|
539
|
+
"n": 1,
|
|
540
|
+
sealed.profile.output_token_parameter: sealed.effective_max_output_tokens,
|
|
541
|
+
}
|
|
542
|
+
for field in ("reasoning_effort", "temperature", "top_p", "parallel_tool_calls"):
|
|
543
|
+
value = getattr(sealed.profile, field)
|
|
544
|
+
if value is not None:
|
|
545
|
+
payload[field] = value
|
|
546
|
+
effort = provider_compat.request_reasoning_effort(
|
|
547
|
+
self._compat_profile,
|
|
548
|
+
model=self._model,
|
|
549
|
+
purpose=sealed.purpose,
|
|
550
|
+
requested=sealed.profile.reasoning_effort,
|
|
551
|
+
)
|
|
552
|
+
if effort is not None:
|
|
553
|
+
payload["reasoning_effort"] = effort
|
|
554
|
+
if streaming:
|
|
555
|
+
payload["stream_options"] = {"include_usage": True}
|
|
556
|
+
if sealed.tools:
|
|
557
|
+
payload["tools"] = [
|
|
558
|
+
{"type": "function", "function": tool.function_schema()} for tool in sealed.tools
|
|
559
|
+
]
|
|
560
|
+
payload["tool_choice"] = (
|
|
561
|
+
provider_compat.project_tool_choice(
|
|
562
|
+
sealed.effective_tool_choice, self._compat_profile,
|
|
563
|
+
)
|
|
564
|
+
)
|
|
565
|
+
# Keep the direct Port on the same endpoint capability policy as the
|
|
566
|
+
# Studio Gateway. Some profiled reasoning models can spend the whole
|
|
567
|
+
# output budget thinking instead of returning a tool result.
|
|
568
|
+
if provider_compat.request_thinking_disabled(
|
|
569
|
+
self._compat_profile, model=self._model, purpose=sealed.purpose,
|
|
570
|
+
requested=sealed.profile.reasoning_effort,
|
|
571
|
+
) or provider_compat.should_disable_thinking(
|
|
572
|
+
self._compat_profile,
|
|
573
|
+
tools_present=bool(sealed.tools) and sealed.effective_tool_choice != "none",
|
|
574
|
+
max_output_tokens=sealed.effective_max_output_tokens,
|
|
575
|
+
reasoning_effort=effort,
|
|
576
|
+
):
|
|
577
|
+
payload = provider_compat.with_thinking_disabled(
|
|
578
|
+
payload, self._compat_profile, reasoning_effort=effort,
|
|
579
|
+
)
|
|
580
|
+
payload = provider_compat.apply_chat_compat(
|
|
581
|
+
payload, self._compat_profile, model=self._model
|
|
582
|
+
)
|
|
583
|
+
return sealed, payload
|
|
584
|
+
|
|
585
|
+
@staticmethod
|
|
586
|
+
def _options(request: ModelRequest) -> dict:
|
|
587
|
+
value = request.profile.request_timeout_seconds
|
|
588
|
+
return {"timeout": value} if value is not None else {}
|
|
589
|
+
|
|
590
|
+
async def complete(self, request: ModelRequest) -> ModelTurnResult:
|
|
591
|
+
if self._streaming:
|
|
592
|
+
async for event in self.stream(request):
|
|
593
|
+
if event.kind == "final":
|
|
594
|
+
return event.result
|
|
595
|
+
raise RuntimeError("stream ended without a sealed result")
|
|
596
|
+
sealed, payload = self._request(request, streaming=False)
|
|
597
|
+
try:
|
|
598
|
+
response = await self._client.post(
|
|
599
|
+
"chat/completions",
|
|
600
|
+
json=payload,
|
|
601
|
+
follow_redirects=False,
|
|
602
|
+
**self._options(sealed),
|
|
603
|
+
)
|
|
604
|
+
except (httpx.UnsupportedProtocol, httpx.InvalidURL, httpx.TooManyRedirects):
|
|
605
|
+
return _result(sealed, "provider_terminal_error", failure_kind="client_error")
|
|
606
|
+
except httpx.TimeoutException:
|
|
607
|
+
return _result(sealed, "provider_retryable_error", failure_kind="request_timeout")
|
|
608
|
+
except (httpx.NetworkError, httpx.RemoteProtocolError):
|
|
609
|
+
return _result(sealed, "provider_retryable_error", failure_kind="network_error")
|
|
610
|
+
except httpx.RequestError:
|
|
611
|
+
return _result(sealed, "provider_terminal_error", failure_kind="client_error")
|
|
612
|
+
except Exception:
|
|
613
|
+
# Host auth hooks or transport code may include credentials in
|
|
614
|
+
# exception messages. Expose only the safe terminal classification.
|
|
615
|
+
return _result(sealed, "provider_terminal_error", failure_kind="host_error")
|
|
616
|
+
if error := _http_failure(sealed, response):
|
|
617
|
+
return error
|
|
618
|
+
return _parse_response(sealed, response.content, compat_profile=self._compat_profile)
|
|
619
|
+
|
|
620
|
+
async def stream(self, request: ModelRequest) -> AsyncIterator[ModelStreamEvent]:
|
|
621
|
+
sealed, payload = self._request(request, streaming=True)
|
|
622
|
+
turn = _StreamTurn(capture_replay=sealed.profile.provider_replay_mode != "none")
|
|
623
|
+
seq, result = 0, None
|
|
624
|
+
inline_reasoning = provider_compat.InlineReasoningProjector(self._compat_profile)
|
|
625
|
+
try:
|
|
626
|
+
response_context = self._client.stream(
|
|
627
|
+
"POST",
|
|
628
|
+
"chat/completions",
|
|
629
|
+
json=payload,
|
|
630
|
+
follow_redirects=False,
|
|
631
|
+
**self._options(sealed),
|
|
632
|
+
)
|
|
633
|
+
async with owning_async_context(response_context, owner="native_http") as response:
|
|
634
|
+
if not 200 <= response.status_code <= 299:
|
|
635
|
+
await response.aread()
|
|
636
|
+
result = _http_failure(sealed, response)
|
|
637
|
+
else:
|
|
638
|
+
async with model_sse_frames(
|
|
639
|
+
response.aiter_bytes(), max_bytes=8 * 1024 * 1024,
|
|
640
|
+
idle_timeout_seconds=(
|
|
641
|
+
sealed.profile.request_timeout_seconds
|
|
642
|
+
if sealed.profile.request_timeout_seconds is not None
|
|
643
|
+
else self._client.timeout.read
|
|
644
|
+
),
|
|
645
|
+
) as frames:
|
|
646
|
+
async for frame in frames:
|
|
647
|
+
if not frame.data.strip():
|
|
648
|
+
continue
|
|
649
|
+
delta = turn.consume(frame.data)
|
|
650
|
+
if delta:
|
|
651
|
+
public_delta = inline_reasoning.push(delta)
|
|
652
|
+
if public_delta:
|
|
653
|
+
seq += 1
|
|
654
|
+
yield ModelStreamEvent(
|
|
655
|
+
kind="text_delta",
|
|
656
|
+
request_id=sealed.request_id,
|
|
657
|
+
attempt_id=sealed.attempt_id,
|
|
658
|
+
seq=seq,
|
|
659
|
+
text=public_delta,
|
|
660
|
+
)
|
|
661
|
+
if turn.done:
|
|
662
|
+
break
|
|
663
|
+
except (httpx.UnsupportedProtocol, httpx.InvalidURL, httpx.TooManyRedirects):
|
|
664
|
+
result = turn.result(sealed, "provider_terminal_error", "client_error")
|
|
665
|
+
except (httpx.TimeoutException, ModelSSEIdleTimeout):
|
|
666
|
+
result = turn.result(sealed, "provider_retryable_error", "request_timeout")
|
|
667
|
+
except (httpx.NetworkError, httpx.RemoteProtocolError):
|
|
668
|
+
result = turn.result(sealed, "provider_retryable_error", "network_error")
|
|
669
|
+
except (ValueError, TypeError, UnicodeError, ValidationError, RecursionError):
|
|
670
|
+
result = turn.result(sealed, "provider_terminal_error", "invalid_response")
|
|
671
|
+
except Exception:
|
|
672
|
+
result = turn.result(sealed, "provider_terminal_error", "host_error")
|
|
673
|
+
if result is None:
|
|
674
|
+
result = turn.result(sealed)
|
|
675
|
+
if result.response_kind not in {"provider_retryable_error", "provider_terminal_error"}:
|
|
676
|
+
public_tail = inline_reasoning.seal()
|
|
677
|
+
if public_tail:
|
|
678
|
+
seq += 1
|
|
679
|
+
yield ModelStreamEvent(
|
|
680
|
+
kind="text_delta",
|
|
681
|
+
request_id=sealed.request_id,
|
|
682
|
+
attempt_id=sealed.attempt_id,
|
|
683
|
+
seq=seq,
|
|
684
|
+
text=public_tail,
|
|
685
|
+
)
|
|
686
|
+
public_text = provider_compat.project_inline_reasoning(result.text, self._compat_profile)
|
|
687
|
+
if public_text != result.text:
|
|
688
|
+
kind = (
|
|
689
|
+
"empty_response"
|
|
690
|
+
if result.response_kind == "final_candidate" and not public_text.strip()
|
|
691
|
+
else result.response_kind
|
|
692
|
+
)
|
|
693
|
+
result = ModelTurnResult.model_validate(
|
|
694
|
+
{**result.model_dump(), "text": public_text, "response_kind": kind}
|
|
695
|
+
)
|
|
696
|
+
result = seal_model_replay(result, sealed.profile, turn.reasoning)
|
|
697
|
+
yield ModelStreamEvent(
|
|
698
|
+
kind="final",
|
|
699
|
+
request_id=sealed.request_id,
|
|
700
|
+
attempt_id=sealed.attempt_id,
|
|
701
|
+
seq=seq + 1,
|
|
702
|
+
result=result,
|
|
703
|
+
)
|