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,852 @@
|
|
|
1
|
+
"""A rejection-only Studio verifier for explicit final-answer shape requests.
|
|
2
|
+
|
|
3
|
+
The host can reject an obvious shape violation and send safe repair feedback.
|
|
4
|
+
Passing this check never proves the user's semantic goal, so the required
|
|
5
|
+
acceptance remains ``not_run`` and the Native outcome remains ``unverified``.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import ast
|
|
11
|
+
import hashlib
|
|
12
|
+
import json
|
|
13
|
+
import re
|
|
14
|
+
from dataclasses import dataclass
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
from typing import Literal
|
|
17
|
+
|
|
18
|
+
from ksadk.harness.native.completion import (
|
|
19
|
+
CompletionCandidate,
|
|
20
|
+
VerificationItemResult,
|
|
21
|
+
VerificationReport,
|
|
22
|
+
)
|
|
23
|
+
from ksadk.harness.native.ports import VerificationBundle, VerificationRequest
|
|
24
|
+
from ksadk.harness.native.state import RunScope
|
|
25
|
+
from ksadk.harness.stores.native_contract import RunStore
|
|
26
|
+
from ksadk.studio.native_browser_port import StudioNativeBrowserPort, browser_environment_warning
|
|
27
|
+
from ksadk.studio.native_output_fields import declared_object_fields
|
|
28
|
+
|
|
29
|
+
VERIFIER_REF = "studio.final-answer-shape-rejection"
|
|
30
|
+
VERIFIER_VERSION = "12"
|
|
31
|
+
BROWSER_VERIFIER_REF = "studio.browser-smoke-rejection"
|
|
32
|
+
BROWSER_VERIFIER_VERSION = "9"
|
|
33
|
+
ARTIFACT_VERIFIER_REF = "studio.exact-workspace-file-observation"
|
|
34
|
+
ARTIFACT_VERIFIER_VERSION = "1"
|
|
35
|
+
# New goals bind rejection-only checks independently of installed capabilities.
|
|
36
|
+
# Legacy shape/browser contracts retain their pinned semantics on restoration.
|
|
37
|
+
EVIDENCE_VERIFIER_REF = "studio.delivery-evidence-rejection"
|
|
38
|
+
EVIDENCE_VERIFIER_VERSION = "1"
|
|
39
|
+
FinalShape = (
|
|
40
|
+
Literal[
|
|
41
|
+
"number", "integer", "digits", "sentence", "json_boolean", "json_object",
|
|
42
|
+
"json_array", "python_list"
|
|
43
|
+
]
|
|
44
|
+
| tuple[str, str]
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def json_object_submission_schema(goal: str | None = None) -> dict:
|
|
49
|
+
"""One host submission protocol for explicit parent and child object goals.
|
|
50
|
+
|
|
51
|
+
Freeze the outer shape and an unambiguous explicit key list, never an
|
|
52
|
+
inferred answer, field value/type or semantic verifier. Every caller
|
|
53
|
+
receives a fresh schema. Unsupported field declarations remain unconstrained.
|
|
54
|
+
"""
|
|
55
|
+
output = {
|
|
56
|
+
"type": "object",
|
|
57
|
+
"description": "The complete JSON object requested by the current user.",
|
|
58
|
+
}
|
|
59
|
+
fields = declared_object_fields(_structured_json_clauses(goal)) if goal else None
|
|
60
|
+
if fields:
|
|
61
|
+
output.update(
|
|
62
|
+
properties={key: {} for key in fields},
|
|
63
|
+
required=list(fields),
|
|
64
|
+
additionalProperties=False,
|
|
65
|
+
)
|
|
66
|
+
return {
|
|
67
|
+
"type": "object",
|
|
68
|
+
"properties": {"output": output},
|
|
69
|
+
"required": ["output"],
|
|
70
|
+
"additionalProperties": False,
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def declared_value_submission_schema(goal: str) -> dict | None:
|
|
75
|
+
"""Compile an explicit delivery form, never its answer or source semantics."""
|
|
76
|
+
shape = requested_final_shape(goal)
|
|
77
|
+
if shape == "json_object":
|
|
78
|
+
return json_object_submission_schema(goal)
|
|
79
|
+
types = {"number": "number", "integer": "integer", "json_boolean": "boolean",
|
|
80
|
+
"json_array": "array", "sentence": "string", "digits": "string"}
|
|
81
|
+
if not isinstance(shape, str) or shape not in types:
|
|
82
|
+
return None
|
|
83
|
+
value = {"type": types[shape]}
|
|
84
|
+
if shape == "sentence":
|
|
85
|
+
value.update(minLength=1, pattern=r"^[^\r\n]+$", description=(
|
|
86
|
+
"Only the complete requested sentence, without an introduction or commentary."
|
|
87
|
+
))
|
|
88
|
+
elif shape == "digits":
|
|
89
|
+
value.update(minLength=1, pattern=r"^[0-9]+$")
|
|
90
|
+
return {"type": "object", "properties": {"output": value},
|
|
91
|
+
"required": ["output"], "additionalProperties": False}
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
@dataclass(frozen=True)
|
|
95
|
+
class ExactWorkspaceFile:
|
|
96
|
+
relative_path: str
|
|
97
|
+
content: str
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
_EXACT_WORKSPACE_FILE = re.compile(
|
|
101
|
+
r"\s*(?:请)?在工作区(?:创建|写入)\s*"
|
|
102
|
+
r"(?P<path>(?:[A-Za-z0-9_.-]+/)*[A-Za-z0-9_.-]+)\s*[,,]\s*"
|
|
103
|
+
r"内容(?:必须)?(?:恰好是|完全是|只写|仅写)\s*"
|
|
104
|
+
r"(?P<content>[^。\r\n]{1,4096})。"
|
|
105
|
+
r"(?:完成后(?:再)?回复(?:文件)?路径。?)?\s*"
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def requested_exact_workspace_file(goal: str) -> ExactWorkspaceFile | None:
|
|
110
|
+
"""Only freeze an explicit path and byte-for-byte content, never infer them."""
|
|
111
|
+
match = _EXACT_WORKSPACE_FILE.fullmatch(goal)
|
|
112
|
+
if match is None:
|
|
113
|
+
return None
|
|
114
|
+
relative = Path(match.group("path"))
|
|
115
|
+
if relative.is_absolute() or any(part in {"", ".", ".."} for part in relative.parts):
|
|
116
|
+
return None
|
|
117
|
+
return ExactWorkspaceFile(relative.as_posix(), match.group("content"))
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def encode_exact_workspace_file(requirement: ExactWorkspaceFile) -> str:
|
|
121
|
+
return json.dumps(
|
|
122
|
+
{"relative_path": requirement.relative_path, "content": requirement.content},
|
|
123
|
+
ensure_ascii=False,
|
|
124
|
+
sort_keys=True,
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def exact_byte_difference(expected: bytes, actual: bytes) -> dict[str, int | str | None]:
|
|
129
|
+
"""Give bounded byte-level repair evidence without echoing file contents."""
|
|
130
|
+
offset = next(
|
|
131
|
+
(index for index, (left, right) in enumerate(zip(expected, actual)) if left != right),
|
|
132
|
+
min(len(expected), len(actual)),
|
|
133
|
+
)
|
|
134
|
+
return {
|
|
135
|
+
"first_mismatch_byte": offset,
|
|
136
|
+
"expected_byte_hex": f"{expected[offset]:02x}" if offset < len(expected) else None,
|
|
137
|
+
"actual_byte_hex": f"{actual[offset]:02x}" if offset < len(actual) else None,
|
|
138
|
+
"expected_byte_length": len(expected),
|
|
139
|
+
"actual_byte_length": len(actual),
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _read_exact_workspace_file(root: Path, requirement: ExactWorkspaceFile) -> tuple[bool, str]:
|
|
144
|
+
resolved_root = root.resolve()
|
|
145
|
+
target = resolved_root / requirement.relative_path
|
|
146
|
+
try:
|
|
147
|
+
inside = target.resolve(strict=False).is_relative_to(resolved_root)
|
|
148
|
+
except (OSError, RuntimeError):
|
|
149
|
+
inside = False
|
|
150
|
+
if not inside:
|
|
151
|
+
return False, "Requested file is outside the bound workspace."
|
|
152
|
+
try:
|
|
153
|
+
actual = target.read_bytes()
|
|
154
|
+
except (OSError, ValueError):
|
|
155
|
+
return False, "Requested file is missing or unreadable."
|
|
156
|
+
expected = requirement.content.encode("utf-8")
|
|
157
|
+
if actual != expected:
|
|
158
|
+
difference = exact_byte_difference(expected, actual)
|
|
159
|
+
return False, (
|
|
160
|
+
"Requested file bytes differ from the user's literal content at byte "
|
|
161
|
+
f"{difference['first_mismatch_byte']}: expected "
|
|
162
|
+
f"{difference['expected_byte_hex']}, actual {difference['actual_byte_hex']} "
|
|
163
|
+
"(UTF-8 hex)."
|
|
164
|
+
)
|
|
165
|
+
return True, hashlib.sha256(actual).hexdigest()
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def _decode_exact_workspace_file(value: str) -> ExactWorkspaceFile | None:
|
|
169
|
+
try:
|
|
170
|
+
parsed = json.loads(value)
|
|
171
|
+
except (TypeError, ValueError):
|
|
172
|
+
return None
|
|
173
|
+
if not isinstance(parsed, dict):
|
|
174
|
+
return None
|
|
175
|
+
relative = parsed.get("relative_path")
|
|
176
|
+
content = parsed.get("content")
|
|
177
|
+
if (
|
|
178
|
+
not isinstance(relative, str)
|
|
179
|
+
or not isinstance(content, str)
|
|
180
|
+
or not re.fullmatch(r"(?:[A-Za-z0-9_.-]+/)*[A-Za-z0-9_.-]+", relative)
|
|
181
|
+
or any(part in {"", ".", ".."} for part in Path(relative).parts)
|
|
182
|
+
or not 1 <= len(content) <= 4096
|
|
183
|
+
):
|
|
184
|
+
return None
|
|
185
|
+
return ExactWorkspaceFile(relative, content)
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
_NUMBER_REQUEST = re.compile(
|
|
189
|
+
r"\b(?:return|reply|respond|output|give)\s+only\s+"
|
|
190
|
+
r"(?:the|a|one)?\s*(?P<kind>total|sum|count|number|integer|numeric\s+value)"
|
|
191
|
+
r"(?:\s+(?:it|they|the\s+[a-z-]+)\s+(?:reported|returned|produced))?"
|
|
192
|
+
r"\s*[.!?]?\s*$",
|
|
193
|
+
re.IGNORECASE,
|
|
194
|
+
)
|
|
195
|
+
_DIGITS_REQUEST = re.compile(
|
|
196
|
+
r"\b(?:return|reply|respond|output|give)(?:\s+with)?\s+only\s+"
|
|
197
|
+
r"(?:the|those|these)?\s*digits?\s*[.!?]?\s*$",
|
|
198
|
+
re.IGNORECASE,
|
|
199
|
+
)
|
|
200
|
+
_SENTENCE_REQUEST = re.compile(
|
|
201
|
+
r"\b(?:return|reply|respond|output|give)\s+only\s+"
|
|
202
|
+
r"(?:the|a|one)\s+(?:[a-z-]+\s+){0,4}sentence\b"
|
|
203
|
+
r"(?:\s+from\s+[a-z0-9_./-]+)?\s*[.!?]?\s*$",
|
|
204
|
+
re.IGNORECASE,
|
|
205
|
+
)
|
|
206
|
+
_NUMBER_ANSWER = re.compile(r"[+-]?(?:\d+(?:\.\d+)?|\.\d+)")
|
|
207
|
+
_INTEGER_ANSWER = re.compile(r"[+-]?\d+")
|
|
208
|
+
_CHINESE_NUMBER_REQUEST = re.compile(r"(?:只|仅)(?:回复|输出)\s*(?:数字|数值)\s*[。.!!]?\s*$")
|
|
209
|
+
_CHINESE_JSON_BOOLEAN_REQUEST = re.compile(
|
|
210
|
+
r"(?:只|仅)(?:回复|输出)\s*JSON\s*布尔值\s*[。.!!]?\s*$", re.IGNORECASE
|
|
211
|
+
)
|
|
212
|
+
_CHINESE_CHOICE_REQUEST = re.compile(
|
|
213
|
+
r"(?:只|仅)(?:回复|输出)\s*"
|
|
214
|
+
r"(?P<first>[\w\u4e00-\u9fff]{1,16})\s*或\s*"
|
|
215
|
+
r"(?P<second>[\w\u4e00-\u9fff]{1,16})\s*[。.!!]?\s*$"
|
|
216
|
+
)
|
|
217
|
+
_STRUCTURED_JSON_REQUEST = re.compile(
|
|
218
|
+
r"\b(?:return|reply|respond|output|give)(?:\s+with)?\s+only\s+"
|
|
219
|
+
r"(?:a|one|the)?\s*JSON\s+(?P<kind>object|array)\s*[.!?]?\s*$",
|
|
220
|
+
re.IGNORECASE,
|
|
221
|
+
)
|
|
222
|
+
_CHINESE_STRUCTURED_JSON_REQUEST = re.compile(
|
|
223
|
+
r"\s*(?:(?:最后|最终)(?:请)?|请)?(?:只|仅)(?:回复|输出|返回)\s*"
|
|
224
|
+
r"(?:一个|上述|该)?\s*JSON\s*"
|
|
225
|
+
r"(?P<kind>对象|数组)(?:[,,]\s*(?:(?:键|字段|每项)[^。\n]*|"
|
|
226
|
+
r"格式(?:为|是)\s*(?P<format>\{[^。\n]*\}|\[[^。\n]*\])|"
|
|
227
|
+
r"(?P<header>(?:格式|结构)如下\s*[::])|"
|
|
228
|
+
r"(?:不(?:要|得)?|禁止)(?:附加|添加)(?:其他|额外|任何)?"
|
|
229
|
+
r"(?:说明|解释)(?:文字|文本)?))?\s*",
|
|
230
|
+
re.IGNORECASE,
|
|
231
|
+
)
|
|
232
|
+
_PYTHON_LIST_REQUEST = re.compile(
|
|
233
|
+
r"(?:^|[.!?\n]\s*)(?:return|reply|respond|output|give)(?:\s+with)?\s+only\s+"
|
|
234
|
+
r"(?:a|one|the)?\s*Python\s+list\s+literal\s*[.!?]?\s*$",
|
|
235
|
+
re.IGNORECASE,
|
|
236
|
+
)
|
|
237
|
+
_CHINESE_PYTHON_LIST_REQUEST = re.compile(
|
|
238
|
+
r"\s*(?:最后)?(?:只|仅)(?:回复|输出|返回)\s*Python\s*列表字面量\s*",
|
|
239
|
+
re.IGNORECASE,
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def _python_list_requested(goal: str) -> bool:
|
|
244
|
+
if _PYTHON_LIST_REQUEST.search(goal):
|
|
245
|
+
return True
|
|
246
|
+
# Only a complete directive counts. A quote, negation, or conflicting
|
|
247
|
+
# request must not silently become a host constraint.
|
|
248
|
+
return any(
|
|
249
|
+
_CHINESE_PYTHON_LIST_REQUEST.fullmatch(sentence) is not None
|
|
250
|
+
for sentence in re.split(r"[。!?\n]", goal)
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def _visible_goal_text(goal: str) -> str:
|
|
255
|
+
"""Quoted blocks and fenced examples cannot supply output authority."""
|
|
256
|
+
visible, fence = [], None
|
|
257
|
+
for line in goal.splitlines():
|
|
258
|
+
marker = re.match(r"\s*(`{3,}|~{3,})(.*)$", line)
|
|
259
|
+
if marker:
|
|
260
|
+
kind, length = marker[1][0], len(marker[1])
|
|
261
|
+
if fence is None:
|
|
262
|
+
fence = kind, length
|
|
263
|
+
elif fence[0] == kind and length >= fence[1] and not marker[2].strip():
|
|
264
|
+
fence = None
|
|
265
|
+
continue
|
|
266
|
+
if fence is None and not line.lstrip().startswith(">"):
|
|
267
|
+
visible.append(line)
|
|
268
|
+
return "\n".join(visible)
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def _directive_match(pattern: re.Pattern, text: str) -> re.Match | None:
|
|
272
|
+
"""A matching phrase needs an imperative clause, not just matching words."""
|
|
273
|
+
match = pattern.search(text)
|
|
274
|
+
if match is None:
|
|
275
|
+
return None
|
|
276
|
+
prefix = re.split(r"[.!?。?!\n,,]", text[:match.start()])[-1].strip().lower()
|
|
277
|
+
direct = prefix in {
|
|
278
|
+
"", "then", "finally", "and then", "请", "最后", "最终", "最后请", "最终请", "然后",
|
|
279
|
+
}
|
|
280
|
+
compound = re.fullmatch(
|
|
281
|
+
r"(?:read|inspect|check|calculate|compute|use|ask|analy[sz]e)\b"
|
|
282
|
+
r"[^\"'`::“”‘’]*\s+(?:and(?:\s+then)?|then)", prefix,
|
|
283
|
+
)
|
|
284
|
+
return match if direct or compound else None
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def _structured_json_clauses(goal: str) -> list[tuple[FinalShape, str]]:
|
|
288
|
+
# Parse explicit directives only, never contradictory outer shapes.
|
|
289
|
+
text = _visible_goal_text(goal)
|
|
290
|
+
candidates = []
|
|
291
|
+
if match := _directive_match(_STRUCTURED_JSON_REQUEST, text):
|
|
292
|
+
candidates.append(
|
|
293
|
+
("json_object" if match.group("kind") == "object" else "json_array", match[0])
|
|
294
|
+
)
|
|
295
|
+
sentences = re.split(r"[。\n]", text)
|
|
296
|
+
for index, sentence in enumerate(sentences):
|
|
297
|
+
sentence = re.sub(r"^\s*(?:-\s+|[1-9][0-9]{0,2}[.)]\s+)", "", sentence)
|
|
298
|
+
if match := _CHINESE_STRUCTURED_JSON_REQUEST.fullmatch(sentence):
|
|
299
|
+
expected = "{" if match.group("kind") == "对象" else "["
|
|
300
|
+
example = match.group("format")
|
|
301
|
+
if match.group("header"):
|
|
302
|
+
example = next((s.lstrip() for s in sentences[index + 1 :] if s.strip()), "")
|
|
303
|
+
if not example.startswith(("{", "[")):
|
|
304
|
+
continue
|
|
305
|
+
# Only validate the explicitly declared outer shape. Example
|
|
306
|
+
# fields, values and task semantics are never inferred here.
|
|
307
|
+
if example and example[0] != expected:
|
|
308
|
+
return []
|
|
309
|
+
candidates.append(("json_object" if expected == "{" else "json_array", match[0]))
|
|
310
|
+
return candidates
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
def _structured_json_clause(goal: str) -> tuple[FinalShape, str] | None:
|
|
314
|
+
candidates = _structured_json_clauses(goal)
|
|
315
|
+
if not candidates or len({shape for shape, _ in candidates}) != 1:
|
|
316
|
+
return None
|
|
317
|
+
return candidates[-1]
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
def final_shape_contract_description(goal: str) -> str:
|
|
321
|
+
"""Keep an explicit output clause when bounding the acceptance description.
|
|
322
|
+
|
|
323
|
+
The full goal remains in the Run's authoritative continuity state. This
|
|
324
|
+
description is only a rejection rule, not proof of semantic completion.
|
|
325
|
+
"""
|
|
326
|
+
suffix = goal[-1024:]
|
|
327
|
+
if requested_final_shape(suffix) == requested_final_shape(goal):
|
|
328
|
+
return suffix
|
|
329
|
+
if structured := _structured_json_clause(goal):
|
|
330
|
+
return structured[1][:1024]
|
|
331
|
+
return suffix
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
def requested_final_shape(goal: str) -> FinalShape | None:
|
|
335
|
+
"""Recognize only an unambiguous final clause; unknown requests get no rule."""
|
|
336
|
+
visible = _visible_goal_text(goal)
|
|
337
|
+
if number := _directive_match(_NUMBER_REQUEST, visible):
|
|
338
|
+
return "integer" if number["kind"].lower() == "integer" else "number"
|
|
339
|
+
if _directive_match(_CHINESE_NUMBER_REQUEST, visible):
|
|
340
|
+
return "number"
|
|
341
|
+
if _directive_match(_CHINESE_JSON_BOOLEAN_REQUEST, visible):
|
|
342
|
+
return "json_boolean"
|
|
343
|
+
if choices := _directive_match(_CHINESE_CHOICE_REQUEST, visible):
|
|
344
|
+
first, second = choices.group("first", "second")
|
|
345
|
+
if first != second:
|
|
346
|
+
return first, second
|
|
347
|
+
if _directive_match(_DIGITS_REQUEST, visible):
|
|
348
|
+
return "digits"
|
|
349
|
+
if _directive_match(_SENTENCE_REQUEST, visible):
|
|
350
|
+
return "sentence"
|
|
351
|
+
if structured := _structured_json_clause(goal):
|
|
352
|
+
return structured[0]
|
|
353
|
+
if _python_list_requested(visible):
|
|
354
|
+
return "python_list"
|
|
355
|
+
return None
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
def _violation(shape: FinalShape, text: str) -> str | None:
|
|
359
|
+
candidate = text.strip()
|
|
360
|
+
if isinstance(shape, tuple):
|
|
361
|
+
return (
|
|
362
|
+
None
|
|
363
|
+
if candidate in shape
|
|
364
|
+
else (
|
|
365
|
+
"Return exactly one of the two requested values, "
|
|
366
|
+
"without punctuation or explanation."
|
|
367
|
+
)
|
|
368
|
+
)
|
|
369
|
+
if shape == "number":
|
|
370
|
+
return (
|
|
371
|
+
None
|
|
372
|
+
if _NUMBER_ANSWER.fullmatch(candidate)
|
|
373
|
+
else "Return only one numeric value, without a preamble or Markdown."
|
|
374
|
+
)
|
|
375
|
+
if shape == "integer":
|
|
376
|
+
return (None if _INTEGER_ANSWER.fullmatch(candidate) else
|
|
377
|
+
"Return only one integer, without a preamble, Markdown or a decimal fraction.")
|
|
378
|
+
if shape == "digits":
|
|
379
|
+
return (
|
|
380
|
+
None
|
|
381
|
+
if re.fullmatch(r"[0-9]+", candidate)
|
|
382
|
+
else "Return only the requested digits, without a preamble or Markdown."
|
|
383
|
+
)
|
|
384
|
+
if shape == "json_boolean":
|
|
385
|
+
return (
|
|
386
|
+
None
|
|
387
|
+
if candidate in {"true", "false"}
|
|
388
|
+
else "Return only a JSON boolean literal: true or false, without Markdown."
|
|
389
|
+
)
|
|
390
|
+
if shape in {"json_object", "json_array"}:
|
|
391
|
+
|
|
392
|
+
def reject_constant(_value):
|
|
393
|
+
raise ValueError("non-JSON numeric constant")
|
|
394
|
+
|
|
395
|
+
try:
|
|
396
|
+
parsed = json.loads(candidate, parse_constant=reject_constant)
|
|
397
|
+
if isinstance(parsed, dict if shape == "json_object" else list):
|
|
398
|
+
return None
|
|
399
|
+
except (ValueError, RecursionError):
|
|
400
|
+
pass
|
|
401
|
+
return (
|
|
402
|
+
"Return only one valid JSON "
|
|
403
|
+
+ ("object" if shape == "json_object" else "array")
|
|
404
|
+
+ ", without a preamble, Markdown fence or trailing explanation."
|
|
405
|
+
)
|
|
406
|
+
if shape == "python_list":
|
|
407
|
+
# Parse a literal, never execute generated Python. The length/node
|
|
408
|
+
# bounds also apply to rejected proposals before recursive evaluation.
|
|
409
|
+
try:
|
|
410
|
+
if len(candidate) <= 65536:
|
|
411
|
+
expression = ast.parse(candidate, mode="eval")
|
|
412
|
+
if (
|
|
413
|
+
isinstance(expression.body, ast.List)
|
|
414
|
+
and ast.get_source_segment(candidate, expression.body) == candidate
|
|
415
|
+
and sum(1 for _node in ast.walk(expression)) <= 4096
|
|
416
|
+
and isinstance(ast.literal_eval(expression), list)
|
|
417
|
+
):
|
|
418
|
+
return None
|
|
419
|
+
except (SyntaxError, ValueError, RecursionError):
|
|
420
|
+
pass
|
|
421
|
+
return (
|
|
422
|
+
"Return only one Python list literal, without Markdown, "
|
|
423
|
+
"an assignment, a computed expression or trailing explanation."
|
|
424
|
+
)
|
|
425
|
+
if (
|
|
426
|
+
not candidate
|
|
427
|
+
or len(candidate.splitlines()) != 1
|
|
428
|
+
or candidate.startswith((">", "#", "-", "*", "`"))
|
|
429
|
+
or "**" in candidate
|
|
430
|
+
or "`" in candidate
|
|
431
|
+
):
|
|
432
|
+
return "Return only the requested sentence on one plain-text line."
|
|
433
|
+
return None
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
def _sha256(value: str) -> str:
|
|
437
|
+
return "sha256:" + hashlib.sha256(value.encode("utf-8")).hexdigest()
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
def _written_web_entry(store: RunStore, scope: RunScope, run_id: str, root: Path) -> str | None:
|
|
441
|
+
"""Choose an entry only after this Run received a successful write receipt."""
|
|
442
|
+
try:
|
|
443
|
+
snapshot = store.load(scope, run_id)
|
|
444
|
+
except Exception:
|
|
445
|
+
return None
|
|
446
|
+
proposed: dict[str, str] = {}
|
|
447
|
+
written: set[str] = {
|
|
448
|
+
path
|
|
449
|
+
for path in snapshot.workspace_modified_paths
|
|
450
|
+
if path.endswith((".html", ".htm", ".js", ".jsx", ".css"))
|
|
451
|
+
}
|
|
452
|
+
for message in snapshot.messages:
|
|
453
|
+
if message.get("role") == "assistant":
|
|
454
|
+
for call in message.get("tool_calls") or ():
|
|
455
|
+
if not isinstance(call, dict):
|
|
456
|
+
continue
|
|
457
|
+
function = call.get("function")
|
|
458
|
+
if not isinstance(function, dict) or function.get("name") != "write_workspace_file":
|
|
459
|
+
continue
|
|
460
|
+
arguments = function.get("arguments")
|
|
461
|
+
if isinstance(arguments, str):
|
|
462
|
+
try:
|
|
463
|
+
arguments = json.loads(arguments)
|
|
464
|
+
except ValueError:
|
|
465
|
+
continue
|
|
466
|
+
path = arguments.get("path") if isinstance(arguments, dict) else None
|
|
467
|
+
call_id = call.get("id")
|
|
468
|
+
if (
|
|
469
|
+
isinstance(call_id, str)
|
|
470
|
+
and isinstance(path, str)
|
|
471
|
+
and path.endswith((".html", ".htm", ".js", ".jsx", ".css"))
|
|
472
|
+
):
|
|
473
|
+
proposed[call_id] = path
|
|
474
|
+
elif message.get("role") == "tool":
|
|
475
|
+
call_id = message.get("tool_call_id")
|
|
476
|
+
if not isinstance(call_id, str) or call_id not in proposed:
|
|
477
|
+
continue
|
|
478
|
+
content = message.get("content")
|
|
479
|
+
if isinstance(content, list):
|
|
480
|
+
content = next(
|
|
481
|
+
(
|
|
482
|
+
block.get("text")
|
|
483
|
+
for block in content
|
|
484
|
+
if isinstance(block, dict) and block.get("type") == "text"
|
|
485
|
+
),
|
|
486
|
+
None,
|
|
487
|
+
)
|
|
488
|
+
try:
|
|
489
|
+
receipt = json.loads(content) if isinstance(content, str) else None
|
|
490
|
+
except ValueError:
|
|
491
|
+
receipt = None
|
|
492
|
+
if isinstance(receipt, dict) and receipt.get("status") == "ok":
|
|
493
|
+
written.add(proposed[call_id])
|
|
494
|
+
if not written:
|
|
495
|
+
return None
|
|
496
|
+
resolved_root = root.resolve()
|
|
497
|
+
direct = sorted(path for path in written if Path(path).name == "index.html")
|
|
498
|
+
candidates = direct or ["index.html"]
|
|
499
|
+
for path in candidates:
|
|
500
|
+
target = (resolved_root / path).resolve()
|
|
501
|
+
if target.is_relative_to(resolved_root) and target.is_file():
|
|
502
|
+
return target.relative_to(resolved_root).as_posix()
|
|
503
|
+
return None
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
class StudioFinalShapeVerifier:
|
|
507
|
+
"""Per-activation verifier with no authority to approve task semantics."""
|
|
508
|
+
|
|
509
|
+
def __init__(
|
|
510
|
+
self,
|
|
511
|
+
scope: RunScope,
|
|
512
|
+
*,
|
|
513
|
+
build_id: str,
|
|
514
|
+
workspace_root: Path | None = None,
|
|
515
|
+
store: RunStore | None = None,
|
|
516
|
+
browser: StudioNativeBrowserPort | None = None,
|
|
517
|
+
require_visual_feedback: bool = False,
|
|
518
|
+
) -> None:
|
|
519
|
+
self._scope = scope.model_copy(deep=True)
|
|
520
|
+
self._environment_digest = _sha256(
|
|
521
|
+
f"{build_id}\0{VERIFIER_REF}\0{VERIFIER_VERSION}\0"
|
|
522
|
+
f"{BROWSER_VERIFIER_REF}\0{BROWSER_VERIFIER_VERSION}\0"
|
|
523
|
+
f"{ARTIFACT_VERIFIER_REF}\0{ARTIFACT_VERIFIER_VERSION}\0"
|
|
524
|
+
f"visual-feedback:{int(require_visual_feedback)}"
|
|
525
|
+
)
|
|
526
|
+
self._workspace_root = workspace_root
|
|
527
|
+
self._store = store
|
|
528
|
+
self._browser = browser
|
|
529
|
+
self._require_visual_feedback = require_visual_feedback
|
|
530
|
+
|
|
531
|
+
async def verify(self, request: VerificationRequest) -> VerificationBundle:
|
|
532
|
+
if request.scope != self._scope:
|
|
533
|
+
raise ValueError("native_final_shape_scope_mismatch")
|
|
534
|
+
acceptance = request.contract.items[0] if request.contract.items else None
|
|
535
|
+
general_evidence = (
|
|
536
|
+
acceptance is not None
|
|
537
|
+
and acceptance.verifier_ref == EVIDENCE_VERIFIER_REF
|
|
538
|
+
and acceptance.verifier_version == EVIDENCE_VERIFIER_VERSION
|
|
539
|
+
)
|
|
540
|
+
candidate = CompletionCandidate(
|
|
541
|
+
candidate_id=request.candidate_id,
|
|
542
|
+
final_text=request.final_text,
|
|
543
|
+
subject_digest=_sha256(request.final_text),
|
|
544
|
+
subject_context_digest=request.subject_context_digest,
|
|
545
|
+
# Do not reinterpret legacy persisted reports under new semantics.
|
|
546
|
+
environment_digest=_sha256(
|
|
547
|
+
f"{self._environment_digest}\0{EVIDENCE_VERIFIER_REF}\0"
|
|
548
|
+
f"{EVIDENCE_VERIFIER_VERSION}"
|
|
549
|
+
) if general_evidence else self._environment_digest,
|
|
550
|
+
)
|
|
551
|
+
if not 1 <= len(request.contract.items) <= 2:
|
|
552
|
+
return VerificationBundle(candidate=candidate, report=None)
|
|
553
|
+
acceptance = request.contract.items[0]
|
|
554
|
+
shape = requested_final_shape(acceptance.description)
|
|
555
|
+
browser_check = (
|
|
556
|
+
(
|
|
557
|
+
general_evidence
|
|
558
|
+
or (
|
|
559
|
+
acceptance.verifier_ref == BROWSER_VERIFIER_REF
|
|
560
|
+
and acceptance.verifier_version == BROWSER_VERIFIER_VERSION
|
|
561
|
+
)
|
|
562
|
+
)
|
|
563
|
+
and self._browser is not None
|
|
564
|
+
and self._store is not None
|
|
565
|
+
and self._workspace_root is not None
|
|
566
|
+
)
|
|
567
|
+
artifact_item = request.contract.items[1] if len(request.contract.items) == 2 else None
|
|
568
|
+
exact_file = (
|
|
569
|
+
_decode_exact_workspace_file(artifact_item.description) if artifact_item else None
|
|
570
|
+
)
|
|
571
|
+
if (
|
|
572
|
+
(shape is None and exact_file is None and not browser_check and not general_evidence)
|
|
573
|
+
or (
|
|
574
|
+
not general_evidence
|
|
575
|
+
and not browser_check
|
|
576
|
+
and (
|
|
577
|
+
acceptance.verifier_ref != VERIFIER_REF
|
|
578
|
+
or acceptance.verifier_version != VERIFIER_VERSION
|
|
579
|
+
)
|
|
580
|
+
)
|
|
581
|
+
or acceptance.verification_method != "deterministic"
|
|
582
|
+
or (
|
|
583
|
+
artifact_item is not None
|
|
584
|
+
and (
|
|
585
|
+
exact_file is None
|
|
586
|
+
or self._workspace_root is None
|
|
587
|
+
or artifact_item.acceptance_id != "exact_workspace_file"
|
|
588
|
+
or artifact_item.verifier_ref != ARTIFACT_VERIFIER_REF
|
|
589
|
+
or artifact_item.verifier_version != ARTIFACT_VERIFIER_VERSION
|
|
590
|
+
or artifact_item.verification_method != "deterministic"
|
|
591
|
+
)
|
|
592
|
+
)
|
|
593
|
+
):
|
|
594
|
+
return VerificationBundle(candidate=candidate, report=None)
|
|
595
|
+
shape_failure = (
|
|
596
|
+
_violation(shape, request.final_text) if shape and request.purpose == "final" else None
|
|
597
|
+
)
|
|
598
|
+
browser_failure = None
|
|
599
|
+
browser_checked = False
|
|
600
|
+
browser_controls = ""
|
|
601
|
+
browser_evidence_ref: str | None = None
|
|
602
|
+
if browser_check:
|
|
603
|
+
assert self._store is not None and self._workspace_root is not None
|
|
604
|
+
entry = _written_web_entry(
|
|
605
|
+
self._store, self._scope, request.run_id, self._workspace_root
|
|
606
|
+
)
|
|
607
|
+
if entry is not None:
|
|
608
|
+
try:
|
|
609
|
+
observation = await self._browser.verify_page(
|
|
610
|
+
run_id=request.run_id,
|
|
611
|
+
entry_path=entry,
|
|
612
|
+
candidate_id=request.candidate_id,
|
|
613
|
+
)
|
|
614
|
+
browser_checked = True
|
|
615
|
+
browser_evidence_ref = (
|
|
616
|
+
observation.screenshot.content_ref
|
|
617
|
+
if observation.screenshot is not None
|
|
618
|
+
else _sha256(
|
|
619
|
+
json.dumps(
|
|
620
|
+
{
|
|
621
|
+
"entry": entry,
|
|
622
|
+
"status": observation.status,
|
|
623
|
+
"status_code": observation.status_code,
|
|
624
|
+
"error_code": observation.error_code,
|
|
625
|
+
"console": observation.console,
|
|
626
|
+
"page_errors": observation.page_errors,
|
|
627
|
+
"page_error_locations": getattr(
|
|
628
|
+
observation, "page_error_locations", ()
|
|
629
|
+
),
|
|
630
|
+
"network_failures": observation.network_failures,
|
|
631
|
+
},
|
|
632
|
+
ensure_ascii=False,
|
|
633
|
+
sort_keys=True,
|
|
634
|
+
)
|
|
635
|
+
)
|
|
636
|
+
)
|
|
637
|
+
browser_controls = ", ".join(
|
|
638
|
+
f"{control.label[:80]} ({control.selector or control.tag})"
|
|
639
|
+
for control in observation.controls[:8]
|
|
640
|
+
if control.label
|
|
641
|
+
)[:800]
|
|
642
|
+
if observation.status != "ok" or (
|
|
643
|
+
observation.status_code is not None and observation.status_code >= 400
|
|
644
|
+
):
|
|
645
|
+
reason = (
|
|
646
|
+
observation.error_code or observation.status_code or observation.status
|
|
647
|
+
)
|
|
648
|
+
browser_failure = (
|
|
649
|
+
"The delivered page has multiple visible start controls. "
|
|
650
|
+
"Remove duplicate launch controls and inspect the current page again."
|
|
651
|
+
if reason == "browser_launch_control_ambiguous"
|
|
652
|
+
else f"Browser could not load the delivered page: {reason}."
|
|
653
|
+
)
|
|
654
|
+
elif (
|
|
655
|
+
any(
|
|
656
|
+
not browser_environment_warning(item)
|
|
657
|
+
for item in observation.page_errors
|
|
658
|
+
)
|
|
659
|
+
or any(
|
|
660
|
+
item.startswith(("error:", "assert:"))
|
|
661
|
+
and not browser_environment_warning(item)
|
|
662
|
+
for item in observation.console
|
|
663
|
+
)
|
|
664
|
+
or observation.network_failures
|
|
665
|
+
):
|
|
666
|
+
policy_denial = next(
|
|
667
|
+
(
|
|
668
|
+
item
|
|
669
|
+
for item in observation.network_failures
|
|
670
|
+
if item.startswith(("network_denied:", "websocket_denied:"))
|
|
671
|
+
),
|
|
672
|
+
None,
|
|
673
|
+
)
|
|
674
|
+
if policy_denial is not None:
|
|
675
|
+
browser_failure = (
|
|
676
|
+
"Browser blocked a page request under the locked network "
|
|
677
|
+
"policy. Use assets served from the authorized local origin "
|
|
678
|
+
"and inspect the page again."
|
|
679
|
+
)
|
|
680
|
+
else:
|
|
681
|
+
missing_asset = next(
|
|
682
|
+
(
|
|
683
|
+
item
|
|
684
|
+
for item in observation.network_failures
|
|
685
|
+
if item.startswith("asset_http_error:")
|
|
686
|
+
),
|
|
687
|
+
None,
|
|
688
|
+
)
|
|
689
|
+
if missing_asset is not None:
|
|
690
|
+
# Chromium's generic console 404 lacks the
|
|
691
|
+
# requested path. The browser host recorded
|
|
692
|
+
# the failing local script/style response.
|
|
693
|
+
browser_failure = (
|
|
694
|
+
"Browser could not load a local script or stylesheet: "
|
|
695
|
+
f"{missing_asset[:300]}. Fix that asset and inspect again."
|
|
696
|
+
)
|
|
697
|
+
else:
|
|
698
|
+
error = (
|
|
699
|
+
*(
|
|
700
|
+
item
|
|
701
|
+
for item in observation.page_errors
|
|
702
|
+
if not browser_environment_warning(item)
|
|
703
|
+
),
|
|
704
|
+
*(
|
|
705
|
+
item
|
|
706
|
+
for item in observation.console
|
|
707
|
+
if item.startswith(("error:", "assert:"))
|
|
708
|
+
and not browser_environment_warning(item)
|
|
709
|
+
),
|
|
710
|
+
*observation.network_failures,
|
|
711
|
+
)[0]
|
|
712
|
+
locations = getattr(observation, "page_error_locations", ())
|
|
713
|
+
where = f" at {locations[0][:300]}" if locations else ""
|
|
714
|
+
browser_failure = (
|
|
715
|
+
f"Browser reported an error in {entry}{where}: {error[:500]}"
|
|
716
|
+
)
|
|
717
|
+
except Exception:
|
|
718
|
+
# An unavailable host browser is missing evidence, not
|
|
719
|
+
# proof that the user's implementation is defective.
|
|
720
|
+
pass
|
|
721
|
+
# Checkpoints are triggered after a browser observation on changed
|
|
722
|
+
# web files. Surface a wrong/stale delivery page immediately, while
|
|
723
|
+
# the model still has tool budget to inspect and repair it.
|
|
724
|
+
if request.purpose in {"final", "checkpoint"} and entry is not None:
|
|
725
|
+
try:
|
|
726
|
+
run_snapshot = self._store.load(self._scope, request.run_id)
|
|
727
|
+
unresolved = run_snapshot.unresolved_interaction_observation
|
|
728
|
+
except Exception:
|
|
729
|
+
run_snapshot = None
|
|
730
|
+
unresolved = None
|
|
731
|
+
if (
|
|
732
|
+
isinstance(unresolved, dict)
|
|
733
|
+
and unresolved.get("tool_name") == "browser_inspect_workspace"
|
|
734
|
+
and unresolved.get("entry_path") == entry
|
|
735
|
+
):
|
|
736
|
+
browser_failure = (
|
|
737
|
+
"The browser interaction previously failed and has not been "
|
|
738
|
+
"successfully rechecked: "
|
|
739
|
+
+ str(unresolved.get("error") or "browser error")[:300]
|
|
740
|
+
)
|
|
741
|
+
ref = unresolved.get("evidence_ref")
|
|
742
|
+
if isinstance(ref, str):
|
|
743
|
+
browser_evidence_ref = ref
|
|
744
|
+
if browser_failure is None:
|
|
745
|
+
observed = (
|
|
746
|
+
getattr(run_snapshot, "last_browser_observation", None)
|
|
747
|
+
if run_snapshot is not None
|
|
748
|
+
else None
|
|
749
|
+
)
|
|
750
|
+
last_web_change = (
|
|
751
|
+
getattr(run_snapshot, "last_web_mutation_tool_call", None)
|
|
752
|
+
if run_snapshot is not None
|
|
753
|
+
else None
|
|
754
|
+
)
|
|
755
|
+
fresh = (
|
|
756
|
+
isinstance(observed, dict)
|
|
757
|
+
and observed.get("entry_path") == entry
|
|
758
|
+
and type(observed.get("tool_call")) is int
|
|
759
|
+
and observed["tool_call"] >= (last_web_change or 0)
|
|
760
|
+
and (
|
|
761
|
+
not self._require_visual_feedback
|
|
762
|
+
or observed.get("vision_description_status") == "available"
|
|
763
|
+
)
|
|
764
|
+
)
|
|
765
|
+
if not fresh:
|
|
766
|
+
browser_failure = (
|
|
767
|
+
"The current screenshot has no usable visual-model description. "
|
|
768
|
+
"Inspect the latest page again with the authorized browser tool."
|
|
769
|
+
if self._require_visual_feedback
|
|
770
|
+
and isinstance(observed, dict)
|
|
771
|
+
and observed.get("entry_path") == entry
|
|
772
|
+
and type(observed.get("tool_call")) is int
|
|
773
|
+
and observed["tool_call"] >= (last_web_change or 0)
|
|
774
|
+
else "The delivered web page has not been observed through the "
|
|
775
|
+
"browser tool after the latest web file change. Open and inspect "
|
|
776
|
+
"the current page before finalizing."
|
|
777
|
+
)
|
|
778
|
+
browser_evidence_ref = _sha256(
|
|
779
|
+
f"browser_observation_missing\0{entry}\0{last_web_change}"
|
|
780
|
+
)
|
|
781
|
+
if request.purpose == "checkpoint" and not browser_checked and exact_file is None:
|
|
782
|
+
return VerificationBundle(candidate=candidate, report=None)
|
|
783
|
+
artifact_ok = False
|
|
784
|
+
artifact_observation = ""
|
|
785
|
+
if exact_file is not None and self._workspace_root is not None:
|
|
786
|
+
artifact_ok, artifact_observation = _read_exact_workspace_file(
|
|
787
|
+
self._workspace_root, exact_file
|
|
788
|
+
)
|
|
789
|
+
failure = (
|
|
790
|
+
shape_failure
|
|
791
|
+
or browser_failure
|
|
792
|
+
or (artifact_observation if exact_file and not artifact_ok else None)
|
|
793
|
+
)
|
|
794
|
+
items = [
|
|
795
|
+
VerificationItemResult(
|
|
796
|
+
acceptance_id=acceptance.acceptance_id,
|
|
797
|
+
status="failed" if failure else "not_run",
|
|
798
|
+
verifier_id=acceptance.verifier_ref,
|
|
799
|
+
verifier_version=acceptance.verifier_version,
|
|
800
|
+
evidence_refs=(browser_evidence_ref,)
|
|
801
|
+
if browser_failure and browser_evidence_ref is not None
|
|
802
|
+
else (_sha256(f"{request.final_text}\0{artifact_observation}"),)
|
|
803
|
+
if failure
|
|
804
|
+
else (),
|
|
805
|
+
verification_method="deterministic",
|
|
806
|
+
safe_summary=failure
|
|
807
|
+
or (
|
|
808
|
+
"Browser smoke check observed no load or script errors. "
|
|
809
|
+
f"Visible controls: {browser_controls or 'none'}. "
|
|
810
|
+
"Interaction and task semantics were not verified."
|
|
811
|
+
if browser_checked
|
|
812
|
+
else (
|
|
813
|
+
"Final-answer shape passed; task semantics were not independently verified."
|
|
814
|
+
)
|
|
815
|
+
if shape
|
|
816
|
+
else "Task semantics were not independently verified."
|
|
817
|
+
if general_evidence
|
|
818
|
+
else "No independent browser evidence was available."
|
|
819
|
+
),
|
|
820
|
+
)
|
|
821
|
+
]
|
|
822
|
+
if artifact_item is not None:
|
|
823
|
+
items.append(
|
|
824
|
+
VerificationItemResult(
|
|
825
|
+
acceptance_id="exact_workspace_file",
|
|
826
|
+
status="passed" if artifact_ok else "failed",
|
|
827
|
+
verifier_id=ARTIFACT_VERIFIER_REF,
|
|
828
|
+
verifier_version=ARTIFACT_VERIFIER_VERSION,
|
|
829
|
+
evidence_refs=("sha256:" + artifact_observation,) if artifact_ok else (),
|
|
830
|
+
verification_method="deterministic",
|
|
831
|
+
safe_summary=(
|
|
832
|
+
"Requested file bytes match exactly."
|
|
833
|
+
if artifact_ok
|
|
834
|
+
else artifact_observation
|
|
835
|
+
),
|
|
836
|
+
)
|
|
837
|
+
)
|
|
838
|
+
report = VerificationReport(
|
|
839
|
+
candidate_id=request.candidate_id,
|
|
840
|
+
contract_revision=request.contract.revision,
|
|
841
|
+
subject_digest=candidate.subject_digest,
|
|
842
|
+
subject_context_digest=request.subject_context_digest,
|
|
843
|
+
environment_digest=candidate.environment_digest,
|
|
844
|
+
items=tuple(items),
|
|
845
|
+
repairable=bool(failure),
|
|
846
|
+
failure_fingerprint=(
|
|
847
|
+
_sha256(f"{shape}\0{request.final_text}\0{artifact_observation}\0{browser_failure}")
|
|
848
|
+
if failure
|
|
849
|
+
else ""
|
|
850
|
+
),
|
|
851
|
+
)
|
|
852
|
+
return VerificationBundle(candidate=candidate, report=report)
|