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,945 @@
|
|
|
1
|
+
"""Opt-in native kernel: schedule pure transitions and atomically commit effects.
|
|
2
|
+
|
|
3
|
+
This is the Phase 2 kernel, not the Studio ExecutionEngine facade. A durable
|
|
4
|
+
Store does not by itself establish recoverable external effects or cloud leases.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import asyncio
|
|
10
|
+
import hashlib
|
|
11
|
+
from collections.abc import Awaitable, Callable
|
|
12
|
+
from contextlib import suppress
|
|
13
|
+
from time import time
|
|
14
|
+
from uuid import uuid4
|
|
15
|
+
|
|
16
|
+
from ksadk.harness.stores.native_contract import (
|
|
17
|
+
ForkingRunStore,
|
|
18
|
+
PendingCommandConflict,
|
|
19
|
+
RunStore,
|
|
20
|
+
StoreConflict,
|
|
21
|
+
check_scope,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
from .activation_contract import ActivationResourceRef
|
|
25
|
+
from .child_interruption import admit_interrupted_child_receipts as admit_interrupted_child_receipts
|
|
26
|
+
from .child_lifecycle import (
|
|
27
|
+
ChildLifecyclePort,
|
|
28
|
+
prepare_child_lifecycle,
|
|
29
|
+
)
|
|
30
|
+
from .child_lifecycle import (
|
|
31
|
+
ChildLifecycleRequest as ChildLifecycleRequest,
|
|
32
|
+
)
|
|
33
|
+
from .child_lifecycle import (
|
|
34
|
+
ChildLifecycleResult as ChildLifecycleResult,
|
|
35
|
+
)
|
|
36
|
+
from .child_lifecycle import (
|
|
37
|
+
recover_paused_child_observation as recover_paused_child_observation,
|
|
38
|
+
)
|
|
39
|
+
from .child_lifecycle import (
|
|
40
|
+
reduce_child_lifecycle as reduce_child_lifecycle,
|
|
41
|
+
)
|
|
42
|
+
from .child_lifecycle_contract import (
|
|
43
|
+
ChildInterruptedReceiptRequest as ChildInterruptedReceiptRequest,
|
|
44
|
+
)
|
|
45
|
+
from .child_notifications import child_ready_probe, stage_child_ready
|
|
46
|
+
from .command_runtime import resolve_command_batch, stage_child_cancellation
|
|
47
|
+
from .completion import TaskContract
|
|
48
|
+
from .context_contributions import ContextPort
|
|
49
|
+
from .context_contributions import reduce_collection as reduce_collection
|
|
50
|
+
from .context_contributor_contract import ContextModelDispatchDenial as ContextModelDispatchDenial
|
|
51
|
+
from .context_driver import ContextDriver
|
|
52
|
+
from .context_reduction import SUMMARY_REDUCTION_POLICY as SUMMARY_REDUCTION_POLICY
|
|
53
|
+
from .context_runtime import ContextPlanner
|
|
54
|
+
from .effect_control import NativeEffectDispatcher
|
|
55
|
+
from .effect_receipts import EffectReceiptCommitter
|
|
56
|
+
from .effective_configuration import effective_run_configuration
|
|
57
|
+
from .finalization_workspace import prepare_finalization_workspace
|
|
58
|
+
from .finalization_workspace import reduce_finalization_workspace as reduce_finalization_workspace
|
|
59
|
+
from .fork import ForkCreation, build_fork_snapshot, command_run_id
|
|
60
|
+
from .history import project_session_history
|
|
61
|
+
from .hook_runtime_contract import HookInvocationResult as HookInvocationResult
|
|
62
|
+
from .hook_runtime_contract import HookPort
|
|
63
|
+
from .lease import RunLeaseController
|
|
64
|
+
from .machine import (
|
|
65
|
+
next_transition,
|
|
66
|
+
)
|
|
67
|
+
from .machine import (
|
|
68
|
+
reduce_model as reduce_model,
|
|
69
|
+
)
|
|
70
|
+
from .machine import (
|
|
71
|
+
reduce_parallel_readonly_tools as reduce_parallel_readonly_tools,
|
|
72
|
+
)
|
|
73
|
+
from .machine import (
|
|
74
|
+
reduce_tool as reduce_tool,
|
|
75
|
+
)
|
|
76
|
+
from .machine import (
|
|
77
|
+
reduce_workspace as reduce_workspace,
|
|
78
|
+
)
|
|
79
|
+
from .model import ModelTurnResult as ModelTurnResult
|
|
80
|
+
from .model_runtime import (
|
|
81
|
+
provisional_delta as provisional_delta,
|
|
82
|
+
)
|
|
83
|
+
from .model_runtime import (
|
|
84
|
+
recover_unsealed_model_receipt as recover_unsealed_model_receipt,
|
|
85
|
+
)
|
|
86
|
+
from .model_runtime import (
|
|
87
|
+
retry_delay as retry_delay,
|
|
88
|
+
)
|
|
89
|
+
from .model_runtime import (
|
|
90
|
+
sealed_model_usage_event as sealed_model_usage_event,
|
|
91
|
+
)
|
|
92
|
+
from .model_runtime import (
|
|
93
|
+
unavailable_uncertain_usage as unavailable_uncertain_usage,
|
|
94
|
+
)
|
|
95
|
+
from .model_takeover import KEY as TAKEOVER_RESERVATION
|
|
96
|
+
from .model_takeover import ModelTakeoverCapability, prepare_reserved_model, settle_lost_model
|
|
97
|
+
from .ports import (
|
|
98
|
+
ArtifactPort,
|
|
99
|
+
BrowserRecoveryPort,
|
|
100
|
+
ModelPort,
|
|
101
|
+
RunConfiguration,
|
|
102
|
+
ToolPort,
|
|
103
|
+
VerificationPort,
|
|
104
|
+
WorkspacePort,
|
|
105
|
+
digest,
|
|
106
|
+
validate_task_tool_scope,
|
|
107
|
+
)
|
|
108
|
+
from .ports import (
|
|
109
|
+
ToolResult as ToolResult,
|
|
110
|
+
)
|
|
111
|
+
from .ports import (
|
|
112
|
+
VerificationBundle as VerificationBundle,
|
|
113
|
+
)
|
|
114
|
+
from .ports import (
|
|
115
|
+
WorkspaceObservation as WorkspaceObservation,
|
|
116
|
+
)
|
|
117
|
+
from .precompact_hook_runtime import prepare_precompact_hook
|
|
118
|
+
from .precompact_hook_runtime import reduce_precompact_hook as reduce_precompact_hook
|
|
119
|
+
from .request_media import ModelRequestDispatchDenial as ModelRequestDispatchDenial
|
|
120
|
+
from .run_clock import ActiveRunClock, wall_budget_stop
|
|
121
|
+
from .state import (
|
|
122
|
+
CommandReceipt,
|
|
123
|
+
CommitBatch,
|
|
124
|
+
EffectReceipt,
|
|
125
|
+
NativeEvent,
|
|
126
|
+
RunCommand,
|
|
127
|
+
RunPhase,
|
|
128
|
+
RunScope,
|
|
129
|
+
RunSnapshot,
|
|
130
|
+
)
|
|
131
|
+
from .state import (
|
|
132
|
+
EffectIntent as EffectIntent,
|
|
133
|
+
)
|
|
134
|
+
from .stop_hook_runtime import prepare_stop_hook
|
|
135
|
+
from .stop_hook_runtime import reduce_stop_hook as reduce_stop_hook
|
|
136
|
+
from .tool_hook_runtime import (
|
|
137
|
+
close_tool_hook_run as close_tool_hook_run,
|
|
138
|
+
)
|
|
139
|
+
from .tool_hook_runtime import (
|
|
140
|
+
consume_hook_feedback as consume_hook_feedback,
|
|
141
|
+
)
|
|
142
|
+
from .tool_hook_runtime import (
|
|
143
|
+
reduce_tool_hook as reduce_tool_hook,
|
|
144
|
+
)
|
|
145
|
+
from .tool_hook_runtime import (
|
|
146
|
+
stage_post_hooks as stage_post_hooks,
|
|
147
|
+
)
|
|
148
|
+
from .transitions import commit_transition as commit_transition
|
|
149
|
+
from .transitions import finish as finish
|
|
150
|
+
from .user_input import NativeUserInput
|
|
151
|
+
from .verification_runtime import reduce_verification as reduce_verification
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class NativeKernel(EffectReceiptCommitter):
|
|
155
|
+
"""One host-authorized scope; start/attach pins the complete configuration.
|
|
156
|
+
|
|
157
|
+
Every side effect has a persisted intent before dispatch and one atomic
|
|
158
|
+
receipt/state/event commit after dispatch. Lost running effects stop with
|
|
159
|
+
``effect_outcome_unknown`` rather than executing again. Host ports must be
|
|
160
|
+
cooperatively cancellable; they retain responsibility for external cleanup.
|
|
161
|
+
"""
|
|
162
|
+
|
|
163
|
+
def __init__(
|
|
164
|
+
self,
|
|
165
|
+
*,
|
|
166
|
+
store: RunStore,
|
|
167
|
+
scope: RunScope,
|
|
168
|
+
configuration: RunConfiguration,
|
|
169
|
+
model: ModelPort,
|
|
170
|
+
tools: ToolPort | None = None,
|
|
171
|
+
verifier: VerificationPort | None = None,
|
|
172
|
+
workspace: WorkspacePort | None = None,
|
|
173
|
+
artifacts: ArtifactPort | None = None,
|
|
174
|
+
context_planner: ContextPlanner | None = None,
|
|
175
|
+
context_port: ContextPort | None = None,
|
|
176
|
+
hook_port: HookPort | None = None,
|
|
177
|
+
child_lifecycle_port: ChildLifecyclePort | None = None,
|
|
178
|
+
workspace_revision: str = "unavailable",
|
|
179
|
+
lease_ttl_seconds: float | None = None,
|
|
180
|
+
activation_resource: ActivationResourceRef | None = None,
|
|
181
|
+
model_recovery_capability: ModelTakeoverCapability | None = None,
|
|
182
|
+
) -> None:
|
|
183
|
+
if configuration.context_sources and (context_port is None or context_planner is None):
|
|
184
|
+
raise ValueError("configured Context sources require a Port and ContextPlanner")
|
|
185
|
+
if any(source.contributor_policy is not None
|
|
186
|
+
and source.contributor_policy.tokenizer_id != context_planner.tokenizer_id
|
|
187
|
+
for source in configuration.context_sources):
|
|
188
|
+
raise ValueError("Contributor tokenizer mismatch")
|
|
189
|
+
if configuration.hooks and not callable(getattr(hook_port, "invoke", None)):
|
|
190
|
+
raise ValueError("configured Hooks require a Hook Port")
|
|
191
|
+
if configuration.child_lifecycle_policy and child_lifecycle_port is None:
|
|
192
|
+
raise ValueError("configured child lifecycle requires a Port")
|
|
193
|
+
if configuration.child_lifecycle_policy == "owned-background/v2" and not callable(
|
|
194
|
+
getattr(child_lifecycle_port, "interrupted_receipts", None)
|
|
195
|
+
):
|
|
196
|
+
raise ValueError("configured child interruption requires its host Port")
|
|
197
|
+
if configuration.child_promotion_policy and not all(
|
|
198
|
+
callable(getattr(child_lifecycle_port, name, None))
|
|
199
|
+
for name in ("child_tasks", "can_promote", "release_foreground")
|
|
200
|
+
):
|
|
201
|
+
raise ValueError("configured child promotion requires its host Port")
|
|
202
|
+
if configuration.child_input_policy:
|
|
203
|
+
from ksadk.harness.stores.native_contract import ChildInputRunStore
|
|
204
|
+
|
|
205
|
+
if not isinstance(store, ChildInputRunStore) or not all(
|
|
206
|
+
callable(getattr(child_lifecycle_port, name, None))
|
|
207
|
+
for name in ("child_input_target", "wake_child_input")
|
|
208
|
+
):
|
|
209
|
+
raise ValueError("configured child input requires its atomic Store and host Port")
|
|
210
|
+
if configuration.child_release_policy and not callable(
|
|
211
|
+
getattr(child_lifecycle_port, "release_run", None)
|
|
212
|
+
):
|
|
213
|
+
raise ValueError("configured child release requires its host Port")
|
|
214
|
+
if configuration.child_notification_policy and not callable(
|
|
215
|
+
getattr(child_lifecycle_port, "ready_children", None)
|
|
216
|
+
):
|
|
217
|
+
raise ValueError("configured child notifications require their host Port")
|
|
218
|
+
if configuration.child_approval_policy and not getattr(
|
|
219
|
+
child_lifecycle_port, "approval_bridge", False
|
|
220
|
+
):
|
|
221
|
+
raise ValueError("configured child approval requires its host Port")
|
|
222
|
+
if (configuration.tools and tools is None
|
|
223
|
+
and any(event != "Stop" for hook in configuration.hooks for event in hook.events)):
|
|
224
|
+
raise ValueError("tool Hooks require a Tool Port")
|
|
225
|
+
self.store = store
|
|
226
|
+
self.scope = scope.model_copy(deep=True)
|
|
227
|
+
if activation_resource is not None and activation_resource.scope != self.scope:
|
|
228
|
+
raise ValueError("activation scope mismatch")
|
|
229
|
+
self._activation_resource = activation_resource
|
|
230
|
+
self.configuration = RunConfiguration.model_validate_json(configuration.model_dump_json())
|
|
231
|
+
if configuration.model_recovery_policy is not None and (
|
|
232
|
+
model_recovery_capability is None
|
|
233
|
+
or model_recovery_capability.host_binding_digest != configuration.host_binding_digest
|
|
234
|
+
):
|
|
235
|
+
raise ValueError("model takeover requires matching host capability")
|
|
236
|
+
self._model_recovery_capability = model_recovery_capability
|
|
237
|
+
self.model, self.tools, self.verifier, self.workspace, self.artifacts = (
|
|
238
|
+
model,
|
|
239
|
+
tools,
|
|
240
|
+
verifier,
|
|
241
|
+
workspace,
|
|
242
|
+
artifacts,
|
|
243
|
+
)
|
|
244
|
+
self.context = ContextDriver(
|
|
245
|
+
context_planner,
|
|
246
|
+
workspace_revision,
|
|
247
|
+
workspace_tracking=workspace is not None,
|
|
248
|
+
replay_context_policy=configuration.profile.provider_replay_projection_policy,
|
|
249
|
+
)
|
|
250
|
+
self._leases = RunLeaseController(store, self.scope, ttl_seconds=lease_ttl_seconds)
|
|
251
|
+
self._effects = NativeEffectDispatcher(
|
|
252
|
+
store, self.scope, self._leases, model, tools, verifier, workspace, artifacts,
|
|
253
|
+
context_port, hook_port,
|
|
254
|
+
child_lifecycle_port,
|
|
255
|
+
)
|
|
256
|
+
self._clock = ActiveRunClock(configuration.limits.max_wall_seconds)
|
|
257
|
+
self._child_promotion = child_lifecycle_port
|
|
258
|
+
self._locks: dict[str, asyncio.Lock] = {}
|
|
259
|
+
self._parallel_progress_locks: dict[str, asyncio.Lock] = {}
|
|
260
|
+
self._wakes: dict[str, asyncio.Event] = {}
|
|
261
|
+
self._finalization_recovery_fences: dict[str, int] = {}
|
|
262
|
+
|
|
263
|
+
def start(
|
|
264
|
+
self,
|
|
265
|
+
*,
|
|
266
|
+
goal: str,
|
|
267
|
+
session_id: str,
|
|
268
|
+
run_id: str | None = None,
|
|
269
|
+
origin: dict | None = None,
|
|
270
|
+
task_contract: TaskContract | None = None,
|
|
271
|
+
expected_parent_run_id: str | None = None,
|
|
272
|
+
pin_parent: bool = False,
|
|
273
|
+
user_input: NativeUserInput | None = None,
|
|
274
|
+
) -> RunSnapshot:
|
|
275
|
+
config = self.configuration
|
|
276
|
+
if user_input is not None:
|
|
277
|
+
user_input = NativeUserInput.model_validate(user_input)
|
|
278
|
+
if user_input.goal != goal:
|
|
279
|
+
raise ValueError("native_user_input_goal_mismatch")
|
|
280
|
+
if any(document.full_text is not None for document in user_input.documents):
|
|
281
|
+
raise ValueError("native_user_document_capture_required")
|
|
282
|
+
user_input.check_profile(config.profile)
|
|
283
|
+
contract = task_contract or config.contract
|
|
284
|
+
validate_task_tool_scope(contract, config.tools)
|
|
285
|
+
parent = self.store.session_head(self.scope, session_id)
|
|
286
|
+
if pin_parent and (parent.run_id if parent else None) != expected_parent_run_id:
|
|
287
|
+
raise StoreConflict("session changed while compiling task contract")
|
|
288
|
+
if parent is not None and not parent.phase.terminal:
|
|
289
|
+
raise StoreConflict("session already has an active turn")
|
|
290
|
+
history = project_session_history(
|
|
291
|
+
parent, profile_digest=config.profile.digest, configuration_digest=config.digest,
|
|
292
|
+
)
|
|
293
|
+
artifact_refs = list(parent.artifact_refs) if parent else []
|
|
294
|
+
available = {ref["uri"]: ref for ref in artifact_refs}
|
|
295
|
+
for document in user_input.documents if user_input is not None else ():
|
|
296
|
+
if document.text_artifact is not None:
|
|
297
|
+
ref = document.text_artifact.model_dump(mode="json")
|
|
298
|
+
if ref["uri"] in available and available[ref["uri"]] != ref:
|
|
299
|
+
raise ValueError("native_user_document_artifact_conflict")
|
|
300
|
+
if ref["uri"] not in available:
|
|
301
|
+
artifact_refs.append(ref)
|
|
302
|
+
available[ref["uri"]] = ref
|
|
303
|
+
snapshot = RunSnapshot(
|
|
304
|
+
scope=self.scope,
|
|
305
|
+
run_id=run_id or str(uuid4()),
|
|
306
|
+
session_id=session_id,
|
|
307
|
+
turn_id=str(uuid4()),
|
|
308
|
+
parent_run_id=parent.run_id if parent else None,
|
|
309
|
+
goal=goal,
|
|
310
|
+
initial_goal_digest=hashlib.sha256(goal.encode("utf-8")).hexdigest(),
|
|
311
|
+
messages=(*history, *(user_input.messages() if user_input is not None
|
|
312
|
+
else ({"role": "user", "content": goal},))),
|
|
313
|
+
task_progress=parent.task_progress if parent else (),
|
|
314
|
+
task_progress_revision=parent.task_progress_revision if parent else 0,
|
|
315
|
+
workspace_revision=(
|
|
316
|
+
parent.workspace_revision
|
|
317
|
+
if parent
|
|
318
|
+
else (
|
|
319
|
+
self.context.workspace_revision
|
|
320
|
+
if self.context.workspace_revision != "unavailable"
|
|
321
|
+
else None
|
|
322
|
+
)
|
|
323
|
+
),
|
|
324
|
+
artifact_refs=tuple(artifact_refs),
|
|
325
|
+
workspace_changed_paths=parent.workspace_changed_paths if parent else (),
|
|
326
|
+
workspace_observation_status=(
|
|
327
|
+
parent.workspace_observation_status
|
|
328
|
+
if parent
|
|
329
|
+
else (
|
|
330
|
+
"initial" if self.context.workspace_revision != "unavailable" else "unavailable"
|
|
331
|
+
)
|
|
332
|
+
),
|
|
333
|
+
workspace_observation_reason=(parent.workspace_observation_reason if parent else None),
|
|
334
|
+
task_contract=contract.model_dump(mode="json"),
|
|
335
|
+
context_binding=self.context.binding,
|
|
336
|
+
profile_digest=config.profile.digest,
|
|
337
|
+
contract_digest=digest(contract),
|
|
338
|
+
configuration_digest=config.digest,
|
|
339
|
+
origin=origin or {},
|
|
340
|
+
activation_resource_ref=(
|
|
341
|
+
self._activation_resource.model_dump(mode="json")
|
|
342
|
+
if self._activation_resource is not None else None
|
|
343
|
+
),
|
|
344
|
+
)
|
|
345
|
+
self.store.create_turn(snapshot, expected_parent_run_id=parent.run_id if parent else None)
|
|
346
|
+
self.attach(snapshot.run_id)
|
|
347
|
+
return self.snapshot(snapshot.run_id)
|
|
348
|
+
|
|
349
|
+
def fork(
|
|
350
|
+
self,
|
|
351
|
+
*,
|
|
352
|
+
source_run_id: str,
|
|
353
|
+
expected_source_revision: int,
|
|
354
|
+
session_id: str,
|
|
355
|
+
goal: str,
|
|
356
|
+
command_id: str | None = None,
|
|
357
|
+
run_id: str | None = None,
|
|
358
|
+
origin: dict | None = None,
|
|
359
|
+
task_contract: TaskContract | None = None,
|
|
360
|
+
) -> ForkCreation:
|
|
361
|
+
"""Start a new branch at an immutable terminal Run, not its latest head.
|
|
362
|
+
|
|
363
|
+
New configuration comes from this destination host. Historical execution
|
|
364
|
+
state and resources remain with the source; this does not rewind files,
|
|
365
|
+
resume an interrupted side effect, or import another runtime's snapshot.
|
|
366
|
+
A stable command_id returns the original branch on retries; only a
|
|
367
|
+
created receipt attaches execution ownership. Without an ID each call
|
|
368
|
+
is a new command, subject to the unique destination Session boundary.
|
|
369
|
+
"""
|
|
370
|
+
if not isinstance(self.store, ForkingRunStore):
|
|
371
|
+
raise StoreConflict("store does not support atomic fork creation")
|
|
372
|
+
if type(expected_source_revision) is not int or expected_source_revision < 0:
|
|
373
|
+
raise StoreConflict("fork source revision must be a nonnegative integer")
|
|
374
|
+
source = self.store.load(self.scope, source_run_id)
|
|
375
|
+
check_scope(self.scope, source)
|
|
376
|
+
if not source.phase.terminal:
|
|
377
|
+
raise StoreConflict("fork requires a terminal source run")
|
|
378
|
+
if source.revision != expected_source_revision:
|
|
379
|
+
raise StoreConflict("fork source revision changed")
|
|
380
|
+
contract = task_contract or self.configuration.contract
|
|
381
|
+
validate_task_tool_scope(contract, self.configuration.tools)
|
|
382
|
+
if command_id is not None:
|
|
383
|
+
if (not isinstance(command_id, str) or not command_id.strip()
|
|
384
|
+
or len(command_id) > 160):
|
|
385
|
+
raise StoreConflict("fork command ID must be nonempty and at most 160 characters")
|
|
386
|
+
addressed_run = command_run_id(self.scope, source_run_id, command_id)
|
|
387
|
+
if run_id is not None and run_id != addressed_run:
|
|
388
|
+
raise StoreConflict("fork command must use its scoped Run identity")
|
|
389
|
+
run_id = addressed_run
|
|
390
|
+
snapshot = build_fork_snapshot(
|
|
391
|
+
source, run_id=run_id or str(uuid4()), turn_id=str(uuid4()), session_id=session_id,
|
|
392
|
+
goal=goal, configuration=self.configuration, contract=contract,
|
|
393
|
+
context_binding=self.context.binding,
|
|
394
|
+
workspace_revision=self.context.workspace_revision,
|
|
395
|
+
activation_resource=self._activation_resource, origin=origin, command_id=command_id,
|
|
396
|
+
)
|
|
397
|
+
result = self.store.create_fork(snapshot)
|
|
398
|
+
if result.created:
|
|
399
|
+
self.attach(result.snapshot.run_id)
|
|
400
|
+
return result
|
|
401
|
+
|
|
402
|
+
def attach(self, run_id: str) -> RunSnapshot:
|
|
403
|
+
snapshot = self.snapshot(run_id)
|
|
404
|
+
if not self._leases.attached(run_id):
|
|
405
|
+
self._leases.acquire(run_id)
|
|
406
|
+
self._locks[run_id] = asyncio.Lock()
|
|
407
|
+
self._wakes[run_id] = asyncio.Event()
|
|
408
|
+
self._clock.attach(snapshot)
|
|
409
|
+
if self.workspace is not None and RunPhase.FINALIZING in {
|
|
410
|
+
snapshot.phase, snapshot.paused_from, snapshot.resume_phase,
|
|
411
|
+
}:
|
|
412
|
+
self._finalization_recovery_fences[run_id] = self.fencing_token(run_id)
|
|
413
|
+
return snapshot
|
|
414
|
+
|
|
415
|
+
def release(self, run_id: str) -> None:
|
|
416
|
+
self._clock.release(run_id)
|
|
417
|
+
self._leases.release(run_id)
|
|
418
|
+
self._locks.pop(run_id, None)
|
|
419
|
+
self._wakes.pop(run_id, None)
|
|
420
|
+
self._finalization_recovery_fences.pop(run_id, None)
|
|
421
|
+
|
|
422
|
+
async def retain_ownership(self, run_id: str, released: asyncio.Event) -> None:
|
|
423
|
+
"""An attached host remains owner during user-controlled suspension.
|
|
424
|
+
|
|
425
|
+
Model/tool effects have their own bounded cancellation scopes. This
|
|
426
|
+
outer scope also covers gaps between effects, approvals and pauses;
|
|
427
|
+
it grants no execution and never reacquires a lost fencing epoch.
|
|
428
|
+
"""
|
|
429
|
+
self.fencing_token(run_id)
|
|
430
|
+
await self._leases.keep_alive(run_id, released.wait())
|
|
431
|
+
|
|
432
|
+
@property
|
|
433
|
+
def leased_ownership(self) -> bool:
|
|
434
|
+
return self._leases.ttl_seconds is not None
|
|
435
|
+
|
|
436
|
+
async def recover_activation_resources(
|
|
437
|
+
self, run_id: str, current: ActivationResourceRef | None,
|
|
438
|
+
available: Callable[[], Awaitable[bool]] | None,
|
|
439
|
+
) -> RunSnapshot:
|
|
440
|
+
from .activation_recovery import recovery_transition
|
|
441
|
+
|
|
442
|
+
self.fencing_token(run_id)
|
|
443
|
+
async with self._locks[run_id]:
|
|
444
|
+
snapshot = self.snapshot(run_id)
|
|
445
|
+
batch = recovery_transition(snapshot, current)
|
|
446
|
+
if current is not None:
|
|
447
|
+
if available is None:
|
|
448
|
+
raise ValueError("activation availability probe required")
|
|
449
|
+
try:
|
|
450
|
+
live = await self._leases.keep_alive(run_id, available())
|
|
451
|
+
except Exception:
|
|
452
|
+
raise ValueError("activation resource unavailable") from None
|
|
453
|
+
if live is not True:
|
|
454
|
+
raise ValueError("activation resource unavailable")
|
|
455
|
+
return snapshot if batch is None else self._commit(snapshot, batch)
|
|
456
|
+
|
|
457
|
+
async def recover_browser_resources(
|
|
458
|
+
self, run_id: str, port: BrowserRecoveryPort | None
|
|
459
|
+
) -> RunSnapshot:
|
|
460
|
+
from .browser_contract import BrowserRecovery, BrowserSessionRef
|
|
461
|
+
from .browser_recovery import recovery_transition
|
|
462
|
+
|
|
463
|
+
self.fencing_token(run_id)
|
|
464
|
+
async with self._locks[run_id]:
|
|
465
|
+
snapshot = self.snapshot(run_id)
|
|
466
|
+
refs = tuple(BrowserSessionRef.model_validate(item)
|
|
467
|
+
for item in snapshot.browser_session_refs)
|
|
468
|
+
if any(ref.scope != snapshot.scope or ref.run_id != run_id for ref in refs):
|
|
469
|
+
raise ValueError("persisted browser scope mismatch")
|
|
470
|
+
reports = (
|
|
471
|
+
await self._leases.keep_alive(run_id, port.recover_sessions(refs))
|
|
472
|
+
if port is not None and refs else tuple(
|
|
473
|
+
BrowserRecovery(status="lost", session_ref=ref, reason="browser_port_unbound")
|
|
474
|
+
for ref in refs
|
|
475
|
+
)
|
|
476
|
+
)
|
|
477
|
+
# Claimed effects must still acquire an unknown-outcome receipt;
|
|
478
|
+
# a resource failure cannot conceal that uncertainty.
|
|
479
|
+
pending = (self.store.get_intent(self.scope, run_id, snapshot.pending_intent)
|
|
480
|
+
if snapshot.pending_intent else None)
|
|
481
|
+
batch = recovery_transition(snapshot, reports)
|
|
482
|
+
if batch is None:
|
|
483
|
+
return snapshot
|
|
484
|
+
if pending is not None and pending.status == "running":
|
|
485
|
+
batch = batch.model_copy(update={"snapshot": snapshot.model_copy(update={
|
|
486
|
+
"revision": batch.snapshot.revision, "event_seq": batch.snapshot.event_seq,
|
|
487
|
+
"last_browser_observation": None,
|
|
488
|
+
})})
|
|
489
|
+
return self._commit(snapshot, batch)
|
|
490
|
+
|
|
491
|
+
def snapshot(self, run_id: str) -> RunSnapshot:
|
|
492
|
+
snapshot = self.store.load(self.scope, run_id)
|
|
493
|
+
if snapshot.configuration_digest != self.configuration.digest:
|
|
494
|
+
raise ValueError(
|
|
495
|
+
"run configuration is immutable; attach requires the original configuration"
|
|
496
|
+
)
|
|
497
|
+
if snapshot.context_binding != self.context.binding:
|
|
498
|
+
raise ValueError("context tokenizer, policy or workspace binding changed")
|
|
499
|
+
return snapshot
|
|
500
|
+
|
|
501
|
+
def effective_configuration(self, snapshot: RunSnapshot) -> RunConfiguration:
|
|
502
|
+
return effective_run_configuration(self.configuration, snapshot)
|
|
503
|
+
|
|
504
|
+
def steer(
|
|
505
|
+
self,
|
|
506
|
+
run_id: str,
|
|
507
|
+
*,
|
|
508
|
+
text: str,
|
|
509
|
+
command_id: str,
|
|
510
|
+
expected_goal_revision: int,
|
|
511
|
+
task_contract: TaskContract | None = None,
|
|
512
|
+
):
|
|
513
|
+
from .steering import SteeringUpdate
|
|
514
|
+
|
|
515
|
+
update = SteeringUpdate(
|
|
516
|
+
text=text, expected_goal_revision=expected_goal_revision, task_contract=task_contract
|
|
517
|
+
)
|
|
518
|
+
return self.submit(
|
|
519
|
+
run_id,
|
|
520
|
+
RunCommand(command_id=command_id, kind="steer", payload=update.model_dump(mode="json")),
|
|
521
|
+
)
|
|
522
|
+
|
|
523
|
+
def reserved_goal_revision(self, run_id: str) -> int:
|
|
524
|
+
"""Project queued user corrections without weakening direct CAS commands."""
|
|
525
|
+
from .steering import reserved_goal_revision
|
|
526
|
+
|
|
527
|
+
return reserved_goal_revision(
|
|
528
|
+
self.snapshot(run_id), self.store.commands(self.scope, run_id)
|
|
529
|
+
)
|
|
530
|
+
|
|
531
|
+
def guide(self, run_id: str, *, text: str, command_id: str, expected_goal_revision: int):
|
|
532
|
+
from .guidance import GuidanceInput
|
|
533
|
+
|
|
534
|
+
payload = GuidanceInput(text=text, expected_goal_revision=expected_goal_revision)
|
|
535
|
+
if self.configuration.guidance_policy is None:
|
|
536
|
+
return CommandReceipt(command_id=command_id, status="rejected",
|
|
537
|
+
reason="guidance_policy_unavailable")
|
|
538
|
+
return self.submit(run_id, RunCommand(command_id=command_id, kind="guide",
|
|
539
|
+
payload=payload.model_dump(mode="json")))
|
|
540
|
+
|
|
541
|
+
def _runnable_commands(self, snapshot: RunSnapshot):
|
|
542
|
+
from .guidance import runnable_commands
|
|
543
|
+
|
|
544
|
+
return runnable_commands(snapshot, self.store.commands(self.scope, snapshot.run_id),
|
|
545
|
+
guidance_enabled=self.configuration.guidance_policy is not None)
|
|
546
|
+
|
|
547
|
+
def child_tasks(self, run_id: str) -> tuple[dict, ...]:
|
|
548
|
+
snapshot = self.snapshot(run_id)
|
|
549
|
+
reader = getattr(self._child_promotion, "child_tasks", None)
|
|
550
|
+
if not callable(reader):
|
|
551
|
+
raise ValueError("child_directory_unavailable")
|
|
552
|
+
rows = reader(snapshot)
|
|
553
|
+
if self.configuration.child_promotion_policy is None:
|
|
554
|
+
rows = tuple({**row, "can_promote": False} for row in rows)
|
|
555
|
+
if self.configuration.child_input_policy is None:
|
|
556
|
+
rows = tuple({**row, "can_send_input": False} for row in rows)
|
|
557
|
+
if not self.supports_child_cancellation():
|
|
558
|
+
rows = tuple({**row, "can_cancel": False} for row in rows)
|
|
559
|
+
return rows
|
|
560
|
+
|
|
561
|
+
def supports_child_cancellation(self) -> bool:
|
|
562
|
+
return self.configuration.child_lifecycle_policy == "owned-background/v2" and all(
|
|
563
|
+
callable(getattr(self._child_promotion, name, None))
|
|
564
|
+
for name in ("can_cancel", "cancel_child")
|
|
565
|
+
)
|
|
566
|
+
|
|
567
|
+
def cancel_child(self, run_id: str, *, child_run_id: str, command_id: str):
|
|
568
|
+
from .child_promotion import ChildPromotionInput
|
|
569
|
+
|
|
570
|
+
payload = ChildPromotionInput(child_run_id=child_run_id)
|
|
571
|
+
snapshot = self.snapshot(run_id)
|
|
572
|
+
if not self.supports_child_cancellation() or not any(
|
|
573
|
+
row["child_run_id"] == child_run_id
|
|
574
|
+
for row in self._child_promotion.child_tasks(snapshot)
|
|
575
|
+
):
|
|
576
|
+
return CommandReceipt(command_id=command_id, status="rejected",
|
|
577
|
+
reason="child_not_owned_or_cancellation_unavailable")
|
|
578
|
+
return self.submit(run_id, RunCommand(command_id=command_id, kind="cancel_child",
|
|
579
|
+
payload=payload.model_dump(mode="json")))
|
|
580
|
+
|
|
581
|
+
async def _consume_child_cancellation(self, run_id: str, command: RunCommand):
|
|
582
|
+
from .child_cancellation import consume_child_cancellation
|
|
583
|
+
|
|
584
|
+
return await consume_child_cancellation(
|
|
585
|
+
self.snapshot(run_id), command, enabled=self.supports_child_cancellation(),
|
|
586
|
+
port=self._child_promotion, commit=self._commit,
|
|
587
|
+
)
|
|
588
|
+
|
|
589
|
+
def child_execution_view(self, run_id: str, child_run_id: str) -> dict:
|
|
590
|
+
reader = getattr(self._child_promotion, "child_execution_view", None)
|
|
591
|
+
if not callable(reader):
|
|
592
|
+
raise ValueError("child_execution_view_unavailable")
|
|
593
|
+
return reader(self.snapshot(run_id), child_run_id)
|
|
594
|
+
|
|
595
|
+
async def release_children(self, run_id: str) -> None:
|
|
596
|
+
from .child_lifecycle_contract import ChildResourceReleaseRequest
|
|
597
|
+
|
|
598
|
+
# Reading the pinned Run does not reacquire a lost parent lease.
|
|
599
|
+
# Cleanup stops locally owned child tasks; it cannot terminalize or
|
|
600
|
+
# reconcile facts under a replacement parent's fence.
|
|
601
|
+
self.snapshot(run_id)
|
|
602
|
+
if self.configuration.child_release_policy is not None:
|
|
603
|
+
await self._child_promotion.release_run(
|
|
604
|
+
ChildResourceReleaseRequest(scope=self.scope, run_id=run_id)
|
|
605
|
+
)
|
|
606
|
+
|
|
607
|
+
def promote_child(self, run_id: str, *, child_run_id: str, command_id: str):
|
|
608
|
+
from .child_promotion import ChildPromotionInput
|
|
609
|
+
|
|
610
|
+
payload = ChildPromotionInput(child_run_id=child_run_id)
|
|
611
|
+
if self.configuration.child_promotion_policy is None:
|
|
612
|
+
return CommandReceipt(command_id=command_id, status="rejected",
|
|
613
|
+
reason="child_promotion_policy_unavailable")
|
|
614
|
+
return self.submit(run_id, RunCommand(command_id=command_id, kind="promote_child",
|
|
615
|
+
payload=payload.model_dump(mode="json")))
|
|
616
|
+
|
|
617
|
+
def _consume_child_promotion(self, run_id: str, command: RunCommand) -> RunSnapshot:
|
|
618
|
+
from .child_promotion import consume_promotion
|
|
619
|
+
|
|
620
|
+
return consume_promotion(
|
|
621
|
+
self.snapshot(run_id), command, port=self._child_promotion,
|
|
622
|
+
enabled=self.configuration.child_promotion_policy is not None, commit=self._commit,
|
|
623
|
+
)
|
|
624
|
+
|
|
625
|
+
def send_child_input(self, run_id, *, child_run_id, text, command_id, expected_goal_revision):
|
|
626
|
+
from .child_input import ChildInput
|
|
627
|
+
|
|
628
|
+
payload = ChildInput(child_run_id=child_run_id, text=text,
|
|
629
|
+
expected_goal_revision=expected_goal_revision)
|
|
630
|
+
if self.configuration.child_input_policy is None:
|
|
631
|
+
return CommandReceipt(command_id=command_id, status="rejected",
|
|
632
|
+
reason="child_input_policy_unavailable")
|
|
633
|
+
return self.submit(run_id, RunCommand(command_id=command_id, kind="message_child",
|
|
634
|
+
payload=payload.model_dump(mode="json")))
|
|
635
|
+
|
|
636
|
+
def _consume_child_input(self, run_id, command):
|
|
637
|
+
from .child_input_runtime import consume_child_input
|
|
638
|
+
|
|
639
|
+
return consume_child_input(self.snapshot(run_id), command, port=self._child_promotion,
|
|
640
|
+
enabled=self.configuration.child_input_policy is not None,
|
|
641
|
+
commit=self._commit)
|
|
642
|
+
|
|
643
|
+
def fencing_token(self, run_id: str) -> int:
|
|
644
|
+
return self._leases.token(run_id)
|
|
645
|
+
|
|
646
|
+
def events(self, run_id: str, after_seq: int = 0) -> tuple[NativeEvent, ...]:
|
|
647
|
+
self.snapshot(run_id)
|
|
648
|
+
return self.store.events(self.scope, run_id, after_seq=after_seq)
|
|
649
|
+
|
|
650
|
+
def submit(self, run_id: str, command: RunCommand) -> CommandReceipt:
|
|
651
|
+
self.snapshot(run_id)
|
|
652
|
+
receipt = self.store.enqueue(self.scope, run_id, command)
|
|
653
|
+
if wake := self._wakes.get(run_id):
|
|
654
|
+
wake.set()
|
|
655
|
+
return receipt
|
|
656
|
+
|
|
657
|
+
def notify_pending_commands(self, run_id: str) -> None:
|
|
658
|
+
"""Wake a locally owned driver after an atomic external inbox commit."""
|
|
659
|
+
self.snapshot(run_id)
|
|
660
|
+
if wake := self._wakes.get(run_id):
|
|
661
|
+
wake.set()
|
|
662
|
+
|
|
663
|
+
async def run_until_idle(self, run_id: str, *, max_steps: int = 1000) -> RunSnapshot:
|
|
664
|
+
if max_steps < 1:
|
|
665
|
+
raise ValueError("max_steps must be positive")
|
|
666
|
+
for _ in range(max_steps):
|
|
667
|
+
before = self.snapshot(run_id)
|
|
668
|
+
after = await self.advance(run_id)
|
|
669
|
+
if after.phase.terminal or after.revision == before.revision:
|
|
670
|
+
return after
|
|
671
|
+
raise RuntimeError("driver step budget reached; run remains resumable")
|
|
672
|
+
|
|
673
|
+
async def _wait_retry(self, snapshot: RunSnapshot) -> RunSnapshot | None:
|
|
674
|
+
"""Wait under the driver's lease, while still admitting control commands."""
|
|
675
|
+
while snapshot.retry_not_before > time():
|
|
676
|
+
remaining = self._clock.remaining(snapshot)
|
|
677
|
+
if remaining is not None and remaining <= 0:
|
|
678
|
+
return self._commit(snapshot, wall_budget_stop(
|
|
679
|
+
snapshot, self.store, self.scope, elapsed=self._clock.elapsed(snapshot)
|
|
680
|
+
))
|
|
681
|
+
wake = self._wakes[snapshot.run_id]
|
|
682
|
+
with suppress(asyncio.TimeoutError):
|
|
683
|
+
await asyncio.wait_for(
|
|
684
|
+
wake.wait(), min(max(0, snapshot.retry_not_before - time()), 0.1)
|
|
685
|
+
)
|
|
686
|
+
wake.clear()
|
|
687
|
+
commands = self._runnable_commands(snapshot)
|
|
688
|
+
if commands:
|
|
689
|
+
return await self._apply_command(snapshot, commands[0])
|
|
690
|
+
return None
|
|
691
|
+
|
|
692
|
+
async def advance(self, run_id: str) -> RunSnapshot:
|
|
693
|
+
self.fencing_token(run_id)
|
|
694
|
+
async with self._locks[run_id]:
|
|
695
|
+
snapshot = self.snapshot(run_id)
|
|
696
|
+
if snapshot.phase.terminal:
|
|
697
|
+
return snapshot
|
|
698
|
+
pending = (self.store.get_intent(self.scope, run_id, snapshot.pending_intent)
|
|
699
|
+
if snapshot.pending_intent else None)
|
|
700
|
+
if (pending is not None and pending.kind == "child"
|
|
701
|
+
and pending.payload["request"]["action"] == "cancel"):
|
|
702
|
+
# Complete the parent-owned child effect before consuming the
|
|
703
|
+
# cancellation it was staged to settle.
|
|
704
|
+
return await self._execute(snapshot)
|
|
705
|
+
commands = self._runnable_commands(snapshot)
|
|
706
|
+
if commands:
|
|
707
|
+
return await self._apply_command(snapshot, commands[0])
|
|
708
|
+
if snapshot.phase in {RunPhase.PAUSED, RunPhase.AWAITING_INTERACTION}:
|
|
709
|
+
return snapshot
|
|
710
|
+
if snapshot.phase != RunPhase.FINALIZING and (
|
|
711
|
+
(remaining := self._clock.remaining(snapshot)) is not None and remaining <= 0
|
|
712
|
+
):
|
|
713
|
+
return self._commit(snapshot, wall_budget_stop(
|
|
714
|
+
snapshot, self.store, self.scope, elapsed=self._clock.elapsed(snapshot)
|
|
715
|
+
))
|
|
716
|
+
if snapshot.pending_intent:
|
|
717
|
+
probe = child_ready_probe(snapshot, self.effective_configuration(snapshot), pending)
|
|
718
|
+
if probe is not None:
|
|
719
|
+
ready = self._child_promotion.ready_children(probe)
|
|
720
|
+
batch = stage_child_ready(snapshot, pending, probe, ready)
|
|
721
|
+
if batch is not None:
|
|
722
|
+
return self._commit(snapshot, batch)
|
|
723
|
+
return await self._execute(snapshot)
|
|
724
|
+
if snapshot.phase != RunPhase.FINALIZING and snapshot.retry_not_before > time():
|
|
725
|
+
stopped = await self._leases.keep_alive(run_id, self._wait_retry(snapshot))
|
|
726
|
+
if stopped is not None:
|
|
727
|
+
return stopped
|
|
728
|
+
config = self.effective_configuration(snapshot)
|
|
729
|
+
child_batch = prepare_child_lifecycle(snapshot, config)
|
|
730
|
+
if child_batch is not None:
|
|
731
|
+
return self._commit(snapshot, child_batch)
|
|
732
|
+
if snapshot.phase != RunPhase.FINALIZING and (
|
|
733
|
+
(remaining := self._clock.remaining(snapshot)) is not None and remaining <= 0
|
|
734
|
+
):
|
|
735
|
+
return self._commit(snapshot, wall_budget_stop(
|
|
736
|
+
snapshot, self.store, self.scope, elapsed=self._clock.elapsed(snapshot)
|
|
737
|
+
))
|
|
738
|
+
if (snapshot.phase == RunPhase.FINALIZING
|
|
739
|
+
and run_id in self._finalization_recovery_fences):
|
|
740
|
+
batch = prepare_finalization_workspace(
|
|
741
|
+
snapshot, self._finalization_recovery_fences[run_id]
|
|
742
|
+
) or next_transition(snapshot, config)
|
|
743
|
+
elif snapshot.phase == RunPhase.PREPARING_CONTEXT:
|
|
744
|
+
batch = self.context.prepare(snapshot, config)
|
|
745
|
+
elif snapshot.phase == RunPhase.COMPACTING:
|
|
746
|
+
batch = (prepare_precompact_hook(snapshot, config)
|
|
747
|
+
or self.context.begin_summary(snapshot, config))
|
|
748
|
+
elif snapshot.phase == RunPhase.VERIFYING and self.verifier is not None:
|
|
749
|
+
batch = (prepare_stop_hook(snapshot, config)
|
|
750
|
+
or self.context.prepare_verification(snapshot)
|
|
751
|
+
or next_transition(snapshot, config))
|
|
752
|
+
else:
|
|
753
|
+
batch = next_transition(snapshot, config)
|
|
754
|
+
if batch is None:
|
|
755
|
+
return snapshot
|
|
756
|
+
if (self._model_recovery_capability is not None and batch.intents
|
|
757
|
+
and batch.intents[0].kind == "model"):
|
|
758
|
+
now = time()
|
|
759
|
+
quote = self._clock.quote(snapshot, wall_time=now, clock_domain_digest=
|
|
760
|
+
self._model_recovery_capability.clock_domain_digest)
|
|
761
|
+
planned = prepare_reserved_model(
|
|
762
|
+
snapshot, self.configuration, self._model_recovery_capability, now=now,
|
|
763
|
+
payload=batch.intents[0].payload, clock_quote=quote,
|
|
764
|
+
commands=self.store.commands(self.scope, run_id),
|
|
765
|
+
)
|
|
766
|
+
# Ineligible requests keep their original behavior and are not
|
|
767
|
+
# retroactively granted takeover on a later process restart.
|
|
768
|
+
if planned.batch is not None:
|
|
769
|
+
batch = planned.batch
|
|
770
|
+
try:
|
|
771
|
+
return self._commit(snapshot, batch)
|
|
772
|
+
except PendingCommandConflict:
|
|
773
|
+
# enqueue() and commit() are serialized by the Store. If a
|
|
774
|
+
# command was accepted after the driver's first poll, consume
|
|
775
|
+
# it before publishing the final answer or terminal event.
|
|
776
|
+
commands = self._runnable_commands(snapshot)
|
|
777
|
+
if not commands:
|
|
778
|
+
raise
|
|
779
|
+
return await self._apply_command(snapshot, commands[0])
|
|
780
|
+
|
|
781
|
+
def _commit(self, previous: RunSnapshot, batch: CommitBatch, *, child_input=None):
|
|
782
|
+
batch, now = self._clock.prepare_commit(previous, batch)
|
|
783
|
+
commit = self.store.commit if child_input is None else self.store.commit_child_input
|
|
784
|
+
committed = commit(
|
|
785
|
+
self.scope,
|
|
786
|
+
batch,
|
|
787
|
+
expected_revision=previous.revision,
|
|
788
|
+
fencing_token=self.fencing_token(previous.run_id),
|
|
789
|
+
**({"delivery": child_input} if child_input is not None else {}),
|
|
790
|
+
)
|
|
791
|
+
self._clock.committed(committed, now)
|
|
792
|
+
return committed
|
|
793
|
+
|
|
794
|
+
async def _apply_command(self, snapshot: RunSnapshot, command: RunCommand) -> RunSnapshot:
|
|
795
|
+
if command.kind == "cancel_child":
|
|
796
|
+
return await self._consume_child_cancellation(snapshot.run_id, command)
|
|
797
|
+
if command.kind == "message_child":
|
|
798
|
+
return self._consume_child_input(snapshot.run_id, command)
|
|
799
|
+
if command.kind == "promote_child":
|
|
800
|
+
return self._consume_child_promotion(snapshot.run_id, command)
|
|
801
|
+
if (self.configuration.child_lifecycle_policy == "owned-background/v2"
|
|
802
|
+
and command.kind in {"cancel", "policy_revoked"} and snapshot.pending_intent):
|
|
803
|
+
intent = self.store.get_intent(self.scope, snapshot.run_id, snapshot.pending_intent)
|
|
804
|
+
if (intent is not None and intent.kind == "tool" and intent.status == "running"
|
|
805
|
+
and self.store.get_receipt(self.scope, snapshot.run_id,
|
|
806
|
+
intent.operation_key) is None):
|
|
807
|
+
interrupted = EffectReceipt(operation_key=intent.operation_key, status="uncertain",
|
|
808
|
+
result={"reason": "control_interrupted_effect"})
|
|
809
|
+
received = self._interrupted_child_receipt(snapshot, intent, interrupted)
|
|
810
|
+
if received is not interrupted or self.snapshot(snapshot.run_id) != snapshot:
|
|
811
|
+
# Keep the original accepted command queued until the
|
|
812
|
+
# known receipts and any owned allocations are settled.
|
|
813
|
+
return self._commit_receipt(
|
|
814
|
+
self.snapshot(snapshot.run_id), intent, received,
|
|
815
|
+
interruption=interrupted if received is not interrupted else None,
|
|
816
|
+
)
|
|
817
|
+
if (self.configuration.child_lifecycle_policy is not None
|
|
818
|
+
and command.kind in {"cancel", "policy_revoked"}
|
|
819
|
+
and snapshot.child_lifecycle_failure != "cancel"
|
|
820
|
+
and any(item.settled_usage_digest is None
|
|
821
|
+
for item in snapshot.child_budget_reservations)):
|
|
822
|
+
if snapshot.pending_intent:
|
|
823
|
+
return self._commit(snapshot, stage_child_cancellation(
|
|
824
|
+
self.store, self.scope, snapshot, command,
|
|
825
|
+
bound_tool_names=frozenset(tool.name for tool in self.configuration.tools),
|
|
826
|
+
))
|
|
827
|
+
batch = prepare_child_lifecycle(snapshot, self.effective_configuration(snapshot),
|
|
828
|
+
cancel=True)
|
|
829
|
+
if batch is not None:
|
|
830
|
+
return self._commit(snapshot, batch)
|
|
831
|
+
committed = self._commit(
|
|
832
|
+
snapshot,
|
|
833
|
+
resolve_command_batch(
|
|
834
|
+
self.store,
|
|
835
|
+
self.scope,
|
|
836
|
+
snapshot,
|
|
837
|
+
command,
|
|
838
|
+
bound_tool_names=frozenset(tool.name for tool in self.configuration.tools),
|
|
839
|
+
guidance_enabled=self.configuration.guidance_policy is not None,
|
|
840
|
+
replay_configuration=self.configuration,
|
|
841
|
+
),
|
|
842
|
+
)
|
|
843
|
+
if (self.workspace is not None and command.kind == "pause"
|
|
844
|
+
and committed.paused_from == RunPhase.FINALIZING):
|
|
845
|
+
self._finalization_recovery_fences[snapshot.run_id] = self.fencing_token(
|
|
846
|
+
snapshot.run_id
|
|
847
|
+
)
|
|
848
|
+
return committed
|
|
849
|
+
|
|
850
|
+
async def _execute(self, snapshot: RunSnapshot) -> RunSnapshot:
|
|
851
|
+
key = snapshot.pending_intent
|
|
852
|
+
intent = self.store.get_intent(self.scope, snapshot.run_id, key)
|
|
853
|
+
if intent is None:
|
|
854
|
+
raise RuntimeError("committed snapshot references a missing intent")
|
|
855
|
+
receipt = self.store.get_receipt(self.scope, snapshot.run_id, key)
|
|
856
|
+
reconcile_tool = (
|
|
857
|
+
receipt is None
|
|
858
|
+
and intent.status == "running"
|
|
859
|
+
and intent.kind == "tool"
|
|
860
|
+
and isinstance(intent.payload.get("call"), dict)
|
|
861
|
+
and self.configuration.tool_recovery_policy in {
|
|
862
|
+
"sealed_local_child/v1", "prepared_local_child/v1",
|
|
863
|
+
"resume_prepared_local_child/v1", "resume_local_child_checkpoint/v1",
|
|
864
|
+
}
|
|
865
|
+
)
|
|
866
|
+
if receipt is None and intent.status == "running" and intent.kind != "workspace":
|
|
867
|
+
if intent.kind == "model" and self._model_recovery_capability is not None:
|
|
868
|
+
now = time()
|
|
869
|
+
planned = settle_lost_model(
|
|
870
|
+
snapshot, intent, receipt, self.configuration,
|
|
871
|
+
self._model_recovery_capability, now=now,
|
|
872
|
+
clock_quote=self._clock.quote(snapshot, wall_time=now, clock_domain_digest=
|
|
873
|
+
self._model_recovery_capability.clock_domain_digest),
|
|
874
|
+
commands=self.store.commands(self.scope, snapshot.run_id),
|
|
875
|
+
)
|
|
876
|
+
if planned.batch is not None:
|
|
877
|
+
try:
|
|
878
|
+
return self._commit(snapshot, planned.batch)
|
|
879
|
+
except PendingCommandConflict:
|
|
880
|
+
commands = self.store.commands(self.scope, snapshot.run_id)
|
|
881
|
+
if not commands:
|
|
882
|
+
raise
|
|
883
|
+
return await self._apply_command(snapshot, commands[0])
|
|
884
|
+
if not reconcile_tool:
|
|
885
|
+
receipt = EffectReceipt(
|
|
886
|
+
operation_key=key, status="uncertain",
|
|
887
|
+
result={"reason": "effect_outcome_unknown"},
|
|
888
|
+
)
|
|
889
|
+
if receipt is None:
|
|
890
|
+
if intent.status == "prepared":
|
|
891
|
+
try:
|
|
892
|
+
self.store.claim_intent(
|
|
893
|
+
self.scope, snapshot.run_id, key,
|
|
894
|
+
fencing_token=self.fencing_token(snapshot.run_id),
|
|
895
|
+
**({"require_no_pending_commands": True}
|
|
896
|
+
if (TAKEOVER_RESERVATION in intent.payload
|
|
897
|
+
or (intent.kind == "workspace"
|
|
898
|
+
and intent.payload.get("purpose") == "finalization")) else {}),
|
|
899
|
+
)
|
|
900
|
+
except PendingCommandConflict:
|
|
901
|
+
commands = self.store.commands(self.scope, snapshot.run_id)
|
|
902
|
+
if not commands:
|
|
903
|
+
raise
|
|
904
|
+
return await self._apply_command(snapshot, commands[0])
|
|
905
|
+
if intent.payload.get("parallel_readonly") is True:
|
|
906
|
+
for index, _call in enumerate(intent.payload["calls"], 1):
|
|
907
|
+
member_key = f"{key}:call:{index}"
|
|
908
|
+
# Old prepared read batches have no member intents.
|
|
909
|
+
# Their unknown fallback does not invent new admission.
|
|
910
|
+
if self.store.get_intent(
|
|
911
|
+
self.scope, snapshot.run_id, member_key,
|
|
912
|
+
) is not None:
|
|
913
|
+
self.store.claim_intent(
|
|
914
|
+
self.scope, snapshot.run_id, member_key,
|
|
915
|
+
fencing_token=self.fencing_token(snapshot.run_id),
|
|
916
|
+
)
|
|
917
|
+
receipt = await self._effects.dispatch(
|
|
918
|
+
snapshot,
|
|
919
|
+
intent,
|
|
920
|
+
self.effective_configuration(snapshot),
|
|
921
|
+
wake=self._wakes[snapshot.run_id],
|
|
922
|
+
emit=lambda event: self._stream_delta(snapshot.run_id, event),
|
|
923
|
+
on_child_promotion=lambda command: self._consume_child_promotion(
|
|
924
|
+
snapshot.run_id, command
|
|
925
|
+
),
|
|
926
|
+
on_child_input=lambda command: self._consume_child_input(snapshot.run_id, command),
|
|
927
|
+
on_child_cancellation=lambda command: self._consume_child_cancellation(
|
|
928
|
+
snapshot.run_id, command,
|
|
929
|
+
),
|
|
930
|
+
remaining_wall_seconds=self._clock.remaining(snapshot),
|
|
931
|
+
reconcile_tool=reconcile_tool,
|
|
932
|
+
on_parallel_child=(
|
|
933
|
+
lambda index, raw_call, operation_key, result: self._commit_parallel_child(
|
|
934
|
+
snapshot.run_id, intent, index, raw_call, operation_key, result
|
|
935
|
+
)
|
|
936
|
+
if intent.payload.get("parallel_readonly") is True
|
|
937
|
+
else None
|
|
938
|
+
),
|
|
939
|
+
)
|
|
940
|
+
interrupted = receipt
|
|
941
|
+
receipt = self._interrupted_child_receipt(self.snapshot(snapshot.run_id), intent, receipt)
|
|
942
|
+
return self._commit_receipt(
|
|
943
|
+
self.snapshot(snapshot.run_id), intent, receipt, reconciled=reconcile_tool,
|
|
944
|
+
interruption=interrupted if receipt is not interrupted else None,
|
|
945
|
+
)
|