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,245 @@
|
|
|
1
|
+
"""Fixed Server-only byte transport for prepared Teams materials/artifacts."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from contextlib import asynccontextmanager
|
|
7
|
+
from dataclasses import dataclass, field
|
|
8
|
+
from typing import Mapping
|
|
9
|
+
from urllib.parse import quote
|
|
10
|
+
|
|
11
|
+
import httpx
|
|
12
|
+
from pydantic import TypeAdapter
|
|
13
|
+
|
|
14
|
+
from ksadk.kernel.teams_materials import CHUNK_BYTES, ReadyMaterial
|
|
15
|
+
from ksadk.plugins.teams.cloud_contracts import MAX_FILE_BYTES, Digest, Identifier
|
|
16
|
+
from ksadk.plugins.teams.errors import TeamsError
|
|
17
|
+
from ksadk.plugins.teams.transport import TeamsHTTPClient
|
|
18
|
+
|
|
19
|
+
MAX_JSON_BYTES = 2 * 1024 * 1024
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dataclass(frozen=True)
|
|
23
|
+
class MaterialHTTPAuthorization:
|
|
24
|
+
headers: Mapping[str, str] = field(repr=False)
|
|
25
|
+
node_command_id: str | None = None
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _segment(value):
|
|
29
|
+
TypeAdapter(Identifier).validate_python(value)
|
|
30
|
+
if value in {".", ".."} or any(c in value for c in "/\\?#%"):
|
|
31
|
+
raise ValueError("material endpoint requires one fixed identifier segment")
|
|
32
|
+
return quote(value, safe="")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _failure(code="material_transport_unavailable", status=503):
|
|
36
|
+
return TeamsError(code, "材料传输未完成,请核对原操作后重试", status=status)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class TeamsHTTPMaterialTransport:
|
|
40
|
+
"""Use configured ``.../teams`` base_url, with fresh authorization per call.
|
|
41
|
+
|
|
42
|
+
``authorization(context, operation)`` is async and returns
|
|
43
|
+
MaterialHTTPAuthorization. Node mode accepts only X-Teams-Node-Token and
|
|
44
|
+
optionally the original prepare nodeCommandId. Runtime mode accepts exactly
|
|
45
|
+
one X-Teams-Execution-Permit (prepare reads) or X-Teams-Callback-Permit. No
|
|
46
|
+
owner credentials, redirects or response-supplied storage URLs are used.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
def __init__(self, base_url, *, authorization, node_id=None, transport=None):
|
|
50
|
+
self.client = TeamsHTTPClient(base_url, transport=transport)
|
|
51
|
+
self.authorization = authorization
|
|
52
|
+
self.node_id = node_id
|
|
53
|
+
self.prefix = "/runtime" if node_id is None else "/nodes/" + _segment(node_id)
|
|
54
|
+
|
|
55
|
+
async def close(self):
|
|
56
|
+
await self.client.close()
|
|
57
|
+
|
|
58
|
+
async def _scope(self, context, operation):
|
|
59
|
+
auth = await self.authorization(context, operation)
|
|
60
|
+
if not isinstance(auth, MaterialHTTPAuthorization):
|
|
61
|
+
raise _failure("material_authorization_invalid", 403)
|
|
62
|
+
headers = {}
|
|
63
|
+
for name, value in auth.headers.items():
|
|
64
|
+
if not isinstance(name, str) or not isinstance(value, str) or name.lower() in headers:
|
|
65
|
+
raise _failure("material_authorization_invalid", 403)
|
|
66
|
+
if (
|
|
67
|
+
not value
|
|
68
|
+
or len(value.encode()) > 16384
|
|
69
|
+
or any(ord(c) < 32 or ord(c) > 126 for c in value)
|
|
70
|
+
):
|
|
71
|
+
raise _failure("material_authorization_invalid", 403)
|
|
72
|
+
headers[name.lower()] = value
|
|
73
|
+
allowed = (
|
|
74
|
+
({"x-teams-node-token"},)
|
|
75
|
+
if self.node_id
|
|
76
|
+
else ({"x-teams-execution-permit"}, {"x-teams-callback-permit"})
|
|
77
|
+
)
|
|
78
|
+
if set(headers) not in allowed or (
|
|
79
|
+
operation != "read_material" and "x-teams-execution-permit" in headers
|
|
80
|
+
):
|
|
81
|
+
raise _failure("material_authorization_invalid", 403)
|
|
82
|
+
params = {"contextRef": context.context_ref}
|
|
83
|
+
if auth.node_command_id is not None:
|
|
84
|
+
if self.node_id is None:
|
|
85
|
+
raise _failure("material_authorization_invalid", 403)
|
|
86
|
+
TypeAdapter(Identifier).validate_python(auth.node_command_id)
|
|
87
|
+
params["nodeCommandId"] = auth.node_command_id
|
|
88
|
+
headers["Accept-Encoding"] = "identity"
|
|
89
|
+
return headers, params
|
|
90
|
+
|
|
91
|
+
@asynccontextmanager
|
|
92
|
+
async def _response(
|
|
93
|
+
self, context, operation, method, path, *, content=None, content_length=None
|
|
94
|
+
):
|
|
95
|
+
headers, params = await self._scope(context, operation)
|
|
96
|
+
if content_length is not None:
|
|
97
|
+
headers.update(
|
|
98
|
+
{"Content-Type": "application/octet-stream", "Content-Length": str(content_length)}
|
|
99
|
+
)
|
|
100
|
+
elif content is not None:
|
|
101
|
+
headers["Content-Type"] = "application/json"
|
|
102
|
+
try:
|
|
103
|
+
async with self.client.http.stream(
|
|
104
|
+
method,
|
|
105
|
+
self.client.base_url + self.prefix + path,
|
|
106
|
+
params=params,
|
|
107
|
+
headers=headers,
|
|
108
|
+
content=content,
|
|
109
|
+
follow_redirects=False,
|
|
110
|
+
) as response:
|
|
111
|
+
if not 200 <= response.status_code < 300:
|
|
112
|
+
# Do not echo remote bodies or Location values: either may
|
|
113
|
+
# contain credentials. A failed mutation is never retried.
|
|
114
|
+
code = "material_request_rejected"
|
|
115
|
+
if (
|
|
116
|
+
response.status_code == 409
|
|
117
|
+
and response.headers.get("Content-Encoding", "identity").lower()
|
|
118
|
+
== "identity"
|
|
119
|
+
):
|
|
120
|
+
data = bytearray()
|
|
121
|
+
async for chunk in response.aiter_bytes(4096):
|
|
122
|
+
if len(data) + len(chunk) > 4096:
|
|
123
|
+
data.clear()
|
|
124
|
+
break
|
|
125
|
+
data.extend(chunk)
|
|
126
|
+
try:
|
|
127
|
+
body = json.loads(data)
|
|
128
|
+
except (ValueError, UnicodeDecodeError):
|
|
129
|
+
body = None
|
|
130
|
+
# This one public constant distinguishes the original
|
|
131
|
+
# submit-report race. Never expose arbitrary server data.
|
|
132
|
+
if isinstance(body, dict) and any(
|
|
133
|
+
isinstance(body.get(key), dict)
|
|
134
|
+
and body[key].get("code") == "original_run_unverified"
|
|
135
|
+
for key in ("error", "detail")
|
|
136
|
+
):
|
|
137
|
+
code = "original_run_unverified"
|
|
138
|
+
raise _failure(
|
|
139
|
+
code,
|
|
140
|
+
response.status_code if response.status_code >= 400 else 502,
|
|
141
|
+
)
|
|
142
|
+
if response.headers.get("Content-Encoding", "identity").lower() != "identity":
|
|
143
|
+
raise _failure("material_response_encoding_invalid", 502)
|
|
144
|
+
yield response
|
|
145
|
+
except httpx.RequestError:
|
|
146
|
+
raise _failure() from None
|
|
147
|
+
|
|
148
|
+
async def _json(self, context, operation, method, path, body=None, *, content=None, size=None):
|
|
149
|
+
if body is not None:
|
|
150
|
+
content = json.dumps(body, ensure_ascii=True, separators=(",", ":")).encode()
|
|
151
|
+
if len(content) > MAX_JSON_BYTES:
|
|
152
|
+
raise _failure("material_request_too_large", 413)
|
|
153
|
+
async with self._response(
|
|
154
|
+
context, operation, method, path, content=content, content_length=size
|
|
155
|
+
) as response:
|
|
156
|
+
data = bytearray()
|
|
157
|
+
async for chunk in response.aiter_bytes(CHUNK_BYTES):
|
|
158
|
+
data.extend(chunk)
|
|
159
|
+
if len(data) > MAX_JSON_BYTES:
|
|
160
|
+
raise _failure("material_response_too_large", 502)
|
|
161
|
+
try:
|
|
162
|
+
value = json.loads(data)
|
|
163
|
+
except (UnicodeDecodeError, ValueError):
|
|
164
|
+
raise _failure("material_response_invalid", 502) from None
|
|
165
|
+
if not isinstance(value, dict):
|
|
166
|
+
raise _failure("material_response_invalid", 502)
|
|
167
|
+
return value
|
|
168
|
+
|
|
169
|
+
async def fetch_manifest(self, context, material_ref):
|
|
170
|
+
if context.material_manifest_ref != material_ref:
|
|
171
|
+
raise _failure("material_scope_mismatch", 403)
|
|
172
|
+
result = await self._json(
|
|
173
|
+
context, "read_material", "GET", "/materials/" + _segment(material_ref)
|
|
174
|
+
)
|
|
175
|
+
return ReadyMaterial.model_validate(result).model_dump(mode="json", exclude_none=True)
|
|
176
|
+
|
|
177
|
+
@asynccontextmanager
|
|
178
|
+
async def open_blob(self, context, material_ref, fingerprint):
|
|
179
|
+
if context.material_manifest_ref != material_ref:
|
|
180
|
+
raise _failure("material_scope_mismatch", 403)
|
|
181
|
+
TypeAdapter(Digest).validate_python(fingerprint)
|
|
182
|
+
path = "/materials/" + _segment(material_ref) + "/blobs/" + _segment(fingerprint)
|
|
183
|
+
async with self._open_bytes(context, path) as chunks:
|
|
184
|
+
yield chunks
|
|
185
|
+
|
|
186
|
+
@asynccontextmanager
|
|
187
|
+
async def open_artifact(self, context, group_id, artifact_id):
|
|
188
|
+
if context.ref.groupId != group_id:
|
|
189
|
+
raise _failure("artifact_scope_mismatch", 403)
|
|
190
|
+
path = "/groups/" + _segment(group_id) + "/artifacts/" + _segment(artifact_id) + "/content"
|
|
191
|
+
async with self._open_bytes(context, path) as chunks:
|
|
192
|
+
yield chunks
|
|
193
|
+
|
|
194
|
+
@asynccontextmanager
|
|
195
|
+
async def _open_bytes(self, context, path):
|
|
196
|
+
async with self._response(context, "read_material", "GET", path) as response:
|
|
197
|
+
|
|
198
|
+
async def chunks():
|
|
199
|
+
size = 0
|
|
200
|
+
async for chunk in response.aiter_bytes(CHUNK_BYTES):
|
|
201
|
+
size += len(chunk)
|
|
202
|
+
if size > MAX_FILE_BYTES:
|
|
203
|
+
raise _failure("material_response_too_large", 413)
|
|
204
|
+
yield chunk
|
|
205
|
+
|
|
206
|
+
yield chunks()
|
|
207
|
+
|
|
208
|
+
async def create_artifact(self, context, body):
|
|
209
|
+
if set(body) != {"name", "mediaType", "sizeBytes", "digest", "idempotencyKey"}:
|
|
210
|
+
raise _failure("artifact_request_invalid", 422)
|
|
211
|
+
return await self._json(context, "create_artifact", "POST", "/artifacts", body)
|
|
212
|
+
|
|
213
|
+
async def upload_artifact(self, context, artifact_id, chunks, *, size_bytes):
|
|
214
|
+
if type(size_bytes) is not int or not 0 <= size_bytes <= MAX_FILE_BYTES:
|
|
215
|
+
raise _failure("artifact_size_invalid", 413)
|
|
216
|
+
|
|
217
|
+
async def bounded():
|
|
218
|
+
total = 0
|
|
219
|
+
async for chunk in chunks:
|
|
220
|
+
if not isinstance(chunk, bytes) or len(chunk) > CHUNK_BYTES:
|
|
221
|
+
raise _failure("artifact_bytes_invalid", 422)
|
|
222
|
+
total += len(chunk)
|
|
223
|
+
if total > size_bytes:
|
|
224
|
+
raise _failure("artifact_size_invalid", 422)
|
|
225
|
+
yield chunk
|
|
226
|
+
if total != size_bytes:
|
|
227
|
+
raise _failure("artifact_size_invalid", 422)
|
|
228
|
+
|
|
229
|
+
return await self._json(
|
|
230
|
+
context,
|
|
231
|
+
"upload_artifact",
|
|
232
|
+
"PUT",
|
|
233
|
+
"/artifacts/" + _segment(artifact_id) + "/content",
|
|
234
|
+
content=bounded(),
|
|
235
|
+
size=size_bytes,
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
async def finalize_artifact(self, context, artifact_id, *, idempotency_key):
|
|
239
|
+
return await self._json(
|
|
240
|
+
context,
|
|
241
|
+
"finalize_artifact",
|
|
242
|
+
"POST",
|
|
243
|
+
"/artifacts/" + _segment(artifact_id) + "/finalize",
|
|
244
|
+
{"idempotencyKey": idempotency_key},
|
|
245
|
+
)
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
"""Verified Teams material downloads into a private, execution-scoped cache.
|
|
2
|
+
|
|
3
|
+
The transport is injected by the trusted Node/runtime assembly. It receives the
|
|
4
|
+
original preparation, never a model-supplied URL, bucket credential or local
|
|
5
|
+
destination. No archive extraction, git command or symlink traversal is used.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import asyncio
|
|
11
|
+
import errno
|
|
12
|
+
import hashlib
|
|
13
|
+
import os
|
|
14
|
+
import shutil
|
|
15
|
+
import stat
|
|
16
|
+
import tempfile
|
|
17
|
+
from dataclasses import dataclass
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
from typing import AsyncContextManager, AsyncIterable, Awaitable, Callable
|
|
20
|
+
|
|
21
|
+
from pydantic import Field
|
|
22
|
+
|
|
23
|
+
from ksadk.kernel.teams_execution_context import ContextConflict, PreparedTeamsContext
|
|
24
|
+
from ksadk.plugins.teams.cloud_contracts import (
|
|
25
|
+
Digest,
|
|
26
|
+
Identifier,
|
|
27
|
+
MaterialManifest,
|
|
28
|
+
MaterialProof,
|
|
29
|
+
WireModel,
|
|
30
|
+
digest,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
CHUNK_BYTES = 64 * 1024
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class ReadyMaterial(WireModel):
|
|
37
|
+
materialId: Identifier
|
|
38
|
+
manifestDigest: Digest
|
|
39
|
+
state: str
|
|
40
|
+
sizeBytes: int = Field(strict=True, ge=0, le=64 * 1024 * 1024)
|
|
41
|
+
manifest: MaterialManifest
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@dataclass(frozen=True)
|
|
45
|
+
class PreparedMaterial:
|
|
46
|
+
proof: MaterialProof
|
|
47
|
+
directory: Path
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _open_directory(path, *, dir_fd=None):
|
|
51
|
+
return os.open(path, os.O_RDONLY | os.O_DIRECTORY | os.O_NOFOLLOW, dir_fd=dir_fd)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _parent(root_fd, path, *, create=False):
|
|
55
|
+
"""Return an owned parent fd; every component is opened without symlinks."""
|
|
56
|
+
parts = path.split("/")
|
|
57
|
+
parent = os.dup(root_fd)
|
|
58
|
+
try:
|
|
59
|
+
for part in parts[:-1]:
|
|
60
|
+
if create:
|
|
61
|
+
try:
|
|
62
|
+
os.mkdir(part, mode=0o700, dir_fd=parent)
|
|
63
|
+
os.fsync(parent)
|
|
64
|
+
except FileExistsError:
|
|
65
|
+
pass
|
|
66
|
+
child = _open_directory(part, dir_fd=parent)
|
|
67
|
+
os.close(parent)
|
|
68
|
+
parent = child
|
|
69
|
+
return parent, parts[-1]
|
|
70
|
+
except BaseException:
|
|
71
|
+
os.close(parent)
|
|
72
|
+
raise
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _verify_file(root_fd, entry):
|
|
76
|
+
parent, name = _parent(root_fd, entry.path)
|
|
77
|
+
try:
|
|
78
|
+
fd = os.open(name, os.O_RDONLY | os.O_NOFOLLOW | os.O_NONBLOCK, dir_fd=parent)
|
|
79
|
+
with os.fdopen(fd, "rb") as source:
|
|
80
|
+
before = os.fstat(source.fileno())
|
|
81
|
+
if (
|
|
82
|
+
not stat.S_ISREG(before.st_mode)
|
|
83
|
+
or before.st_nlink != 1
|
|
84
|
+
or before.st_size != entry.sizeBytes
|
|
85
|
+
):
|
|
86
|
+
raise ContextConflict("material cache entry is not the original regular file")
|
|
87
|
+
fingerprint, size = hashlib.sha256(), 0
|
|
88
|
+
while chunk := source.read(min(CHUNK_BYTES, entry.sizeBytes - size + 1)):
|
|
89
|
+
size += len(chunk)
|
|
90
|
+
if size > entry.sizeBytes:
|
|
91
|
+
raise ContextConflict("material cache file changed while reading")
|
|
92
|
+
fingerprint.update(chunk)
|
|
93
|
+
after = os.fstat(source.fileno())
|
|
94
|
+
if (
|
|
95
|
+
size != entry.sizeBytes
|
|
96
|
+
or "sha256:" + fingerprint.hexdigest() != entry.digest
|
|
97
|
+
or (before.st_ino, before.st_size, before.st_mtime_ns, before.st_ctime_ns)
|
|
98
|
+
!= (after.st_ino, after.st_size, after.st_mtime_ns, after.st_ctime_ns)
|
|
99
|
+
):
|
|
100
|
+
raise ContextConflict("material cache file checksum changed")
|
|
101
|
+
finally:
|
|
102
|
+
os.close(parent)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _verify_tree(root_fd, name, manifest):
|
|
106
|
+
fd = _open_directory(name, dir_fd=root_fd)
|
|
107
|
+
try:
|
|
108
|
+
expected_files = {entry.path for entry in manifest.entries}
|
|
109
|
+
expected_dirs = {
|
|
110
|
+
str(parent)
|
|
111
|
+
for path in expected_files
|
|
112
|
+
for parent in Path(path).parents
|
|
113
|
+
if str(parent) != "."
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
def walk(directory, prefix=""):
|
|
117
|
+
for child in os.listdir(directory):
|
|
118
|
+
path = prefix + child
|
|
119
|
+
info = os.stat(child, dir_fd=directory, follow_symlinks=False)
|
|
120
|
+
if stat.S_ISDIR(info.st_mode) and path in expected_dirs:
|
|
121
|
+
child_fd = _open_directory(child, dir_fd=directory)
|
|
122
|
+
try:
|
|
123
|
+
walk(child_fd, path + "/")
|
|
124
|
+
finally:
|
|
125
|
+
os.close(child_fd)
|
|
126
|
+
elif not stat.S_ISREG(info.st_mode) or path not in expected_files:
|
|
127
|
+
raise ContextConflict("material cache contains an unexpected file or link")
|
|
128
|
+
|
|
129
|
+
walk(fd)
|
|
130
|
+
for entry in manifest.entries:
|
|
131
|
+
_verify_file(fd, entry)
|
|
132
|
+
return os.fstat(fd).st_ino
|
|
133
|
+
finally:
|
|
134
|
+
os.close(fd)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
async def _verify_async(root_fd, name, manifest):
|
|
138
|
+
# A cancelled asyncio.to_thread does not stop its OS thread. Give that
|
|
139
|
+
# thread an independent fd and shield scheduling so cancellation cannot
|
|
140
|
+
# leak it or close/reuse the caller's descriptor while it is being read.
|
|
141
|
+
owned_fd = os.dup(root_fd)
|
|
142
|
+
|
|
143
|
+
def verify():
|
|
144
|
+
try:
|
|
145
|
+
return _verify_tree(owned_fd, name, manifest)
|
|
146
|
+
finally:
|
|
147
|
+
os.close(owned_fd)
|
|
148
|
+
|
|
149
|
+
task = asyncio.create_task(asyncio.to_thread(verify))
|
|
150
|
+
try:
|
|
151
|
+
return await asyncio.shield(task)
|
|
152
|
+
except asyncio.CancelledError:
|
|
153
|
+
task.add_done_callback(lambda result: None if result.cancelled() else result.exception())
|
|
154
|
+
raise
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
class TeamsMaterializer:
|
|
158
|
+
"""Materialize a trusted preparation before native execution admission.
|
|
159
|
+
|
|
160
|
+
``fetch_manifest(context, material_ref)`` returns the Server's ready manifest
|
|
161
|
+
after current command/grant authorization. ``open_blob(context, ref, digest)``
|
|
162
|
+
is an async context manager yielding an async iterator of raw byte chunks.
|
|
163
|
+
Both callbacks must use the configured Server and current short-lived Node
|
|
164
|
+
or runtime authorization; cached files do not skip this manifest check.
|
|
165
|
+
"""
|
|
166
|
+
|
|
167
|
+
def __init__(
|
|
168
|
+
self,
|
|
169
|
+
root: Path | str,
|
|
170
|
+
*,
|
|
171
|
+
fetch_manifest: Callable[[PreparedTeamsContext, str], Awaitable[dict]],
|
|
172
|
+
open_blob: Callable[
|
|
173
|
+
[PreparedTeamsContext, str, str], AsyncContextManager[AsyncIterable[bytes]]
|
|
174
|
+
],
|
|
175
|
+
):
|
|
176
|
+
if not hasattr(os, "O_NOFOLLOW") or not hasattr(os, "O_DIRECTORY"):
|
|
177
|
+
raise RuntimeError("Teams materialization requires no-follow directory operations")
|
|
178
|
+
path = Path(root)
|
|
179
|
+
if not path.is_absolute():
|
|
180
|
+
raise ValueError("material cache root must be an absolute trusted path")
|
|
181
|
+
path.mkdir(mode=0o700, parents=True, exist_ok=True)
|
|
182
|
+
if path.is_symlink():
|
|
183
|
+
raise ValueError("material cache root must not be a symlink")
|
|
184
|
+
self.root = path.resolve(strict=True)
|
|
185
|
+
self.fetch_manifest, self.open_blob = fetch_manifest, open_blob
|
|
186
|
+
|
|
187
|
+
async def prepare(self, context: PreparedTeamsContext) -> MaterialProof:
|
|
188
|
+
return (await self.materialize(context)).proof
|
|
189
|
+
|
|
190
|
+
async def materialize(self, context: PreparedTeamsContext) -> PreparedMaterial:
|
|
191
|
+
# Revalidation prevents model_copy or a caller's mutable dict bypassing
|
|
192
|
+
# the original command/grant/context validator.
|
|
193
|
+
context = PreparedTeamsContext.model_validate_json(context.model_dump_json())
|
|
194
|
+
ref, fingerprint = context.material_manifest_ref, context.material_manifest_digest
|
|
195
|
+
if ref is None or fingerprint is None:
|
|
196
|
+
raise ContextConflict("preparation has no frozen material manifest")
|
|
197
|
+
response = ReadyMaterial.model_validate(await self.fetch_manifest(context, ref))
|
|
198
|
+
manifest = response.manifest
|
|
199
|
+
if (
|
|
200
|
+
response.state != "ready"
|
|
201
|
+
or response.materialId != ref
|
|
202
|
+
or response.manifestDigest != fingerprint
|
|
203
|
+
or manifest.manifest_digest != fingerprint
|
|
204
|
+
or response.sizeBytes != sum(entry.sizeBytes for entry in manifest.entries)
|
|
205
|
+
):
|
|
206
|
+
raise ContextConflict("downloaded manifest differs from trusted preparation")
|
|
207
|
+
name = (
|
|
208
|
+
"material_"
|
|
209
|
+
+ digest(
|
|
210
|
+
{
|
|
211
|
+
"authority": context.ref.authorityId,
|
|
212
|
+
"owner": context.owner_subject,
|
|
213
|
+
"group": context.ref.groupId,
|
|
214
|
+
"teamRun": context.ref.teamRunId,
|
|
215
|
+
"command": context.ref.commandId,
|
|
216
|
+
"contextRef": context.context_ref,
|
|
217
|
+
"manifestRef": ref,
|
|
218
|
+
"manifestDigest": fingerprint,
|
|
219
|
+
}
|
|
220
|
+
)[7:]
|
|
221
|
+
)
|
|
222
|
+
root_fd = _open_directory(self.root)
|
|
223
|
+
stage = None
|
|
224
|
+
try:
|
|
225
|
+
try:
|
|
226
|
+
await _verify_async(root_fd, name, manifest)
|
|
227
|
+
except FileNotFoundError:
|
|
228
|
+
# Only a missing cache *directory* allows download. A damaged
|
|
229
|
+
# existing directory remains evidence, never overwritten.
|
|
230
|
+
try:
|
|
231
|
+
os.stat(name, dir_fd=root_fd, follow_symlinks=False)
|
|
232
|
+
except FileNotFoundError:
|
|
233
|
+
pass
|
|
234
|
+
else:
|
|
235
|
+
raise ContextConflict("existing material cache is incomplete")
|
|
236
|
+
else:
|
|
237
|
+
return PreparedMaterial(
|
|
238
|
+
MaterialProof(manifestRef=ref, digest=fingerprint), self.root / name
|
|
239
|
+
)
|
|
240
|
+
stage = Path(tempfile.mkdtemp(prefix=".teams-material-", dir=self.root))
|
|
241
|
+
stage_fd = _open_directory(stage.name, dir_fd=root_fd)
|
|
242
|
+
try:
|
|
243
|
+
for entry in sorted(manifest.entries, key=lambda item: item.path):
|
|
244
|
+
parent, leaf = _parent(stage_fd, entry.path, create=True)
|
|
245
|
+
try:
|
|
246
|
+
fd = os.open(
|
|
247
|
+
leaf,
|
|
248
|
+
os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW,
|
|
249
|
+
mode=0o600,
|
|
250
|
+
dir_fd=parent,
|
|
251
|
+
)
|
|
252
|
+
with os.fdopen(fd, "wb") as target:
|
|
253
|
+
hasher, size = hashlib.sha256(), 0
|
|
254
|
+
async with self.open_blob(context, ref, entry.digest) as chunks:
|
|
255
|
+
async for chunk in chunks:
|
|
256
|
+
if not isinstance(chunk, bytes) or len(chunk) > CHUNK_BYTES:
|
|
257
|
+
raise ContextConflict(
|
|
258
|
+
"material stream must use bounded byte chunks"
|
|
259
|
+
)
|
|
260
|
+
size += len(chunk)
|
|
261
|
+
if size > entry.sizeBytes:
|
|
262
|
+
raise ContextConflict(
|
|
263
|
+
"material stream exceeded declared size"
|
|
264
|
+
)
|
|
265
|
+
target.write(chunk)
|
|
266
|
+
hasher.update(chunk)
|
|
267
|
+
if (
|
|
268
|
+
size != entry.sizeBytes
|
|
269
|
+
or "sha256:" + hasher.hexdigest() != entry.digest
|
|
270
|
+
):
|
|
271
|
+
raise ContextConflict(
|
|
272
|
+
"downloaded bytes differ from frozen material digest"
|
|
273
|
+
)
|
|
274
|
+
target.flush()
|
|
275
|
+
os.fsync(target.fileno())
|
|
276
|
+
os.fchmod(target.fileno(), 0o400)
|
|
277
|
+
os.fsync(parent)
|
|
278
|
+
finally:
|
|
279
|
+
os.close(parent)
|
|
280
|
+
# Reauthorize after network I/O and before exposing a complete
|
|
281
|
+
# directory. Expired or revoked grants must fail this callback.
|
|
282
|
+
current = ReadyMaterial.model_validate(await self.fetch_manifest(context, ref))
|
|
283
|
+
if current != response:
|
|
284
|
+
raise ContextConflict(
|
|
285
|
+
"material authorization or manifest changed during download"
|
|
286
|
+
)
|
|
287
|
+
os.fsync(stage_fd)
|
|
288
|
+
inode = os.fstat(stage_fd).st_ino
|
|
289
|
+
finally:
|
|
290
|
+
os.close(stage_fd)
|
|
291
|
+
if await _verify_async(root_fd, stage.name, manifest) != inode:
|
|
292
|
+
raise ContextConflict("material staging directory was replaced")
|
|
293
|
+
try:
|
|
294
|
+
os.rename(stage.name, name, src_dir_fd=root_fd, dst_dir_fd=root_fd)
|
|
295
|
+
except OSError as exc:
|
|
296
|
+
if exc.errno not in {errno.EEXIST, errno.ENOTEMPTY}:
|
|
297
|
+
raise
|
|
298
|
+
# An independent preparation may have completed the same
|
|
299
|
+
# immutable target. Verify its actual bytes before using it.
|
|
300
|
+
await _verify_async(root_fd, name, manifest)
|
|
301
|
+
else:
|
|
302
|
+
stage = None
|
|
303
|
+
if await _verify_async(root_fd, name, manifest) != inode:
|
|
304
|
+
raise ContextConflict("material destination changed while committing")
|
|
305
|
+
os.fsync(root_fd)
|
|
306
|
+
return PreparedMaterial(
|
|
307
|
+
MaterialProof(manifestRef=ref, digest=fingerprint), self.root / name
|
|
308
|
+
)
|
|
309
|
+
except OSError as exc:
|
|
310
|
+
raise ContextConflict(
|
|
311
|
+
"material filesystem rejected an unsafe or unavailable path"
|
|
312
|
+
) from exc
|
|
313
|
+
finally:
|
|
314
|
+
os.close(root_fd)
|
|
315
|
+
if stage is not None:
|
|
316
|
+
# Python's fd-based rmtree avoids following malicious links.
|
|
317
|
+
# Only this request's private unfinished staging dir is removed.
|
|
318
|
+
shutil.rmtree(stage, ignore_errors=True)
|