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,116 @@
|
|
|
1
|
+
"""A2A 1.0 error binding corrections for the pinned a2a-sdk 1.1 handler.
|
|
2
|
+
|
|
3
|
+
Keep the upstream transport/authentication path, correct terminal-task errors,
|
|
4
|
+
and persist confirmed Kernel cancellation after an upstream queue-close race.
|
|
5
|
+
No global SDK patching.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
from functools import wraps
|
|
10
|
+
|
|
11
|
+
from a2a.server.request_handlers import DefaultRequestHandler
|
|
12
|
+
from a2a.server.request_handlers.request_handler import validate_request_params
|
|
13
|
+
from a2a.types import TaskState
|
|
14
|
+
from a2a.utils.errors import InvalidParamsError, TaskNotFoundError, UnsupportedOperationError
|
|
15
|
+
from starlette.responses import JSONResponse
|
|
16
|
+
from starlette.routing import Route
|
|
17
|
+
|
|
18
|
+
_CONFIRMED_KERNEL_CANCEL = "ksadk.confirmed_kernel_cancel"
|
|
19
|
+
|
|
20
|
+
_TERMINAL = {
|
|
21
|
+
TaskState.TASK_STATE_COMPLETED,
|
|
22
|
+
TaskState.TASK_STATE_FAILED,
|
|
23
|
+
TaskState.TASK_STATE_CANCELED,
|
|
24
|
+
TaskState.TASK_STATE_REJECTED,
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class ProtocolRequestHandler(DefaultRequestHandler):
|
|
29
|
+
async def _reconcile_owned_task(self, task_id, context):
|
|
30
|
+
task = await self.task_store.get(task_id, context)
|
|
31
|
+
if task is None:
|
|
32
|
+
raise TaskNotFoundError()
|
|
33
|
+
reconcile = getattr(self, "terminal_task_reconciler", None)
|
|
34
|
+
if task.status.state not in _TERMINAL and reconcile is not None:
|
|
35
|
+
await reconcile(task, context, self.task_store)
|
|
36
|
+
task = await self.task_store.get(task_id, context)
|
|
37
|
+
if task is None:
|
|
38
|
+
raise TaskNotFoundError()
|
|
39
|
+
return task
|
|
40
|
+
|
|
41
|
+
@validate_request_params
|
|
42
|
+
async def on_get_task(self, params, context):
|
|
43
|
+
await self._reconcile_owned_task(params.id, context)
|
|
44
|
+
return await super().on_get_task(params, context)
|
|
45
|
+
|
|
46
|
+
@validate_request_params
|
|
47
|
+
async def on_cancel_task(self, params, context):
|
|
48
|
+
# ActiveTask may cache a Task; authorize this request against durable ownership.
|
|
49
|
+
if await self.task_store.get(params.id, context) is None:
|
|
50
|
+
raise TaskNotFoundError()
|
|
51
|
+
context.state.pop(_CONFIRMED_KERNEL_CANCEL, None)
|
|
52
|
+
try:
|
|
53
|
+
result = await super().on_cancel_task(params, context)
|
|
54
|
+
confirmed = context.state.get(_CONFIRMED_KERNEL_CANCEL)
|
|
55
|
+
if confirmed is not None and confirmed[0] == params.id:
|
|
56
|
+
# Upstream V2 cancels its producer before invoking executor.cancel.
|
|
57
|
+
# That can close the event queue before the Kernel acknowledgement.
|
|
58
|
+
# Wait for upstream cleanup, then persist only this confirmed fact.
|
|
59
|
+
current = await self.task_store.get(params.id, context)
|
|
60
|
+
if current is None:
|
|
61
|
+
raise TaskNotFoundError()
|
|
62
|
+
if current.status.state not in _TERMINAL:
|
|
63
|
+
repair = getattr(self.task_store, "save_confirmed_cancellation", None)
|
|
64
|
+
if repair is not None:
|
|
65
|
+
current = await repair(current, confirmed[1], context)
|
|
66
|
+
if current is None:
|
|
67
|
+
raise TaskNotFoundError()
|
|
68
|
+
else:
|
|
69
|
+
current.status.CopyFrom(confirmed[1])
|
|
70
|
+
await self.task_store.save(current, context)
|
|
71
|
+
return current
|
|
72
|
+
return result
|
|
73
|
+
finally:
|
|
74
|
+
context.state.pop(_CONFIRMED_KERNEL_CANCEL, None)
|
|
75
|
+
|
|
76
|
+
async def on_subscribe_to_task(self, params, context):
|
|
77
|
+
task = await self._reconcile_owned_task(params.id, context)
|
|
78
|
+
if task.status.state in _TERMINAL:
|
|
79
|
+
raise UnsupportedOperationError("Task is already terminal")
|
|
80
|
+
try:
|
|
81
|
+
async for event in super().on_subscribe_to_task(params, context):
|
|
82
|
+
yield event
|
|
83
|
+
except InvalidParamsError:
|
|
84
|
+
# V2 ActiveTask reports a terminal subscription as invalid params.
|
|
85
|
+
# Confirm the same owned task before translating the error.
|
|
86
|
+
task = await self.task_store.get(params.id, context)
|
|
87
|
+
if task is not None and task.status.state in _TERMINAL:
|
|
88
|
+
raise UnsupportedOperationError("Task is already terminal") from None
|
|
89
|
+
raise
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def correct_cancel_rest_route(route):
|
|
93
|
+
if not isinstance(route, Route) or not route.path.endswith("/tasks/{id}:cancel"):
|
|
94
|
+
return route
|
|
95
|
+
original = route.endpoint
|
|
96
|
+
|
|
97
|
+
@wraps(original)
|
|
98
|
+
async def endpoint(request):
|
|
99
|
+
response = await original(request)
|
|
100
|
+
if response.status_code == 400 and isinstance(response, JSONResponse):
|
|
101
|
+
body = json.loads(response.body)
|
|
102
|
+
error = body.get("error", {})
|
|
103
|
+
if any(
|
|
104
|
+
detail.get("reason") == "TASK_NOT_CANCELABLE" for detail in error.get("details", [])
|
|
105
|
+
):
|
|
106
|
+
error["code"] = 409
|
|
107
|
+
return JSONResponse(body, status_code=409)
|
|
108
|
+
return response
|
|
109
|
+
|
|
110
|
+
return Route(
|
|
111
|
+
route.path,
|
|
112
|
+
endpoint,
|
|
113
|
+
methods=route.methods,
|
|
114
|
+
name=route.name,
|
|
115
|
+
include_in_schema=route.include_in_schema,
|
|
116
|
+
)
|
ksadk/a2a/result_text.py
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""Select the legacy single-string reply from canonical A2A outputs."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Mapping, Sequence
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def select_terminal_reply(
|
|
10
|
+
output_refs: Sequence[Any],
|
|
11
|
+
snapshots: Mapping[tuple[str, str], Mapping[str, str]],
|
|
12
|
+
item_kinds: Mapping[tuple[str, str], str],
|
|
13
|
+
) -> str:
|
|
14
|
+
"""Return one authoritative text item without flattening conversation history.
|
|
15
|
+
|
|
16
|
+
Canonical output refs deliberately retain every terminal artifact/message for
|
|
17
|
+
replay and presentation. The legacy tool envelope, however, has only one
|
|
18
|
+
``reply`` string. Prefer the last text artifact (the A2A task result), and
|
|
19
|
+
only fall back to the last agent message for peers that return no artifact.
|
|
20
|
+
Parts within that selected item retain their declared order.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
selected: dict[tuple[str, str], list[str]] = {}
|
|
24
|
+
ordered: dict[str, list[tuple[str, str]]] = {"artifact": [], "message": []}
|
|
25
|
+
for ref in output_refs:
|
|
26
|
+
key = (str(ref.scope_id), str(ref.item_id))
|
|
27
|
+
kind = item_kinds.get(key)
|
|
28
|
+
parts = snapshots.get(key)
|
|
29
|
+
if kind not in ordered or not parts:
|
|
30
|
+
continue
|
|
31
|
+
if key not in selected:
|
|
32
|
+
selected[key] = []
|
|
33
|
+
ordered[kind].append(key)
|
|
34
|
+
if ref.part_id is None:
|
|
35
|
+
values = parts.values()
|
|
36
|
+
else:
|
|
37
|
+
value = parts.get(str(ref.part_id))
|
|
38
|
+
values = () if value is None else (value,)
|
|
39
|
+
for value in values:
|
|
40
|
+
if value:
|
|
41
|
+
selected[key].append(value)
|
|
42
|
+
|
|
43
|
+
candidates = ordered["artifact"] or ordered["message"]
|
|
44
|
+
if not candidates:
|
|
45
|
+
return ""
|
|
46
|
+
return "".join(selected[candidates[-1]])
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
__all__ = ["select_terminal_reply"]
|
ksadk/a2a/resume_store.py
CHANGED
|
@@ -12,6 +12,9 @@ from dataclasses import dataclass
|
|
|
12
12
|
from pathlib import Path
|
|
13
13
|
from typing import Literal, TypeAlias
|
|
14
14
|
|
|
15
|
+
from sqlalchemy import text
|
|
16
|
+
from sqlalchemy.ext.asyncio import AsyncEngine
|
|
17
|
+
|
|
15
18
|
from ksadk.runtime.adapter import ResumePayload, ResumeTarget, RunHandle
|
|
16
19
|
|
|
17
20
|
A2AResumePayloadKind: TypeAlias = Literal[
|
|
@@ -116,9 +119,7 @@ class SQLiteA2AResumeStateStore(A2AResumeStateStore):
|
|
|
116
119
|
return A2AResumeState(
|
|
117
120
|
handle=RunHandle.model_validate(raw["handle"]),
|
|
118
121
|
target=ResumeTarget.model_validate(raw["target"]),
|
|
119
|
-
payload_kind=ResumePayload.model_validate(
|
|
120
|
-
{"kind": raw["payload_kind"]}
|
|
121
|
-
).kind,
|
|
122
|
+
payload_kind=ResumePayload.model_validate({"kind": raw["payload_kind"]}).kind,
|
|
122
123
|
call_id=str(raw["call_id"]) if raw.get("call_id") is not None else None,
|
|
123
124
|
)
|
|
124
125
|
except (KeyError, TypeError, ValueError, json.JSONDecodeError) as exc:
|
|
@@ -192,10 +193,99 @@ class SQLiteA2AResumeStateStore(A2AResumeStateStore):
|
|
|
192
193
|
connection.close()
|
|
193
194
|
|
|
194
195
|
|
|
196
|
+
def _serialize_state(state: A2AResumeState) -> str:
|
|
197
|
+
return json.dumps(
|
|
198
|
+
{
|
|
199
|
+
"handle": state.handle.model_dump(mode="json"),
|
|
200
|
+
"target": state.target.model_dump(mode="json"),
|
|
201
|
+
"payload_kind": state.payload_kind,
|
|
202
|
+
"call_id": state.call_id,
|
|
203
|
+
},
|
|
204
|
+
separators=(",", ":"),
|
|
205
|
+
sort_keys=True,
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def _deserialize_state(payload: str) -> A2AResumeState:
|
|
210
|
+
try:
|
|
211
|
+
raw = json.loads(payload)
|
|
212
|
+
return A2AResumeState(
|
|
213
|
+
handle=RunHandle.model_validate(raw["handle"]),
|
|
214
|
+
target=ResumeTarget.model_validate(raw["target"]),
|
|
215
|
+
payload_kind=ResumePayload.model_validate({"kind": raw["payload_kind"]}).kind,
|
|
216
|
+
call_id=str(raw["call_id"]) if raw.get("call_id") is not None else None,
|
|
217
|
+
)
|
|
218
|
+
except (KeyError, TypeError, ValueError, json.JSONDecodeError) as exc:
|
|
219
|
+
raise RuntimeError("A2A resume state is invalid") from exc
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
class PostgresA2AResumeStateStore(A2AResumeStateStore):
|
|
223
|
+
"""Shared opaque resume state for managed Runtime restart recovery."""
|
|
224
|
+
|
|
225
|
+
def __init__(self, engine: AsyncEngine) -> None:
|
|
226
|
+
self._engine = engine
|
|
227
|
+
|
|
228
|
+
@staticmethod
|
|
229
|
+
def _hash(key: str) -> str:
|
|
230
|
+
return hashlib.sha256(key.encode("utf-8")).hexdigest()
|
|
231
|
+
|
|
232
|
+
async def initialize(self) -> None:
|
|
233
|
+
async with self._engine.begin() as connection:
|
|
234
|
+
await connection.execute(
|
|
235
|
+
text(
|
|
236
|
+
"""
|
|
237
|
+
CREATE TABLE IF NOT EXISTS ksadk_a2a_resume_states (
|
|
238
|
+
resume_key_sha256 TEXT PRIMARY KEY,
|
|
239
|
+
state_json TEXT NOT NULL,
|
|
240
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
241
|
+
)
|
|
242
|
+
"""
|
|
243
|
+
)
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
async def put(self, key: str, state: A2AResumeState) -> None:
|
|
247
|
+
async with self._engine.begin() as connection:
|
|
248
|
+
await connection.execute(
|
|
249
|
+
text(
|
|
250
|
+
"""
|
|
251
|
+
INSERT INTO ksadk_a2a_resume_states(resume_key_sha256, state_json)
|
|
252
|
+
VALUES (:key, :payload)
|
|
253
|
+
ON CONFLICT(resume_key_sha256) DO UPDATE SET
|
|
254
|
+
state_json = EXCLUDED.state_json,
|
|
255
|
+
updated_at = CURRENT_TIMESTAMP
|
|
256
|
+
"""
|
|
257
|
+
),
|
|
258
|
+
{"key": self._hash(key), "payload": _serialize_state(state)},
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
async def get(self, key: str) -> A2AResumeState | None:
|
|
262
|
+
async with self._engine.connect() as connection:
|
|
263
|
+
result = await connection.execute(
|
|
264
|
+
text(
|
|
265
|
+
"SELECT state_json FROM ksadk_a2a_resume_states "
|
|
266
|
+
"WHERE resume_key_sha256 = :key"
|
|
267
|
+
),
|
|
268
|
+
{"key": self._hash(key)},
|
|
269
|
+
)
|
|
270
|
+
payload = result.scalar_one_or_none()
|
|
271
|
+
return _deserialize_state(str(payload)) if payload is not None else None
|
|
272
|
+
|
|
273
|
+
async def delete(self, key: str) -> None:
|
|
274
|
+
async with self._engine.begin() as connection:
|
|
275
|
+
await connection.execute(
|
|
276
|
+
text(
|
|
277
|
+
"DELETE FROM ksadk_a2a_resume_states "
|
|
278
|
+
"WHERE resume_key_sha256 = :key"
|
|
279
|
+
),
|
|
280
|
+
{"key": self._hash(key)},
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
|
|
195
284
|
__all__ = [
|
|
196
285
|
"A2AResumeState",
|
|
197
286
|
"A2AResumePayloadKind",
|
|
198
287
|
"A2AResumeStateStore",
|
|
199
288
|
"InMemoryA2AResumeStateStore",
|
|
289
|
+
"PostgresA2AResumeStateStore",
|
|
200
290
|
"SQLiteA2AResumeStateStore",
|
|
201
291
|
]
|
ksadk/a2a/routes.py
CHANGED
|
@@ -31,6 +31,7 @@ from ksadk.a2a.card import build_agent_card
|
|
|
31
31
|
from ksadk.a2a.server import A2AProtocolServer
|
|
32
32
|
from ksadk.a2a.task_adapter import A2ARuntimeTaskAdapter
|
|
33
33
|
from ksadk.a2a.task_store import A2A_TASK_TABLE, A2AOwnerContextBuilder, build_a2a_task_store
|
|
34
|
+
from ksadk.a2a.tool_activity import PublicToolActivityPolicy
|
|
34
35
|
|
|
35
36
|
|
|
36
37
|
@dataclass
|
|
@@ -48,6 +49,7 @@ class A2AConfig:
|
|
|
48
49
|
# 本地调试可显式开放 reasoning artifact;托管 Runtime 默认关闭,避免把
|
|
49
50
|
# 模型内部推理写入公开 A2A Task。
|
|
50
51
|
include_reasoning: bool = False
|
|
52
|
+
public_tool_policy: PublicToolActivityPolicy = field(default_factory=PublicToolActivityPolicy)
|
|
51
53
|
# durable task store:dsn(如 sqlite+aiosqlite:///.agentengine/a2a_tasks.db 或
|
|
52
54
|
# postgresql+asyncpg://...)或外部传入 engine/task_store。
|
|
53
55
|
task_store_dsn: Optional[str] = None
|
|
@@ -76,6 +78,7 @@ def add_a2a_protocol_routes(
|
|
|
76
78
|
version=config.version,
|
|
77
79
|
skills=config.skills,
|
|
78
80
|
streaming=config.streaming,
|
|
81
|
+
public_tool_policy=config.public_tool_policy,
|
|
79
82
|
)
|
|
80
83
|
store = task_store or build_a2a_task_store(
|
|
81
84
|
dsn=config.task_store_dsn,
|
|
@@ -89,6 +92,7 @@ def add_a2a_protocol_routes(
|
|
|
89
92
|
task_adapter=task_adapter,
|
|
90
93
|
context_builder=context_builder,
|
|
91
94
|
include_reasoning=config.include_reasoning,
|
|
95
|
+
public_tool_policy=config.public_tool_policy,
|
|
92
96
|
)
|
|
93
97
|
rest = server.rest_routes()
|
|
94
98
|
# a2a-sdk REST routes 附带贪婪 Mount('/{tenant}')(多租户 catch-all),
|
|
@@ -97,7 +101,8 @@ def add_a2a_protocol_routes(
|
|
|
97
101
|
from starlette.routing import Mount as _Mount
|
|
98
102
|
|
|
99
103
|
rest = [
|
|
100
|
-
route
|
|
104
|
+
route
|
|
105
|
+
for route in rest
|
|
101
106
|
if not (isinstance(route, _Mount) and getattr(route, "path", "") == "/{tenant}")
|
|
102
107
|
]
|
|
103
108
|
add_a2a_routes_to_fastapi(
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"""Resolve managed invocation approval from the Kernel's single durable log."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import hashlib
|
|
5
|
+
import json
|
|
6
|
+
import time
|
|
7
|
+
from contextlib import aclosing
|
|
8
|
+
|
|
9
|
+
from pydantic import PrivateAttr
|
|
10
|
+
|
|
11
|
+
from ksadk.events.canonical import ApprovalRequest, InteractionRequested, SourceRef
|
|
12
|
+
from ksadk.events.identity import stable_event_id
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
async def invoke_with_approval(service, request, *, trigger_ref):
|
|
16
|
+
"""Pause the original invocation, then recheck durable policy before send."""
|
|
17
|
+
from ksadk.a2a.invocation_policy import A2AApprovalRequired
|
|
18
|
+
from ksadk.a2a.invocation_types import A2AContinuationRequest
|
|
19
|
+
|
|
20
|
+
def operation():
|
|
21
|
+
if isinstance(request, A2AContinuationRequest):
|
|
22
|
+
return service.continue_task(request)
|
|
23
|
+
return service.invoke(request, trigger_ref=trigger_ref)
|
|
24
|
+
|
|
25
|
+
for attempt in range(2):
|
|
26
|
+
try:
|
|
27
|
+
async with aclosing(operation()) as events:
|
|
28
|
+
async for event in events:
|
|
29
|
+
yield event
|
|
30
|
+
return
|
|
31
|
+
except A2AApprovalRequired:
|
|
32
|
+
if attempt:
|
|
33
|
+
raise RuntimeError("A2A_APPROVAL_NOT_COMMITTED") from None
|
|
34
|
+
waiter = ManagedA2AApprovalWaiter(request)
|
|
35
|
+
remaining = request.deadline_unix_seconds - time.time()
|
|
36
|
+
if remaining <= 0:
|
|
37
|
+
raise TimeoutError("A2A_OVERALL_TIMEOUT") from None
|
|
38
|
+
try:
|
|
39
|
+
yield waiter.event(timestamp=time.time())
|
|
40
|
+
outcome = await asyncio.wait_for(
|
|
41
|
+
waiter.wait(), max(0, request.deadline_unix_seconds - time.time())
|
|
42
|
+
)
|
|
43
|
+
except TimeoutError:
|
|
44
|
+
raise TimeoutError("A2A_OVERALL_TIMEOUT") from None
|
|
45
|
+
finally:
|
|
46
|
+
waiter.close()
|
|
47
|
+
if outcome != "approved":
|
|
48
|
+
raise PermissionError("A2A_APPROVAL_DENIED")
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class ManagedA2AApprovalRequested(InteractionRequested):
|
|
52
|
+
"""An in-process binding; wire metadata cannot select a Kernel provider."""
|
|
53
|
+
|
|
54
|
+
_invocation = PrivateAttr(default=None)
|
|
55
|
+
_waiter = PrivateAttr(default=None)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class ManagedA2AApprovalWaiter:
|
|
59
|
+
"""One live call; only a committed Kernel receipt may wake it."""
|
|
60
|
+
|
|
61
|
+
def __init__(self, request):
|
|
62
|
+
self.request = request
|
|
63
|
+
self._future = asyncio.get_running_loop().create_future()
|
|
64
|
+
|
|
65
|
+
def event(self, *, timestamp):
|
|
66
|
+
event = approval_event(self.request, timestamp=timestamp)
|
|
67
|
+
event._waiter = self
|
|
68
|
+
return event
|
|
69
|
+
|
|
70
|
+
def accepts(self, record):
|
|
71
|
+
return (not self._future.done()
|
|
72
|
+
and record.interaction_id == approval_id(self.request)
|
|
73
|
+
and record.native_target == approval_target(self.request)
|
|
74
|
+
and record.run_id == self.request.handle.run_id
|
|
75
|
+
and record.session_id == self.request.handle.session_id)
|
|
76
|
+
|
|
77
|
+
async def wait(self):
|
|
78
|
+
return await self._future
|
|
79
|
+
|
|
80
|
+
def close(self):
|
|
81
|
+
self._future.cancel()
|
|
82
|
+
|
|
83
|
+
def deliver(self, receipt, response=None):
|
|
84
|
+
if (receipt.interaction_id != approval_id(self.request)
|
|
85
|
+
or receipt.status != "resolved"
|
|
86
|
+
or receipt.outcome not in {"approved", "rejected"}):
|
|
87
|
+
raise ValueError("A2A_APPROVAL_RECEIPT_INVALID")
|
|
88
|
+
if not self._future.done():
|
|
89
|
+
self._future.set_result(receipt.outcome)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def approval_event(request, *, timestamp):
|
|
93
|
+
interaction_id = approval_id(request)
|
|
94
|
+
event = ManagedA2AApprovalRequested(
|
|
95
|
+
schema_version=2, seq=0, timestamp=timestamp,
|
|
96
|
+
event_id=stable_event_id(
|
|
97
|
+
"a2a", request.handle.parent_scope_id, interaction_id,
|
|
98
|
+
"interaction.requested", "approval", interaction_id, 0,
|
|
99
|
+
),
|
|
100
|
+
run_id=request.handle.run_id, scope_id=request.handle.parent_scope_id,
|
|
101
|
+
source=SourceRef(framework="a2a"), interaction_id=interaction_id,
|
|
102
|
+
interaction_kind="approval", request=ApprovalRequest(
|
|
103
|
+
kind="tool", call_id=request.handle.call_id,
|
|
104
|
+
detail={"tool_name": request.spec.local_name, "risk_level": "high",
|
|
105
|
+
"name": request.spec.local_name, "risk": "high",
|
|
106
|
+
"args": {
|
|
107
|
+
"target_agent_id": request.spec.target_agent_id,
|
|
108
|
+
"version_id": request.spec.expected_version_id,
|
|
109
|
+
"text_parts": list(request.message.text_parts),
|
|
110
|
+
"data_parts": list(request.message.data_parts),
|
|
111
|
+
},
|
|
112
|
+
"side_effects": ["a2a_remote_call"]},
|
|
113
|
+
),
|
|
114
|
+
)
|
|
115
|
+
event._invocation = request
|
|
116
|
+
return event
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def bound_approval_request(event, *, run_id, session_id):
|
|
120
|
+
if not isinstance(event, ManagedA2AApprovalRequested):
|
|
121
|
+
return None
|
|
122
|
+
request = event._invocation
|
|
123
|
+
if (request is None or request.handle.run_id != run_id
|
|
124
|
+
or request.handle.session_id != session_id
|
|
125
|
+
or event.run_id != run_id
|
|
126
|
+
or event.scope_id != request.handle.parent_scope_id
|
|
127
|
+
or event.interaction_id != approval_id(request)
|
|
128
|
+
or event.request.call_id != request.handle.call_id):
|
|
129
|
+
raise ValueError("A2A_APPROVAL_BINDING_CONFLICT")
|
|
130
|
+
return request
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def approval_target(request):
|
|
134
|
+
"""Bind every immutable invocation field without storing message plaintext."""
|
|
135
|
+
values = request.model_dump(mode="json")
|
|
136
|
+
values["message"] = {"message_id": request.message.message_id,
|
|
137
|
+
"sha256": request.message_sha256}
|
|
138
|
+
# A public correlation hint is not part of the authorization identity.
|
|
139
|
+
values["context"].pop("approval_request_id", None)
|
|
140
|
+
digest = hashlib.sha256(json.dumps(
|
|
141
|
+
values, sort_keys=True, separators=(",", ":"), ensure_ascii=False
|
|
142
|
+
).encode()).hexdigest()
|
|
143
|
+
return {"schema": "a2a.approval/v1", "invocation_sha256": digest}
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def approval_id(request):
|
|
147
|
+
return "a2a-approval-" + approval_target(request)["invocation_sha256"]
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
class KernelA2AApprovalResolver:
|
|
151
|
+
"""Read a fully scoped record and its matching first-wins terminal fact.
|
|
152
|
+
|
|
153
|
+
Tenant and agent-instance scope must come from the runtime composition
|
|
154
|
+
root, never from model arguments. No secondary approval cache is created.
|
|
155
|
+
"""
|
|
156
|
+
|
|
157
|
+
def __init__(self, ledger, event_store, *, tenant_id, agent_instance_id):
|
|
158
|
+
if not tenant_id or not agent_instance_id:
|
|
159
|
+
raise ValueError("A2A_APPROVAL_SCOPE_REQUIRED")
|
|
160
|
+
self._ledger, self._events = ledger, event_store
|
|
161
|
+
self._tenant, self._agent = tenant_id, agent_instance_id
|
|
162
|
+
|
|
163
|
+
async def __call__(self, request):
|
|
164
|
+
record = await self._ledger.get(
|
|
165
|
+
approval_id(request), tenant_id=self._tenant,
|
|
166
|
+
agent_instance_id=self._agent, session_id=request.handle.session_id,
|
|
167
|
+
run_id=request.handle.run_id,
|
|
168
|
+
)
|
|
169
|
+
if record is None:
|
|
170
|
+
return None
|
|
171
|
+
if (record.kind != "approval" or record.provider_id != "managed-a2a"
|
|
172
|
+
or record.native_target != approval_target(request)):
|
|
173
|
+
raise ValueError("A2A_APPROVAL_BINDING_CONFLICT")
|
|
174
|
+
if record.status in {"pending", "resolving"}:
|
|
175
|
+
return None
|
|
176
|
+
if record.status in {"cancelled", "expired"}:
|
|
177
|
+
return "denied"
|
|
178
|
+
cursor = 0
|
|
179
|
+
while True:
|
|
180
|
+
events = await self._events.read(record.session_id, cursor, 256)
|
|
181
|
+
if not events:
|
|
182
|
+
raise RuntimeError("A2A_APPROVAL_TERMINAL_FACT_MISSING")
|
|
183
|
+
for event in events:
|
|
184
|
+
payload = event.payload
|
|
185
|
+
if (event.family == "interaction" and event.family_version == 1
|
|
186
|
+
and event.event_type == "interaction.resolved"
|
|
187
|
+
and event.run_id == record.run_id
|
|
188
|
+
and payload.get("interaction_id") == record.interaction_id
|
|
189
|
+
and payload.get("tenant_id") == self._tenant
|
|
190
|
+
and payload.get("agent_instance_id") == self._agent
|
|
191
|
+
and payload.get("session_id") == record.session_id
|
|
192
|
+
and payload.get("run_id") == record.run_id
|
|
193
|
+
and payload.get("revision") == record.revision):
|
|
194
|
+
return "approved" if payload.get("outcome") == "approved" else "denied"
|
|
195
|
+
next_cursor = max(event.seq for event in events)
|
|
196
|
+
if next_cursor <= cursor:
|
|
197
|
+
raise RuntimeError("A2A_APPROVAL_CURSOR_INVALID")
|
|
198
|
+
cursor = next_cursor
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"""Keep the original remote invocation alive across Kernel-owned input waits."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import time
|
|
5
|
+
from collections.abc import Mapping
|
|
6
|
+
from contextlib import aclosing
|
|
7
|
+
|
|
8
|
+
from pydantic import PrivateAttr
|
|
9
|
+
|
|
10
|
+
from ksadk.a2a.invocation_types import A2AContinuationRequest, A2AInvocationMessage
|
|
11
|
+
from ksadk.a2a.runtime_approval import ManagedA2AApprovalRequested, invoke_with_approval
|
|
12
|
+
from ksadk.events.canonical import InteractionRequested
|
|
13
|
+
from ksadk.events.identity import stable_item_id
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _structured_input_value(event, response):
|
|
17
|
+
"""Remove the UI result envelope only for non-object input schemas."""
|
|
18
|
+
schema = getattr(getattr(event, "request", None), "schema_", None)
|
|
19
|
+
normalized = dict(response) if isinstance(response, Mapping) else response
|
|
20
|
+
if (
|
|
21
|
+
isinstance(normalized, dict)
|
|
22
|
+
and set(normalized) == {"result"}
|
|
23
|
+
and isinstance(schema, dict)
|
|
24
|
+
and schema.get("type") != "object"
|
|
25
|
+
):
|
|
26
|
+
return normalized["result"]
|
|
27
|
+
return normalized
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class ManagedA2AInputRequested(InteractionRequested):
|
|
31
|
+
_managed_input_waiter = PrivateAttr(default=None)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class ManagedA2AInputWaiter:
|
|
35
|
+
def __init__(self, event, snapshot):
|
|
36
|
+
self.handle = snapshot.handle
|
|
37
|
+
self.interaction_id = event.interaction_id
|
|
38
|
+
self.target = {
|
|
39
|
+
"schema": ("a2a.remote-approval/v1" if event.interaction_kind == "approval"
|
|
40
|
+
else "a2a.input/v1"),
|
|
41
|
+
"handle": self.handle.model_dump(mode="json"),
|
|
42
|
+
"continuation_id": snapshot.continuation_id,
|
|
43
|
+
"interaction_id": event.interaction_id,
|
|
44
|
+
}
|
|
45
|
+
self.event = ManagedA2AInputRequested.model_validate(event.model_dump(by_alias=True))
|
|
46
|
+
self.event._managed_input_waiter = self
|
|
47
|
+
self._future = asyncio.get_running_loop().create_future()
|
|
48
|
+
|
|
49
|
+
def accepts(self, record):
|
|
50
|
+
return (
|
|
51
|
+
not self._future.done()
|
|
52
|
+
and record.interaction_id == self.interaction_id
|
|
53
|
+
and record.native_target == self.target
|
|
54
|
+
and record.run_id == self.handle.run_id
|
|
55
|
+
and record.session_id == self.handle.session_id
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
def deliver(self, receipt, response=None):
|
|
59
|
+
outcomes = ({"approved", "rejected"} if self.event.interaction_kind == "approval"
|
|
60
|
+
else {"submitted", "rejected"})
|
|
61
|
+
if (
|
|
62
|
+
receipt.interaction_id != self.interaction_id
|
|
63
|
+
or receipt.status != "resolved"
|
|
64
|
+
or receipt.outcome not in outcomes
|
|
65
|
+
):
|
|
66
|
+
raise ValueError("A2A_INPUT_RECEIPT_INVALID")
|
|
67
|
+
if not self._future.done():
|
|
68
|
+
self._future.set_result((receipt.outcome, response))
|
|
69
|
+
|
|
70
|
+
async def wait(self):
|
|
71
|
+
return await self._future
|
|
72
|
+
|
|
73
|
+
def close(self):
|
|
74
|
+
self._future.cancel()
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def bound_input_waiter(event, *, run_id, session_id):
|
|
78
|
+
if not isinstance(event, ManagedA2AInputRequested):
|
|
79
|
+
return None
|
|
80
|
+
waiter = event._managed_input_waiter
|
|
81
|
+
if (
|
|
82
|
+
waiter is None
|
|
83
|
+
or event is not waiter.event
|
|
84
|
+
or event.run_id != run_id
|
|
85
|
+
or waiter.handle.run_id != run_id
|
|
86
|
+
or waiter.handle.session_id != session_id
|
|
87
|
+
or event.scope_id != waiter.handle.scope_id
|
|
88
|
+
or event.interaction_id != waiter.interaction_id
|
|
89
|
+
):
|
|
90
|
+
raise ValueError("A2A_INPUT_BINDING_CONFLICT")
|
|
91
|
+
return waiter
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
async def invoke_with_input(service, request, *, trigger_ref):
|
|
95
|
+
"""Wait on the same task/scope; supplemental messages get their own approval."""
|
|
96
|
+
frozen = await service.pending_continuation(request.handle)
|
|
97
|
+
if frozen is not None:
|
|
98
|
+
request = frozen
|
|
99
|
+
while True:
|
|
100
|
+
pending = None
|
|
101
|
+
async with aclosing(
|
|
102
|
+
invoke_with_approval(service, request, trigger_ref=trigger_ref)
|
|
103
|
+
) as events:
|
|
104
|
+
async for event in events:
|
|
105
|
+
if (
|
|
106
|
+
isinstance(event, InteractionRequested)
|
|
107
|
+
and event.interaction_kind in {"structured_input", "approval"}
|
|
108
|
+
and not isinstance(event, ManagedA2AApprovalRequested)
|
|
109
|
+
):
|
|
110
|
+
pending = event
|
|
111
|
+
else:
|
|
112
|
+
yield event
|
|
113
|
+
snapshot = service.snapshot(service.handle(request.scope_id))
|
|
114
|
+
if snapshot is None or snapshot.status not in {"input_required", "auth_required"}:
|
|
115
|
+
return
|
|
116
|
+
if pending is None:
|
|
117
|
+
pending = await service.pending_input_request(snapshot.handle)
|
|
118
|
+
if pending is None or snapshot.continuation_id is None:
|
|
119
|
+
raise ValueError("A2A_INPUT_CONTINUATION_REQUIRED")
|
|
120
|
+
waiter = ManagedA2AInputWaiter(pending, snapshot)
|
|
121
|
+
try:
|
|
122
|
+
yield waiter.event
|
|
123
|
+
outcome, response = await asyncio.wait_for(
|
|
124
|
+
waiter.wait(), max(0, request.deadline_unix_seconds - time.time())
|
|
125
|
+
)
|
|
126
|
+
except TimeoutError:
|
|
127
|
+
raise TimeoutError("A2A_OVERALL_TIMEOUT") from None
|
|
128
|
+
finally:
|
|
129
|
+
waiter.close()
|
|
130
|
+
is_approval = pending.interaction_kind == "approval"
|
|
131
|
+
if outcome != ("approved" if is_approval else "submitted"):
|
|
132
|
+
if is_approval:
|
|
133
|
+
# Rejection never sends a supplemental message. Retire the
|
|
134
|
+
# remote wait through the normal authorized cancellation path;
|
|
135
|
+
# that path records unknown outcomes without inventing success.
|
|
136
|
+
await service.cancel(snapshot.handle)
|
|
137
|
+
raise PermissionError("A2A_INPUT_REJECTED")
|
|
138
|
+
response_value = "approve" if is_approval else _structured_input_value(pending, response)
|
|
139
|
+
request = A2AContinuationRequest(
|
|
140
|
+
spec=request.spec,
|
|
141
|
+
handle=snapshot.handle,
|
|
142
|
+
message=A2AInvocationMessage(
|
|
143
|
+
message_id=stable_item_id("a2a", request.scope_id, pending.interaction_id, "input"),
|
|
144
|
+
data_parts=(response_value,),
|
|
145
|
+
),
|
|
146
|
+
context=request.context,
|
|
147
|
+
deadline_unix_seconds=request.deadline_unix_seconds,
|
|
148
|
+
idempotency_token=stable_item_id(
|
|
149
|
+
"a2a", request.scope_id, pending.interaction_id, "continue"
|
|
150
|
+
),
|
|
151
|
+
)
|