agentengine-sdk-python 0.8.0__py3-none-any.whl → 0.8.2__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.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/METADATA +43 -7
- agentengine_sdk_python-0.8.2.dist-info/RECORD +778 -0
- {agentengine_sdk_python-0.8.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/WHEEL +1 -1
- ksadk/a2a/__init__.py +2 -0
- ksadk/a2a/_space_client_events.py +381 -0
- ksadk/a2a/bootstrap.py +0 -2
- ksadk/a2a/card.py +6 -111
- ksadk/a2a/control_plane.py +239 -1
- ksadk/a2a/event_adapter.py +156 -64
- ksadk/a2a/executor.py +195 -172
- ksadk/a2a/routes.py +12 -5
- ksadk/a2a/server.py +1 -8
- ksadk/a2a/service_env.py +33 -0
- ksadk/a2a/space_client.py +43 -349
- ksadk/a2a_card.py +101 -0
- ksadk/a2ui/core.py +222 -53
- ksadk/agui/_agent_helpers.py +243 -0
- ksadk/agui/a2ui_projection.py +12 -5
- ksadk/agui/agent.py +474 -275
- ksadk/agui/config.py +11 -5
- ksadk/agui/routes.py +7 -15
- ksadk/api/client.py +530 -40
- ksadk/api/environment.py +27 -0
- ksadk/builders/code_builder.py +352 -53
- ksadk/builders/container_builder.py +71 -44
- ksadk/builders/framework_requirements.py +2 -1
- ksadk/builders/ks3_uploader.py +2 -2
- ksadk/builders/managed_runtime_builder.py +60 -28
- ksadk/cli/__init__.py +25 -0
- ksadk/cli/cmd_a2a.py +18 -31
- ksadk/cli/cmd_create.py +13 -26
- ksadk/cli/cmd_dashboard.py +15 -1
- ksadk/cli/cmd_deploy.py +28 -3
- ksadk/cli/cmd_eval.py +443 -0
- ksadk/cli/cmd_evalset.py +284 -0
- ksadk/cli/cmd_files.py +5 -1
- ksadk/cli/cmd_hermes.py +137 -163
- ksadk/cli/cmd_invoke.py +28 -38
- ksadk/cli/cmd_launch.py +12 -0
- ksadk/cli/cmd_managed_runtime.py +95 -0
- ksadk/cli/cmd_observe.py +85 -0
- ksadk/cli/cmd_openclaw.py +85 -479
- ksadk/cli/cmd_replay.py +28 -4
- ksadk/cli/cmd_run.py +29 -67
- ksadk/cli/cmd_studio.py +201 -0
- ksadk/cli/cmd_web.py +15 -6
- ksadk/cli/dry_run.py +2 -1
- ksadk/cli/env_options.py +83 -0
- ksadk/cli/global_options.py +3 -1
- ksadk/cli/hermes_env.py +151 -0
- ksadk/cli/invoke_payload.py +49 -0
- ksadk/cli/network_options.py +7 -5
- ksadk/cli/openclaw_env.py +458 -0
- ksadk/cli/runtime_bootstrap.py +51 -0
- ksadk/cli/ui.py +6 -0
- ksadk/cli/workflow_common.py +5 -5
- ksadk/codex/__init__.py +3 -3
- ksadk/codex/client.py +833 -49
- ksadk/codex/phase.py +1 -1
- ksadk/codex/runtime.py +720 -127
- ksadk/common/kop_client.py +232 -0
- ksadk/configs/__init__.py +1 -3
- ksadk/configs/env_registry.py +244 -45
- ksadk/configs/env_registry_pcm.py +181 -0
- ksadk/configs/env_var_spec.py +18 -0
- ksadk/configs/global_config.py +6 -1
- ksadk/configs/settings.py +5 -108
- ksadk/context_engine/__init__.py +98 -0
- ksadk/context_engine/assembler.py +176 -0
- ksadk/context_engine/baseline.py +419 -0
- ksadk/context_engine/cache_observability.py +228 -0
- ksadk/context_engine/capabilities.py +443 -0
- ksadk/context_engine/contributors.py +344 -0
- ksadk/context_engine/hosted_pipeline.py +417 -0
- ksadk/context_engine/models.py +117 -0
- ksadk/context_engine/planner.py +698 -0
- ksadk/context_engine/policies.py +319 -0
- ksadk/context_engine/projection.py +31 -0
- ksadk/context_engine/shadow_plan.py +266 -0
- ksadk/context_engine/tokenizer.py +164 -0
- ksadk/conversations/__init__.py +85 -94
- ksadk/conversations/context.py +126 -6
- ksadk/conversations/message_projection.py +292 -28
- ksadk/conversations/model_context.py +49 -3
- ksadk/conversations/runtime_compaction.py +207 -5
- ksadk/conversations/runtime_input.py +193 -3
- ksadk/conversations/runtime_invocation.py +81 -3
- ksadk/conversations/runtime_observability.py +157 -4
- ksadk/conversations/runtime_payloads.py +42 -0
- ksadk/conversations/runtime_preparation.py +280 -2
- ksadk/conversations/runtime_resume.py +71 -32
- ksadk/conversations/runtime_stream_events.py +94 -9
- ksadk/conversations/runtime_streaming.py +175 -22
- ksadk/conversations/semantic_summary.py +311 -1
- ksadk/conversations/session_lock.py +51 -0
- ksadk/deployment/env_forward.py +72 -0
- ksadk/deployment/managed_runtime.py +38 -0
- ksadk/deployment/manager.py +24 -8
- ksadk/deployment/providers/serverless.py +228 -92
- ksadk/evaluation/__init__.py +116 -0
- ksadk/evaluation/a2a_adapter.py +452 -0
- ksadk/evaluation/adapters.py +67 -0
- ksadk/evaluation/agent_eval_client.py +395 -0
- ksadk/evaluation/cloud_binding.py +80 -0
- ksadk/evaluation/cloud_converter.py +194 -0
- ksadk/evaluation/cloud_service.py +199 -0
- ksadk/evaluation/contracts.py +478 -0
- ksadk/evaluation/evalset.py +351 -0
- ksadk/evaluation/evaluators.py +627 -0
- ksadk/evaluation/evidence.py +258 -0
- ksadk/evaluation/executor.py +143 -0
- ksadk/evaluation/local_adapter.py +550 -0
- ksadk/evaluation/service_env.py +27 -0
- ksadk/evaluation/storage.py +68 -0
- ksadk/evaluation/studio_build_adapter.py +253 -0
- ksadk/evaluation/target.py +82 -0
- ksadk/events/__init__.py +13 -13
- ksadk/events/_v1_compat/__init__.py +1 -0
- ksadk/events/_v1_compat/models.py +299 -0
- ksadk/events/_v1_compat/parser.py +247 -0
- ksadk/events/_v1_compat/projection.py +753 -0
- ksadk/events/adapters/__init__.py +34 -0
- ksadk/events/adapters/_a2a_snapshot.py +622 -0
- ksadk/events/adapters/_a2a_support.py +275 -0
- ksadk/events/adapters/_codex_interactions.py +375 -0
- ksadk/events/adapters/_codex_items.py +801 -0
- ksadk/events/adapters/_codex_validators.py +311 -0
- ksadk/events/adapters/_langgraph_support.py +785 -0
- ksadk/events/adapters/a2a.py +841 -0
- ksadk/events/adapters/adk.py +503 -0
- ksadk/events/adapters/codex.py +717 -0
- ksadk/events/adapters/langgraph.py +745 -0
- ksadk/events/canonical.py +440 -0
- ksadk/events/canonical_replay.py +497 -0
- ksadk/events/canonical_store.py +468 -0
- ksadk/events/cold_recovery.py +257 -0
- ksadk/events/content.py +89 -0
- ksadk/events/identity.py +86 -0
- ksadk/events/pipeline.py +455 -0
- ksadk/events/projections.py +66 -0
- ksadk/events/reducer.py +661 -0
- ksadk/events/replay.py +3 -36
- ksadk/events/runtime_event.py +20 -256
- ksadk/events/session_event.py +324 -0
- ksadk/events/store.py +3 -316
- ksadk/events/v1_compat.py +41 -0
- ksadk/harness/__init__.py +3 -2
- ksadk/harness/app.py +114 -123
- ksadk/harness/config.py +1 -1
- ksadk/harness/runtime.py +467 -0
- ksadk/hermes_terminal.py +5 -0
- ksadk/identity/resolver.py +4 -3
- ksadk/interaction/__init__.py +28 -0
- ksadk/interaction/contracts.py +136 -0
- ksadk/interaction/ledger.py +189 -0
- ksadk/interaction/provider.py +122 -0
- ksadk/interaction/providers/__init__.py +52 -0
- ksadk/interaction/providers/adk.py +40 -0
- ksadk/interaction/providers/codex.py +94 -0
- ksadk/interaction/providers/langgraph.py +58 -0
- ksadk/kernel/__init__.py +117 -0
- ksadk/kernel/authorization.py +258 -0
- ksadk/kernel/bootstrap.py +1074 -0
- ksadk/kernel/contract_fingerprints.py +61 -0
- ksadk/kernel/contracts.py +362 -0
- ksadk/kernel/control.py +219 -0
- ksadk/kernel/errors.py +79 -0
- ksadk/kernel/ingress.py +1102 -0
- ksadk/kernel/mapping.py +111 -0
- ksadk/kernel/memory_store.py +1133 -0
- ksadk/kernel/postgres_store.py +1756 -0
- ksadk/kernel/recovery.py +452 -0
- ksadk/kernel/runtime_identity.py +103 -0
- ksadk/kernel/sql/001_agent_kernel.sql +120 -0
- ksadk/kernel/sqlite_store.py +1410 -0
- ksadk/kernel/state.py +145 -0
- ksadk/kernel/store.py +232 -0
- ksadk/kernel/worker.py +953 -0
- ksadk/knowledge_base/client.py +22 -4
- ksadk/knowledge_base/service.py +32 -5
- ksadk/managed_a2a_card.py +160 -0
- ksadk/managed_runtime.py +16 -9
- ksadk/memory/__init__.py +61 -0
- ksadk/memory/adk/backends/base_ltm_backend.py +96 -1
- ksadk/memory/adk/backends/http_ltm_backend.py +14 -5
- ksadk/memory/adk/backends/inmemory_ltm_backend.py +136 -3
- ksadk/memory/adk/backends/sdk_ltm_backend.py +394 -5
- ksadk/memory/adk/backends/sqlite_ltm_backend.py +95 -0
- ksadk/memory/adk/long_term_memory.py +3 -2
- ksadk/memory/coordinator.py +461 -0
- ksadk/memory/events.py +202 -0
- ksadk/memory/extraction.py +228 -0
- ksadk/memory/ltm_backend_factory.py +16 -3
- ksadk/memory/models.py +316 -0
- ksadk/memory/policy.py +215 -0
- ksadk/memory/provider.py +47 -0
- ksadk/memory/provider_adapter.py +159 -0
- ksadk/memory/provider_resolver.py +71 -0
- ksadk/memory/providers/__init__.py +5 -0
- ksadk/memory/providers/local_sqlite.py +490 -0
- ksadk/memory/resolved_policy.py +145 -0
- ksadk/memory/service.py +198 -8
- ksadk/memory/tool.py +4 -0
- ksadk/model_proxy/bootstrap.py +16 -9
- ksadk/model_proxy/config.py +22 -1
- ksadk/model_proxy/detect.py +202 -9
- ksadk/model_proxy/namespace.py +67 -15
- ksadk/model_proxy/server.py +168 -6
- ksadk/model_proxy/transform.py +105 -3
- ksadk/observability/__init__.py +25 -0
- ksadk/observability/session_log.py +420 -0
- ksadk/observability/trajectory.py +105 -0
- ksadk/prompts/__init__.py +71 -0
- ksadk/prompts/compiler.py +215 -0
- ksadk/prompts/models.py +82 -0
- ksadk/prompts/projection.py +89 -0
- ksadk/prompts/resolved.py +137 -0
- ksadk/prompts/sources.py +233 -0
- ksadk/runners/_langgraph_runner_streams.py +822 -0
- ksadk/runners/adk_runner.py +14 -31
- ksadk/runners/base_runner.py +44 -3
- ksadk/runners/factory.py +3 -3
- ksadk/runners/langgraph_runner.py +252 -433
- ksadk/runners/utils/__init__.py +0 -10
- ksadk/runners/utils/loader.py +16 -0
- ksadk/runtime/__init__.py +67 -41
- ksadk/runtime/_runner_adapter/__init__.py +1 -0
- ksadk/runtime/_runner_adapter/stream_mapping.py +788 -0
- ksadk/runtime/adapter.py +199 -16
- ksadk/runtime/conversation_execution.py +687 -0
- ksadk/runtime/executor.py +392 -0
- ksadk/runtime/factory.py +342 -0
- ksadk/runtime/framework_adapters.py +6 -12
- ksadk/runtime/hosted_finalizer.py +268 -0
- ksadk/runtime/launch.py +61 -0
- ksadk/runtime/preprocessing.py +49 -14
- ksadk/runtime/runner_adapter.py +330 -391
- ksadk/runtime/runner_loading.py +36 -0
- ksadk/runtime/usage.py +33 -0
- ksadk/sandbox/backends/e2b.py +36 -3
- ksadk/server/__init__.py +39 -4
- ksadk/server/app.py +18 -492
- ksadk/server/composition.py +36 -2
- ksadk/server/factory.py +210 -149
- ksadk/server/routes/common.py +15 -46
- ksadk/server/routes/control.py +13 -9
- ksadk/server/routes/kernel_ingress.py +258 -0
- ksadk/server/routes/misc.py +10 -33
- ksadk/server/routes/models.py +14 -6
- ksadk/server/routes/openai_compat.py +129 -27
- ksadk/server/routes/projection.py +84 -16
- ksadk/server/routes/run.py +347 -460
- ksadk/server/routes/sessions.py +37 -40
- ksadk/server/routes/streaming.py +52 -7
- ksadk/server/routes/workspace.py +54 -21
- ksadk/server/static/assets/{ArtifactsPanel-Cjnqt-8W.js → ArtifactsPanel-DSU1sWD_.js} +1 -1
- ksadk/server/static/assets/{CodeBlock-BqyqZfuB.js → CodeBlock-DOH6MVcn.js} +4 -4
- ksadk/server/static/assets/{MathMessageMarkdown-BpH7jiFM.js → MathMessageMarkdown-BL8my1R2.js} +4 -4
- ksadk/server/static/assets/MathMessageMarkdown-BorAY7qD.css +1 -0
- ksadk/server/static/assets/MermaidBlock-Dz4IP-Tx.js +312 -0
- ksadk/server/static/assets/NativeTerminalPanel-DUrK0JpZ.js +1 -0
- ksadk/server/static/assets/abnfDiagram-VCTEODGH-g20pFzNV.js +1 -0
- ksadk/server/static/assets/arc-C4FzinUA.js +1 -0
- ksadk/server/static/assets/architecture-7GRP2DOG-DjKratdf.js +1 -0
- ksadk/server/static/assets/architectureDiagram-5GKGNRK7-DpIqL5h4.js +36 -0
- ksadk/server/static/assets/blockDiagram-NRAW4CY4-BjkljTNz.js +129 -0
- ksadk/server/static/assets/c4Diagram-UCG6FXSJ-Dk_ieq2X.js +38 -0
- ksadk/server/static/assets/channel-4cQHKtx1.js +1 -0
- ksadk/server/static/assets/chunk-2Q5K7J3B-DmgWkESh.js +1 -0
- ksadk/server/static/assets/{chunk-FMBD7UC4-BGhvzDYt.js → chunk-5VM5RSS4-BVHAchFb.js} +1 -1
- ksadk/server/static/assets/{chunk-ND2GUHAM-D98vPd-E.js → chunk-F27PBJKO-C-ipQzuS.js} +1 -1
- ksadk/server/static/assets/chunk-G27WJ6UU-C2EyJbIK.js +231 -0
- ksadk/server/static/assets/{chunk-4BX2VUAB-CsWIQRhc.js → chunk-JWPE2WC7-vYvVJb_M.js} +1 -1
- ksadk/server/static/assets/chunk-LCL6LL3I-BcI6ysPT.js +206 -0
- ksadk/server/static/assets/chunk-POPQ4Y6H-C030x_Z1.js +1 -0
- ksadk/server/static/assets/chunk-RHFEMEQ7-yyGpsz4n.js +168 -0
- ksadk/server/static/assets/chunk-SVP7TREG-BLTlmMU7.js +88 -0
- ksadk/server/static/assets/chunk-XXDRQBXY-C_32ArgP.js +1 -0
- ksadk/server/static/assets/classDiagram-DTDB5LWJ-DLFd9Xi0.js +1 -0
- ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-DLFd9Xi0.js +1 -0
- ksadk/server/static/assets/{cose-bilkent-S5V4N54A-CX3yotHq.js → cose-bilkent-JH36ORCC-9YQYwdl0.js} +1 -1
- ksadk/server/static/assets/cynefin-OW5HDTMX-DjEM48Qp.js +1 -0
- ksadk/server/static/assets/cynefinDiagram-5FMLGOSQ-ErLF5N13.js +62 -0
- ksadk/server/static/assets/cytoscape.esm-CyCl8rPi.js +321 -0
- ksadk/server/static/assets/dagre-3AP2YEHR-DFiQF-6f.js +4 -0
- ksadk/server/static/assets/dagre-BuhGnRI1.js +1 -0
- ksadk/server/static/assets/diagram-S7CK7UJ4-Bt1v8-GC.js +30 -0
- ksadk/server/static/assets/diagram-UQ7AKVKN-DSCxJdBK.js +41 -0
- ksadk/server/static/assets/diagram-VSXAHHWV-DHfYwp_9.js +3 -0
- ksadk/server/static/assets/diagram-VX7I27RA-DdzD-4Le.js +24 -0
- ksadk/server/static/assets/diagram-Z3DM3KII-Du-nAJ9F.js +24 -0
- ksadk/server/static/assets/{dist-D82mtD2s.js → dist-8hqcx0sU.js} +1 -1
- ksadk/server/static/assets/dist-B7seoj3d.js +1 -0
- ksadk/server/static/assets/{dist-DHn6nBzr.js → dist-BE7bu-DL.js} +1 -1
- ksadk/server/static/assets/{dist-eoW6tZXA.js → dist-BVDffZ0U.js} +1 -1
- ksadk/server/static/assets/{dist-C2xjE7cO.js → dist-BX8z72IC.js} +1 -1
- ksadk/server/static/assets/{dist-CgF3fj15.js → dist-Bf2M8m3N.js} +1 -1
- ksadk/server/static/assets/{dist-Bs-jQcRX.js → dist-BjU6y-A2.js} +1 -1
- ksadk/server/static/assets/{dist-Djgl2wVZ.js → dist-BytlxIDT.js} +1 -1
- ksadk/server/static/assets/{dist-CVQRZjPu.js → dist-CSh_DE14.js} +1 -1
- ksadk/server/static/assets/{dist-6CVKuTAe.js → dist-CXYYBw3_.js} +1 -1
- ksadk/server/static/assets/{dist-DlzCRy0S.js → dist-C_wsv-Qd.js} +1 -1
- ksadk/server/static/assets/{dist-DF06ORQo.js → dist-ClxGviKw.js} +1 -1
- ksadk/server/static/assets/{dist-Cf23NY4L.js → dist-CttYUqzS.js} +1 -1
- ksadk/server/static/assets/{dist-ivOya1LD.js → dist-DNp6rLRA.js} +1 -1
- ksadk/server/static/assets/{dist-BibcG1V9.js → dist-DUX-id_F.js} +1 -1
- ksadk/server/static/assets/{dist-BUHRxvDG.js → dist-DmldrHd_.js} +1 -1
- ksadk/server/static/assets/{dist-BZ9n9AjO.js → dist-DnfXs8Vn.js} +2 -2
- ksadk/server/static/assets/{dist-DqNnNFrw.js → dist-Dq9gLD7L.js} +1 -1
- ksadk/server/static/assets/{dist-CGcp2ex8.js → dist-W-TIVntx.js} +1 -1
- ksadk/server/static/assets/{dist-Cwt7koer.js → dist-dDdADKFA.js} +1 -1
- ksadk/server/static/assets/{dist-C7-3jInC.js → dist-dydu68Fl.js} +1 -1
- ksadk/server/static/assets/{dist-C99THtIA.js → dist-ngtN0DJB.js} +1 -1
- ksadk/server/static/assets/ebnfDiagram-PWID7BFC-Da9C9NO1.js +1 -0
- ksadk/server/static/assets/erDiagram-SSCWMZ5O-EAGqqR79.js +99 -0
- ksadk/server/static/assets/eventmodeling-NTZA5JFV-CMgMaJrC.js +1 -0
- ksadk/server/static/assets/flowDiagram-A5DVABFB-BBKL0x3P.js +1 -0
- ksadk/server/static/assets/ganttDiagram-EL5Y4UJY-DqJsKb59.js +292 -0
- ksadk/server/static/assets/gitGraph-4MIJSDKK-Dw63mrhw.js +1 -0
- ksadk/server/static/assets/gitGraphDiagram-WWUBYQGX-B6g4dtDi.js +106 -0
- ksadk/server/static/assets/index-8ipRcQ-M.js +240 -0
- ksadk/server/static/assets/index-ByFCqjlh.css +2 -0
- ksadk/server/static/assets/info-A6RAGUB7-B6iAblII.js +1 -0
- ksadk/server/static/assets/infoDiagram-RXCK75RN-Djm_nbd5.js +2 -0
- ksadk/server/static/assets/{ishikawaDiagram-YF4QCWOH-DLOHGvWw.js → ishikawaDiagram-5VMMS53U-DWya9SG2.js} +6 -6
- ksadk/server/static/assets/{journeyDiagram-JHISSGLW-BIzKeejT.js → journeyDiagram-EYS64GPL-DutxhSNI.js} +6 -6
- ksadk/server/static/assets/{kanban-definition-UN3LZRKU-BWHoFSw2.js → kanban-definition-3QL26DDD-DJdOF8Fm.js} +10 -10
- ksadk/server/static/assets/katex-vFWytM5c.js +257 -0
- ksadk/server/static/assets/{linear-CvMBw9cA.js → linear-BHjG8b-J.js} +1 -1
- ksadk/server/static/assets/mermaid-parser.core-KGSy4jWT.js +166 -0
- ksadk/server/static/assets/{mindmap-definition-RKZ34NQL-CSAQxEAe.js → mindmap-definition-FBJOCRG2-9-HC88D4.js} +29 -29
- ksadk/server/static/assets/packet-AYTQ26CC-BOYAipuq.js +1 -0
- ksadk/server/static/assets/pegDiagram-XKGWAZYB-DrEZd4fD.js +1 -0
- ksadk/server/static/assets/pie-WAS4IAKB-Ctq0Kbku.js +1 -0
- ksadk/server/static/assets/pieDiagram-E7YTZNPT-DpjqOFFp.js +39 -0
- ksadk/server/static/assets/{quadrantDiagram-W4KKPZXB-CxIR4JXI.js → quadrantDiagram-AXDQQJYC-BiNhgOXX.js} +6 -6
- ksadk/server/static/assets/radar-RG4KPBEZ-DN0-ul_0.js +1 -0
- ksadk/server/static/assets/railroad-74A4TZTK-C6cC_to0.js +1 -0
- ksadk/server/static/assets/railroad-abnf-HS5TGJTU-BimjIuRc.js +1 -0
- ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-CvY65ABq.js +1 -0
- ksadk/server/static/assets/railroad-peg-WCYAUIDC-D72Iq_Tv.js +1 -0
- ksadk/server/static/assets/railroadDiagram-O6MQD6OU-_Y3Ojg6G.js +1 -0
- ksadk/server/static/assets/requirementDiagram-EFPCY7ZU-DeCFdg9K.js +84 -0
- ksadk/server/static/assets/{sankeyDiagram-5OEKKPKP-DpGa6EAV.js → sankeyDiagram-P5KCCOFB-CPH75rhw.js} +7 -7
- ksadk/server/static/assets/{sequenceDiagram-3UESZ5HK-NTKNGGe5.js → sequenceDiagram-WJ2MYXX4-OEpQQdr4.js} +10 -10
- ksadk/server/static/assets/sizeCapture-X5ZJPWSS-heUErzhI.js +1 -0
- ksadk/server/static/assets/stateDiagram-HBIQ2CUA-DvA3jSMB.js +1 -0
- ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-BgQY03nz.js +1 -0
- ksadk/server/static/assets/swimlanes-XN3QIQJK-CR-dfN_t.js +1 -0
- ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-DLVw3q5Q.js +8 -0
- ksadk/server/static/assets/{timeline-definition-PNZ67QCA-jqoYs3jQ.js → timeline-definition-24CTP7MA-DAVJf1TX.js} +7 -7
- ksadk/server/static/assets/treeView-Q6P3EWNA-BMpO0wsB.js +1 -0
- ksadk/server/static/assets/treemap-WGGIJYW6-Et0aqzU3.js +1 -0
- ksadk/server/static/assets/vennDiagram-4TSXK5OY-DwM8eDkh.js +34 -0
- ksadk/server/static/assets/wardley-WFR3VGLG-CbY0mhpl.js +1 -0
- ksadk/server/static/assets/wardleyDiagram-VM6X3IG4-DZL-Zz2t.js +78 -0
- ksadk/server/static/assets/xychartDiagram-S5SC5T6Z-Dy6Yh_hu.js +7 -0
- ksadk/server/static/index.html +2 -2
- ksadk/sessions/__init__.py +26 -9
- ksadk/sessions/_local_service_sync.py +688 -0
- ksadk/sessions/_local_tables.py +21 -0
- ksadk/sessions/_postgres_schema.py +305 -0
- ksadk/sessions/_postgres_tables.py +15 -0
- ksadk/sessions/base.py +80 -1
- ksadk/sessions/in_memory.py +53 -2
- ksadk/sessions/local_service.py +63 -604
- ksadk/sessions/postgres_service.py +58 -148
- ksadk/sessions/resilient.py +35 -1
- ksadk/skills/runtime/backends/e2b.py +1 -1
- ksadk/skills/service_client.py +13 -3
- ksadk/studio/__init__.py +5 -0
- ksadk/studio/agent_avatar_assets.py +120 -0
- ksadk/studio/agent_lifecycle.py +51 -0
- ksadk/studio/api.py +1598 -0
- ksadk/studio/api_catalog_routes.py +324 -0
- ksadk/studio/api_contracts.py +286 -0
- ksadk/studio/api_helpers.py +132 -0
- ksadk/studio/api_memory_routes.py +82 -0
- ksadk/studio/authoring.py +749 -0
- ksadk/studio/authoring_coordinator.py +1017 -0
- ksadk/studio/builder.py +397 -0
- ksadk/studio/capabilities.py +368 -0
- ksadk/studio/cloud.py +2099 -0
- ksadk/studio/codex_agent_service.py +694 -0
- ksadk/studio/codex_authoring.py +469 -0
- ksadk/studio/codex_builder.py +437 -0
- ksadk/studio/codex_manifest.py +307 -0
- ksadk/studio/codex_run.py +395 -0
- ksadk/studio/compiler.py +190 -0
- ksadk/studio/contracts.py +755 -0
- ksadk/studio/errors.py +47 -0
- ksadk/studio/event_store.py +214 -0
- ksadk/studio/framework_run.py +342 -0
- ksadk/studio/hosted_kernel.py +317 -0
- ksadk/studio/identifiers.py +33 -0
- ksadk/studio/manifest_resolver.py +131 -0
- ksadk/studio/mcp_runtime.py +229 -0
- ksadk/studio/model_client.py +629 -0
- ksadk/studio/model_profile_service.py +214 -0
- ksadk/studio/operations.py +275 -0
- ksadk/studio/otel_trace.py +1060 -0
- ksadk/studio/pagination.py +182 -0
- ksadk/studio/pcm_memory.py +85 -0
- ksadk/studio/python_tool_inspection.py +183 -0
- ksadk/studio/repository.py +327 -0
- ksadk/studio/resource_catalog.py +1260 -0
- ksadk/studio/run_service.py +1133 -0
- ksadk/studio/runtime_catalog.py +74 -0
- ksadk/studio/runtime_source.py +365 -0
- ksadk/studio/service.py +2249 -0
- ksadk/studio/shared_web.py +1004 -0
- ksadk/studio/skill_discovery.py +628 -0
- ksadk/studio/static/assets/PrismRenderer-IYN-ffww.js +3 -0
- ksadk/studio/static/assets/index-BLpcdrgW.css +1 -0
- ksadk/studio/static/assets/index-CYekR2Xv.js +260 -0
- ksadk/studio/static/assets/react-vendor-BNmTiJ-I.js +9 -0
- ksadk/studio/static/assets/rolldown-runtime-hePW80VL.js +1 -0
- ksadk/studio/static/index.html +15 -0
- ksadk/studio/templates.py +722 -0
- ksadk/studio/validator.py +265 -0
- ksadk/studio/workspace.py +135 -0
- ksadk/tools/gateway.py +9 -0
- ksadk/toolsets/__init__.py +27 -1
- ksadk/toolsets/a2a.py +426 -0
- ksadk/tracing/__init__.py +19 -21
- ksadk/tracing/setup.py +317 -403
- ksadk/tracing/span_utils.py +0 -44
- ksadk/version.py +1 -1
- ksadk_runtime_common/memory_backend/registry.py +56 -56
- ksadk_runtime_common/schemas/runtime_event_v1.json +37 -0
- ksadk_runtime_common/schemas/runtime_event_v2.json +271 -0
- ksadk_runtime_common/workspace_files/router.py +8 -2
- agentengine_sdk_python-0.8.0.dist-info/RECORD +0 -578
- ksadk/a2a/card_builder.py +0 -64
- ksadk/a2a/client.py +0 -309
- ksadk/events/parser.py +0 -191
- ksadk/harness/runner.py +0 -211
- ksadk/runners/codex_runner.py +0 -132
- ksadk/runners/utils/langfuse.py +0 -230
- ksadk/server/static/assets/MathMessageMarkdown-DeYh8QPr.css +0 -1
- ksadk/server/static/assets/MermaidBlock-DWuxETaJ.js +0 -303
- ksadk/server/static/assets/NativeTerminalPanel-MDTopWMO.js +0 -1
- ksadk/server/static/assets/arc-CFKwSk_B.js +0 -1
- ksadk/server/static/assets/architecture-7EHR7CIX-CynqOWjZ.js +0 -1
- ksadk/server/static/assets/architectureDiagram-3BPJPVTR-Dej8jX8c.js +0 -36
- ksadk/server/static/assets/blockDiagram-GPEHLZMM-1F64jqvy.js +0 -132
- ksadk/server/static/assets/c4Diagram-AAUBKEIU-9q7AUAKb.js +0 -10
- ksadk/server/static/assets/channel-iUGv2N24.js +0 -1
- ksadk/server/static/assets/chunk-2J33WTMH-6qgwJm7Q.js +0 -1
- ksadk/server/static/assets/chunk-55IACEB6-BK8paA20.js +0 -1
- ksadk/server/static/assets/chunk-727SXJPM-B-JEhy7h.js +0 -206
- ksadk/server/static/assets/chunk-AQP2D5EJ-DYBvMHAa.js +0 -231
- ksadk/server/static/assets/chunk-QZHKN3VN-YQIEXeF6.js +0 -1
- ksadk/server/static/assets/classDiagram-4FO5ZUOK-CDAUuoXK.js +0 -1
- ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-CDAUuoXK.js +0 -1
- ksadk/server/static/assets/cytoscape.esm-DelgaX4f.js +0 -321
- ksadk/server/static/assets/dagre-BM42HDAG-C7TguAWo.js +0 -4
- ksadk/server/static/assets/dagre-Bx709z4p.js +0 -1
- ksadk/server/static/assets/diagram-2AECGRRQ-Dd17_kws.js +0 -43
- ksadk/server/static/assets/diagram-5GNKFQAL-DVIClIil.js +0 -10
- ksadk/server/static/assets/diagram-KO2AKTUF-Df_3gYQa.js +0 -3
- ksadk/server/static/assets/diagram-LMA3HP47-BhLk6ZtA.js +0 -24
- ksadk/server/static/assets/diagram-OG6HWLK6-D4GNGvuu.js +0 -24
- ksadk/server/static/assets/dist-DyvYLMW9.js +0 -1
- ksadk/server/static/assets/erDiagram-TEJ5UH35-CnfRcY2M.js +0 -85
- ksadk/server/static/assets/eventmodeling-FCH6USID-ChYO-ijM.js +0 -1
- ksadk/server/static/assets/flowDiagram-I6XJVG4X-DGaJjGNJ.js +0 -162
- ksadk/server/static/assets/ganttDiagram-6RSMTGT7-DpCoB2g9.js +0 -292
- ksadk/server/static/assets/gitGraph-WXDBUCRP-BN_0Fk-j.js +0 -1
- ksadk/server/static/assets/gitGraphDiagram-PVQCEYII-9IKVFBVT.js +0 -106
- ksadk/server/static/assets/graphlib-B8gBHxth.js +0 -1
- ksadk/server/static/assets/index-QSwCHuB8.js +0 -177
- ksadk/server/static/assets/index-jOPmTOZH.css +0 -2
- ksadk/server/static/assets/info-J43DQDTF-Cp6o3vId.js +0 -1
- ksadk/server/static/assets/infoDiagram-5YYISTIA-CYIIsb8y.js +0 -2
- ksadk/server/static/assets/katex-DATssjp1.js +0 -265
- ksadk/server/static/assets/mermaid-parser.core-mGAcEwcq.js +0 -161
- ksadk/server/static/assets/packet-YPE3B663-wQzct3cT.js +0 -1
- ksadk/server/static/assets/pie-LRSECV5Y-BgTQiv-9.js +0 -1
- ksadk/server/static/assets/pieDiagram-4H26LBE5-By-ra07M.js +0 -30
- ksadk/server/static/assets/radar-GUYGQ44K-BIq5fXsn.js +0 -1
- ksadk/server/static/assets/requirementDiagram-4Y6WPE33-DpW90iu3.js +0 -84
- ksadk/server/static/assets/stateDiagram-AJRCARHV-DGpd9yFG.js +0 -1
- ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-B3o579IQ.js +0 -1
- ksadk/server/static/assets/treeView-BLDUP644-Dqi-E0EM.js +0 -1
- ksadk/server/static/assets/treemap-LRROVOQU-ClQP9CJ9.js +0 -1
- ksadk/server/static/assets/vennDiagram-CIIHVFJN-l3Z7-wbP.js +0 -34
- ksadk/server/static/assets/wardley-L42UT6IY-8XLvnNIs.js +0 -1
- ksadk/server/static/assets/wardleyDiagram-YWT4CUSO-BR54GPmr.js +0 -78
- ksadk/server/static/assets/xychartDiagram-2RQKCTM6-SkiH8GsK.js +0 -7
- ksadk/tracing/exporters/langfuse_exporter.py +0 -460
- {agentengine_sdk_python-0.8.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/entry_points.txt +0 -0
- {agentengine_sdk_python-0.8.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/licenses/LICENSE +0 -0
- {agentengine_sdk_python-0.8.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/top_level.txt +0 -0
ksadk/studio/errors.py
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""Stable errors shared by the Studio service and HTTP API."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class StudioError(Exception):
|
|
9
|
+
"""A user-safe error with a stable machine-readable code."""
|
|
10
|
+
|
|
11
|
+
def __init__(
|
|
12
|
+
self,
|
|
13
|
+
code: str,
|
|
14
|
+
message: str,
|
|
15
|
+
*,
|
|
16
|
+
status_code: int = 400,
|
|
17
|
+
field: str | None = None,
|
|
18
|
+
details: dict[str, Any] | None = None,
|
|
19
|
+
) -> None:
|
|
20
|
+
super().__init__(message)
|
|
21
|
+
self.code = code
|
|
22
|
+
self.message = message
|
|
23
|
+
self.status_code = status_code
|
|
24
|
+
self.field = field
|
|
25
|
+
self.details = details or {}
|
|
26
|
+
|
|
27
|
+
def as_dict(self, *, request_id: str | None = None) -> dict[str, Any]:
|
|
28
|
+
payload: dict[str, Any] = {
|
|
29
|
+
"code": self.code,
|
|
30
|
+
"message": self.message,
|
|
31
|
+
}
|
|
32
|
+
if self.field:
|
|
33
|
+
payload["field"] = self.field
|
|
34
|
+
if self.details:
|
|
35
|
+
payload["details"] = self.details
|
|
36
|
+
if request_id:
|
|
37
|
+
payload["requestId"] = request_id
|
|
38
|
+
return {"error": payload}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def not_found(resource: str, resource_id: str) -> StudioError:
|
|
42
|
+
return StudioError(
|
|
43
|
+
f"{resource.upper()}_NOT_FOUND",
|
|
44
|
+
f"{resource} 不存在",
|
|
45
|
+
status_code=404,
|
|
46
|
+
details={"id": resource_id},
|
|
47
|
+
)
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
"""Persistent local Run record store and derived trace access."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import shutil
|
|
7
|
+
from datetime import datetime, timezone
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from pydantic import ValidationError
|
|
12
|
+
|
|
13
|
+
from ksadk.studio.contracts import RunEvent, RunRecord
|
|
14
|
+
from ksadk.studio.errors import StudioError, not_found
|
|
15
|
+
from ksadk.studio.otel_trace import OtlpTraceStore
|
|
16
|
+
from ksadk.studio.workspace import Workspace
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class RunEventStore:
|
|
20
|
+
def __init__(self, workspace: Workspace) -> None:
|
|
21
|
+
self.workspace = workspace
|
|
22
|
+
self.trace_store = OtlpTraceStore(workspace)
|
|
23
|
+
|
|
24
|
+
def _path(self, run_id: str) -> Path:
|
|
25
|
+
return self.workspace.resolve(Path(".agentkit/runs") / f"{run_id}.json")
|
|
26
|
+
|
|
27
|
+
def create(self, record: RunRecord) -> RunRecord:
|
|
28
|
+
path = self._path(record.id)
|
|
29
|
+
if path.exists():
|
|
30
|
+
raise StudioError("RUN_ALREADY_EXISTS", "Run 已存在", status_code=409)
|
|
31
|
+
self._write(record)
|
|
32
|
+
return record
|
|
33
|
+
|
|
34
|
+
def save(self, record: RunRecord) -> RunRecord:
|
|
35
|
+
_, events = self._read(record.id)
|
|
36
|
+
self._write(record, events or None)
|
|
37
|
+
return record
|
|
38
|
+
|
|
39
|
+
def append(self, run_id: str, event_type: str, data: dict) -> RunEvent:
|
|
40
|
+
"""Persist a Studio lifecycle RunEvent (run.created, memory.recall.projected, …).
|
|
41
|
+
|
|
42
|
+
These Studio-level events (as opposed to RuntimeEvents) are durably
|
|
43
|
+
stored in the run JSON so the Studio events timeline survives restarts.
|
|
44
|
+
Runs that never call ``append`` keep ``set(run_payload) == {"record"}``.
|
|
45
|
+
"""
|
|
46
|
+
record, events = self._read(run_id)
|
|
47
|
+
event = RunEvent(
|
|
48
|
+
id=len(events) + 1,
|
|
49
|
+
run_id=run_id,
|
|
50
|
+
type=event_type,
|
|
51
|
+
data=data,
|
|
52
|
+
)
|
|
53
|
+
events.append(event)
|
|
54
|
+
self._write(record, events)
|
|
55
|
+
return event
|
|
56
|
+
|
|
57
|
+
def events(self, run_id: str, *, after: int = 0) -> list[RunEvent]:
|
|
58
|
+
_, events = self._read(run_id)
|
|
59
|
+
return [event for event in events if event.id > after]
|
|
60
|
+
|
|
61
|
+
def get(self, run_id: str) -> RunRecord:
|
|
62
|
+
record, _ = self._read(run_id)
|
|
63
|
+
return record
|
|
64
|
+
|
|
65
|
+
def list_runs(
|
|
66
|
+
self,
|
|
67
|
+
*,
|
|
68
|
+
session_id: str | None = None,
|
|
69
|
+
agent_id: str | None = None,
|
|
70
|
+
) -> list[RunRecord]:
|
|
71
|
+
records: list[RunRecord] = []
|
|
72
|
+
directory = self.workspace.resolve(".agentkit/runs")
|
|
73
|
+
for path in sorted(directory.glob("run_*.json")):
|
|
74
|
+
try:
|
|
75
|
+
payload = json.loads(path.read_text(encoding="utf-8"))
|
|
76
|
+
record = RunRecord.model_validate(payload["record"])
|
|
77
|
+
except (OSError, ValueError, KeyError, ValidationError):
|
|
78
|
+
continue
|
|
79
|
+
if session_id and record.session_id != session_id:
|
|
80
|
+
continue
|
|
81
|
+
if agent_id and record.agent_id != agent_id:
|
|
82
|
+
continue
|
|
83
|
+
records.append(record)
|
|
84
|
+
records.sort(
|
|
85
|
+
key=lambda item: (
|
|
86
|
+
item.started_at or item.completed_at or datetime.min.replace(tzinfo=timezone.utc)
|
|
87
|
+
),
|
|
88
|
+
reverse=False,
|
|
89
|
+
)
|
|
90
|
+
return records
|
|
91
|
+
|
|
92
|
+
def delete_session(self, session_id: str) -> int:
|
|
93
|
+
"""Delete every persisted run that belongs to one local chat session."""
|
|
94
|
+
|
|
95
|
+
deleted = 0
|
|
96
|
+
for record in self.list_runs(session_id=session_id):
|
|
97
|
+
path = self._path(record.id)
|
|
98
|
+
if path.is_file():
|
|
99
|
+
self.trace_store.delete(record.trace_id, purge=True)
|
|
100
|
+
path.unlink()
|
|
101
|
+
deleted += 1
|
|
102
|
+
return deleted
|
|
103
|
+
|
|
104
|
+
def delete_agent(
|
|
105
|
+
self,
|
|
106
|
+
agent_id: str,
|
|
107
|
+
*,
|
|
108
|
+
purge: bool,
|
|
109
|
+
trash_directory: Path | None = None,
|
|
110
|
+
) -> int:
|
|
111
|
+
"""Remove the persisted Runs and Trace events owned by one Agent."""
|
|
112
|
+
|
|
113
|
+
deleted = 0
|
|
114
|
+
for record in self.list_runs(agent_id=agent_id):
|
|
115
|
+
path = self._path(record.id)
|
|
116
|
+
if not path.is_file():
|
|
117
|
+
continue
|
|
118
|
+
if purge:
|
|
119
|
+
self.trace_store.delete(record.trace_id, purge=True)
|
|
120
|
+
path.unlink()
|
|
121
|
+
else:
|
|
122
|
+
if trash_directory is None:
|
|
123
|
+
raise ValueError("recoverable deletion requires a trash directory")
|
|
124
|
+
destination = self.workspace.resolve(trash_directory / "runs" / path.name)
|
|
125
|
+
destination.parent.mkdir(parents=True, exist_ok=True)
|
|
126
|
+
self.trace_store.delete(
|
|
127
|
+
record.trace_id,
|
|
128
|
+
purge=False,
|
|
129
|
+
trash_directory=trash_directory,
|
|
130
|
+
)
|
|
131
|
+
shutil.move(str(path), str(destination))
|
|
132
|
+
deleted += 1
|
|
133
|
+
return deleted
|
|
134
|
+
|
|
135
|
+
def trace(self, trace_id: str) -> dict:
|
|
136
|
+
return self.trace_store.get_trace_view(trace_id)
|
|
137
|
+
|
|
138
|
+
def trace_otlp(self, trace_id: str) -> dict:
|
|
139
|
+
return self.trace_store.get_otlp(trace_id)
|
|
140
|
+
|
|
141
|
+
def list_traces(
|
|
142
|
+
self,
|
|
143
|
+
*,
|
|
144
|
+
agent_id: str | None = None,
|
|
145
|
+
status: str | None = None,
|
|
146
|
+
limit: int = 200,
|
|
147
|
+
) -> list[dict]:
|
|
148
|
+
return self.trace_store.list_trace_summaries(
|
|
149
|
+
agent_id=agent_id,
|
|
150
|
+
status=status,
|
|
151
|
+
limit=limit,
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
def list_traces_page(
|
|
155
|
+
self,
|
|
156
|
+
*,
|
|
157
|
+
agent_id: str | None = None,
|
|
158
|
+
status: str | None = None,
|
|
159
|
+
query: str = "",
|
|
160
|
+
limit: int = 50,
|
|
161
|
+
cursor: str | None = None,
|
|
162
|
+
sort: str = "startedAt:desc",
|
|
163
|
+
) -> dict:
|
|
164
|
+
return self.trace_store.paginate_trace_summaries(
|
|
165
|
+
agent_id=agent_id,
|
|
166
|
+
status=status,
|
|
167
|
+
query=query,
|
|
168
|
+
limit=limit,
|
|
169
|
+
cursor=cursor,
|
|
170
|
+
sort=sort,
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
def trace_overview(
|
|
174
|
+
self,
|
|
175
|
+
*,
|
|
176
|
+
range_name: str = "24h",
|
|
177
|
+
agent_id: str | None = None,
|
|
178
|
+
status: str | None = None,
|
|
179
|
+
) -> dict:
|
|
180
|
+
return self.trace_store.trace_overview(
|
|
181
|
+
range_name=range_name,
|
|
182
|
+
agent_id=agent_id,
|
|
183
|
+
status=status,
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
def _read(self, run_id: str) -> tuple[RunRecord, list[RunEvent]]:
|
|
187
|
+
path = self._path(run_id)
|
|
188
|
+
if not path.is_file():
|
|
189
|
+
raise not_found("run", run_id)
|
|
190
|
+
try:
|
|
191
|
+
payload = json.loads(path.read_text(encoding="utf-8"))
|
|
192
|
+
record = RunRecord.model_validate(payload["record"])
|
|
193
|
+
events = [RunEvent.model_validate(item) for item in payload.get("events", [])]
|
|
194
|
+
return record, events
|
|
195
|
+
except (OSError, ValueError, KeyError, ValidationError) as exc:
|
|
196
|
+
raise StudioError(
|
|
197
|
+
"RUN_RECORD_INVALID",
|
|
198
|
+
"Run 记录损坏",
|
|
199
|
+
status_code=500,
|
|
200
|
+
details={"id": run_id},
|
|
201
|
+
) from exc
|
|
202
|
+
|
|
203
|
+
def _write(self, record: RunRecord, events: list[RunEvent] | None = None) -> None:
|
|
204
|
+
payload: dict[str, Any] = {
|
|
205
|
+
"record": record.model_dump(by_alias=True, exclude_none=True, mode="json")
|
|
206
|
+
}
|
|
207
|
+
if events is not None:
|
|
208
|
+
payload["events"] = [
|
|
209
|
+
event.model_dump(by_alias=True, exclude_none=True, mode="json") for event in events
|
|
210
|
+
]
|
|
211
|
+
self.workspace.atomic_write_text(
|
|
212
|
+
self._path(record.id),
|
|
213
|
+
json.dumps(payload, ensure_ascii=False, sort_keys=True, indent=2) + "\n",
|
|
214
|
+
)
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
"""Resolve immutable ADK/LangGraph Studio builds into RuntimeLaunchContext."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import hashlib
|
|
6
|
+
import json
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from ksadk.detection.detector import FrameworkDetector
|
|
11
|
+
from ksadk.runtime import RuntimeLaunchContext
|
|
12
|
+
from ksadk.studio.capabilities import compute_bundle_digest
|
|
13
|
+
from ksadk.studio.contracts import BundleManifest
|
|
14
|
+
from ksadk.studio.errors import StudioError
|
|
15
|
+
from ksadk.studio.repository import BuildRepository
|
|
16
|
+
from ksadk.studio.run_service import StudioRunSpec
|
|
17
|
+
from ksadk.studio.workspace import Workspace
|
|
18
|
+
from ksadk.tools.gateway import normalize_tool_approval_mode
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _resolved_prompt_ownership(resolved: Any) -> str:
|
|
22
|
+
"""从 resolved-agent-spec.json 的 context 块读 prompt_ownership。
|
|
23
|
+
|
|
24
|
+
resolved spec 由 ContractModel 以 ``by_alias=True`` 序列化,alias_generator 为
|
|
25
|
+
camelCase,故字段名为 ``promptOwnership``;``populate_by_name`` 仅作用于输入,JSON
|
|
26
|
+
输出仍为 alias。此处 camelCase 与 snake 两种写法都查,稳妥兼容。非 dict / 缺失时
|
|
27
|
+
返回空串(== framework 默认,不接管 Runner 输入)。
|
|
28
|
+
"""
|
|
29
|
+
if not isinstance(resolved, dict):
|
|
30
|
+
return ""
|
|
31
|
+
context = resolved.get("context")
|
|
32
|
+
if not isinstance(context, dict):
|
|
33
|
+
return ""
|
|
34
|
+
return str(
|
|
35
|
+
context.get("promptOwnership")
|
|
36
|
+
or context.get("prompt_ownership")
|
|
37
|
+
or context.get("ownership")
|
|
38
|
+
or ""
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _resolved_context_engine_rollout(resolved: Any) -> str:
|
|
43
|
+
"""读取 AgentVersion 固化的 Context Engine rollout。"""
|
|
44
|
+
if not isinstance(resolved, dict):
|
|
45
|
+
return ""
|
|
46
|
+
context = resolved.get("context")
|
|
47
|
+
if not isinstance(context, dict):
|
|
48
|
+
return ""
|
|
49
|
+
rollout = context.get("rollout")
|
|
50
|
+
if not isinstance(rollout, dict):
|
|
51
|
+
return ""
|
|
52
|
+
return str(rollout.get("contextEngine") or rollout.get("context_engine") or "")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _resolved_memory_recall_enabled(resolved: Any) -> bool | None:
|
|
56
|
+
"""读取 AgentVersion 的 Memory 召回开关;缺失时保留旧环境策略。"""
|
|
57
|
+
if not isinstance(resolved, dict):
|
|
58
|
+
return None
|
|
59
|
+
memory = resolved.get("memory")
|
|
60
|
+
if not isinstance(memory, dict) or "enabled" not in memory:
|
|
61
|
+
return None
|
|
62
|
+
enabled = bool(memory.get("enabled"))
|
|
63
|
+
recall = memory.get("recall")
|
|
64
|
+
if isinstance(recall, dict) and "enabled" in recall:
|
|
65
|
+
enabled = enabled and bool(recall.get("enabled"))
|
|
66
|
+
context = resolved.get("context")
|
|
67
|
+
contributors = context.get("contributors") if isinstance(context, dict) else None
|
|
68
|
+
if isinstance(contributors, dict):
|
|
69
|
+
explicit = contributors.get("memoryRecall", contributors.get("memory_recall"))
|
|
70
|
+
if explicit is not None:
|
|
71
|
+
enabled = enabled and bool(explicit)
|
|
72
|
+
return enabled
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _resolved_memory_write_rollout(resolved: Any) -> str:
|
|
76
|
+
"""读取 AgentVersion 固化的 Memory 写入 rollout。"""
|
|
77
|
+
if not isinstance(resolved, dict):
|
|
78
|
+
return ""
|
|
79
|
+
context = resolved.get("context")
|
|
80
|
+
if not isinstance(context, dict):
|
|
81
|
+
return ""
|
|
82
|
+
rollout = context.get("rollout")
|
|
83
|
+
if not isinstance(rollout, dict):
|
|
84
|
+
return ""
|
|
85
|
+
return str(rollout.get("memoryWrite") or rollout.get("memory_write") or "")
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class FrameworkRunSpecResolver:
|
|
89
|
+
# manifest.json 是 bundle 自身的描述文件,不进入 manifest.files 清单
|
|
90
|
+
# (builder 在扫描文件列表之后才写它),校验时排除。checksums.txt 在本仓
|
|
91
|
+
# bundle 格式中是 manifest 声明的普通成员,参与校验。
|
|
92
|
+
_BUNDLE_META_FILES = frozenset({"manifest.json"})
|
|
93
|
+
|
|
94
|
+
def __init__(
|
|
95
|
+
self,
|
|
96
|
+
workspace: Workspace,
|
|
97
|
+
*,
|
|
98
|
+
build_repository: BuildRepository | None = None,
|
|
99
|
+
) -> None:
|
|
100
|
+
self.workspace = workspace
|
|
101
|
+
self.builds = build_repository or BuildRepository(workspace)
|
|
102
|
+
|
|
103
|
+
def resolve(
|
|
104
|
+
self,
|
|
105
|
+
build_id: str,
|
|
106
|
+
*,
|
|
107
|
+
model: str | None = None,
|
|
108
|
+
approval_mode: str | None = None,
|
|
109
|
+
) -> StudioRunSpec:
|
|
110
|
+
build = self.builds.get(build_id)
|
|
111
|
+
runtime_type = build.runtime_type.strip().lower()
|
|
112
|
+
if runtime_type not in {"adk", "langgraph"}:
|
|
113
|
+
raise StudioError(
|
|
114
|
+
"BUILD_RUNTIME_UNSUPPORTED",
|
|
115
|
+
"Build 没有可由 RuntimeAdapter 启动的 ADK/LangGraph Runtime",
|
|
116
|
+
status_code=422,
|
|
117
|
+
details={"buildId": build_id, "runtimeType": runtime_type},
|
|
118
|
+
)
|
|
119
|
+
if not build.artifact_path:
|
|
120
|
+
raise StudioError("BUILD_NOT_READY", "Build 尚未生成制品", status_code=409)
|
|
121
|
+
artifact_root = self.workspace.resolve(build.artifact_path, must_exist=True).parent
|
|
122
|
+
bundle_root = artifact_root / "agent-bundle"
|
|
123
|
+
self._verify_bundle_integrity(
|
|
124
|
+
bundle_root, expected_bundle_digest=build.bundle_digest
|
|
125
|
+
)
|
|
126
|
+
project_dir = bundle_root / "runtime"
|
|
127
|
+
if not project_dir.is_dir():
|
|
128
|
+
raise StudioError(
|
|
129
|
+
"BUILD_RUNTIME_SOURCE_MISSING",
|
|
130
|
+
"Build 缺少不可变 Runtime 源码快照",
|
|
131
|
+
status_code=500,
|
|
132
|
+
)
|
|
133
|
+
detection = FrameworkDetector(str(project_dir)).detect()
|
|
134
|
+
if not detection.is_valid or detection.type.value != runtime_type:
|
|
135
|
+
raise StudioError(
|
|
136
|
+
"BUILD_RUNTIME_DETECTION_MISMATCH",
|
|
137
|
+
"Build 中的 Runtime 源码与 Runtime Lock 不一致",
|
|
138
|
+
status_code=422,
|
|
139
|
+
details={
|
|
140
|
+
"expected": runtime_type,
|
|
141
|
+
"detected": detection.type.value,
|
|
142
|
+
},
|
|
143
|
+
)
|
|
144
|
+
selected_model = self._select_model(build.runtime_lock, model)
|
|
145
|
+
resolved_path = bundle_root / "resolved-agent-spec.json"
|
|
146
|
+
resolved = json.loads(resolved_path.read_text(encoding="utf-8"))
|
|
147
|
+
instructions = resolved.get("instructions") if isinstance(resolved, dict) else {}
|
|
148
|
+
request_config = {
|
|
149
|
+
"base_instructions": str((instructions or {}).get("system") or ""),
|
|
150
|
+
# Preserve system/task as separate PCM sources while keeping the
|
|
151
|
+
# framework runner's existing base_instructions projection.
|
|
152
|
+
"agent_system": str((instructions or {}).get("system") or ""),
|
|
153
|
+
"agent_task": str((instructions or {}).get("task") or ""),
|
|
154
|
+
**(
|
|
155
|
+
{"prompt_integration_mode": "ksadk_hosted"}
|
|
156
|
+
if _resolved_prompt_ownership(resolved) == "ksadk"
|
|
157
|
+
else {}
|
|
158
|
+
),
|
|
159
|
+
"context_engine_rollout": _resolved_context_engine_rollout(resolved),
|
|
160
|
+
"memory_recall_enabled": _resolved_memory_recall_enabled(resolved),
|
|
161
|
+
"memory_write_rollout": _resolved_memory_write_rollout(resolved),
|
|
162
|
+
"memory_enabled": _resolved_memory_enabled(resolved),
|
|
163
|
+
"memory_write_mode": _resolved_memory_write_mode(resolved),
|
|
164
|
+
"flush_before_compaction": _resolved_memory_flush_before_compaction(resolved),
|
|
165
|
+
"provider_ref": _resolved_memory_provider_ref(resolved),
|
|
166
|
+
"entry_point": detection.entry_point,
|
|
167
|
+
"agent_variable": detection.agent_variable,
|
|
168
|
+
}
|
|
169
|
+
# AgentVersion 的 ContextSpec 预算传到 Planner(方案 §8.2)
|
|
170
|
+
context_spec = resolved.get("context") if isinstance(resolved, dict) else {}
|
|
171
|
+
if isinstance(context_spec, dict):
|
|
172
|
+
max_input = context_spec.get("maxInputTokens") or context_spec.get("max_input_tokens")
|
|
173
|
+
reserve_output = context_spec.get("reserveOutputTokens") or context_spec.get(
|
|
174
|
+
"reserve_output_tokens"
|
|
175
|
+
)
|
|
176
|
+
if max_input is not None:
|
|
177
|
+
request_config["max_input_tokens"] = int(max_input)
|
|
178
|
+
if reserve_output is not None:
|
|
179
|
+
request_config["reserve_output_tokens"] = int(reserve_output)
|
|
180
|
+
if approval_mode:
|
|
181
|
+
request_config["tool_approval_mode"] = normalize_tool_approval_mode(approval_mode)
|
|
182
|
+
return StudioRunSpec(
|
|
183
|
+
launch_context=RuntimeLaunchContext(
|
|
184
|
+
runtime_type=runtime_type,
|
|
185
|
+
project_dir=project_dir,
|
|
186
|
+
detection=detection,
|
|
187
|
+
config=dict(detection.raw_config or {}),
|
|
188
|
+
),
|
|
189
|
+
build_id=build.id,
|
|
190
|
+
agent_id=build.agent_id,
|
|
191
|
+
model=selected_model,
|
|
192
|
+
request_config=request_config,
|
|
193
|
+
manifest_sha256=build.resolved_digest,
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
@staticmethod
|
|
197
|
+
def _select_model(runtime_lock: dict, requested: str | None) -> str:
|
|
198
|
+
allowed = [str(value) for value in runtime_lock.get("models") or [] if str(value)]
|
|
199
|
+
default = str(runtime_lock.get("model") or "").strip()
|
|
200
|
+
if default and default not in allowed:
|
|
201
|
+
allowed.insert(0, default)
|
|
202
|
+
selected = str(requested or default).strip()
|
|
203
|
+
if not selected:
|
|
204
|
+
raise StudioError(
|
|
205
|
+
"AGENT_MODEL_REQUIRED",
|
|
206
|
+
"Build 没有绑定可运行模型",
|
|
207
|
+
status_code=422,
|
|
208
|
+
)
|
|
209
|
+
if allowed and selected not in allowed:
|
|
210
|
+
raise StudioError(
|
|
211
|
+
"MODEL_NOT_BOUND",
|
|
212
|
+
"请求模型未绑定到当前 Agent Build",
|
|
213
|
+
status_code=422,
|
|
214
|
+
details={"model": selected, "allowedModels": allowed},
|
|
215
|
+
)
|
|
216
|
+
return selected
|
|
217
|
+
|
|
218
|
+
def _verify_bundle_integrity(
|
|
219
|
+
self,
|
|
220
|
+
bundle_dir: Path,
|
|
221
|
+
*,
|
|
222
|
+
expected_bundle_digest: str = "",
|
|
223
|
+
) -> None:
|
|
224
|
+
"""加载前校验 bundle 未被篡改:manifest 自身摘要、与 Build 记录一致、
|
|
225
|
+
文件清单无增删、每个文件 sha256/size 匹配。"""
|
|
226
|
+
try:
|
|
227
|
+
manifest = BundleManifest.model_validate_json(
|
|
228
|
+
(bundle_dir / "manifest.json").read_text(encoding="utf-8")
|
|
229
|
+
)
|
|
230
|
+
except (OSError, ValueError) as exc:
|
|
231
|
+
raise StudioError(
|
|
232
|
+
"BUILD_ARTIFACT_INVALID",
|
|
233
|
+
"Build 缺少有效的 Bundle Manifest",
|
|
234
|
+
status_code=500,
|
|
235
|
+
) from exc
|
|
236
|
+
if manifest.bundle_digest != compute_bundle_digest(manifest):
|
|
237
|
+
raise StudioError(
|
|
238
|
+
"BUILD_ARTIFACT_INVALID",
|
|
239
|
+
"Bundle Manifest 摘要不匹配,Bundle 可能已被篡改",
|
|
240
|
+
status_code=500,
|
|
241
|
+
details={"bundleDigest": manifest.bundle_digest},
|
|
242
|
+
)
|
|
243
|
+
if expected_bundle_digest and manifest.bundle_digest != expected_bundle_digest:
|
|
244
|
+
raise StudioError(
|
|
245
|
+
"BUILD_ARTIFACT_INVALID",
|
|
246
|
+
"Bundle 与 Build 记录的摘要不一致,Bundle 可能已被篡改",
|
|
247
|
+
status_code=500,
|
|
248
|
+
details={
|
|
249
|
+
"expected": expected_bundle_digest,
|
|
250
|
+
"actual": manifest.bundle_digest,
|
|
251
|
+
},
|
|
252
|
+
)
|
|
253
|
+
declared = {entry.path for entry in manifest.files}
|
|
254
|
+
actual: dict[str, Path] = {}
|
|
255
|
+
for path in bundle_dir.rglob("*"):
|
|
256
|
+
if not path.is_file():
|
|
257
|
+
continue
|
|
258
|
+
relative = path.relative_to(bundle_dir).as_posix()
|
|
259
|
+
if relative in self._BUNDLE_META_FILES:
|
|
260
|
+
continue
|
|
261
|
+
actual[relative] = path
|
|
262
|
+
extra = sorted(set(actual) - declared)
|
|
263
|
+
if extra:
|
|
264
|
+
raise StudioError(
|
|
265
|
+
"BUILD_ARTIFACT_INVALID",
|
|
266
|
+
"Bundle 含未在 Manifest 中声明的文件",
|
|
267
|
+
status_code=500,
|
|
268
|
+
details={"extraFiles": extra},
|
|
269
|
+
)
|
|
270
|
+
for entry in manifest.files:
|
|
271
|
+
file_path = actual.get(entry.path)
|
|
272
|
+
if file_path is None:
|
|
273
|
+
raise StudioError(
|
|
274
|
+
"BUILD_ARTIFACT_INVALID",
|
|
275
|
+
"Bundle 缺少 Manifest 声明的文件",
|
|
276
|
+
status_code=500,
|
|
277
|
+
details={"missingFile": entry.path},
|
|
278
|
+
)
|
|
279
|
+
content = file_path.read_bytes()
|
|
280
|
+
actual_sha = f"sha256:{hashlib.sha256(content).hexdigest()}"
|
|
281
|
+
if actual_sha != entry.sha256:
|
|
282
|
+
raise StudioError(
|
|
283
|
+
"BUILD_ARTIFACT_INVALID",
|
|
284
|
+
"Bundle 文件摘要不匹配",
|
|
285
|
+
status_code=500,
|
|
286
|
+
details={
|
|
287
|
+
"path": entry.path,
|
|
288
|
+
"expected": entry.sha256,
|
|
289
|
+
"actual": actual_sha,
|
|
290
|
+
},
|
|
291
|
+
)
|
|
292
|
+
if len(content) != entry.size:
|
|
293
|
+
raise StudioError(
|
|
294
|
+
"BUILD_ARTIFACT_INVALID",
|
|
295
|
+
"Bundle 文件大小不匹配",
|
|
296
|
+
status_code=500,
|
|
297
|
+
details={
|
|
298
|
+
"path": entry.path,
|
|
299
|
+
"expected": entry.size,
|
|
300
|
+
"actual": len(content),
|
|
301
|
+
},
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
__all__ = ["FrameworkRunSpecResolver"]
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
def _resolved_memory_enabled(resolved: Any) -> bool:
|
|
309
|
+
memory = resolved.get("memory") if isinstance(resolved, dict) else {}
|
|
310
|
+
return bool(memory.get("enabled", False)) if isinstance(memory, dict) else False
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
memory = resolved.get("memory") if isinstance(resolved, dict) else {}
|
|
314
|
+
if not isinstance(memory, dict) or not memory.get("enabled", False):
|
|
315
|
+
return False
|
|
316
|
+
recall = memory.get("recall", {})
|
|
317
|
+
return bool(recall.get("enabled", True)) if isinstance(recall, dict) else True
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
def _resolved_memory_write_mode(resolved: Any) -> str:
|
|
321
|
+
memory = resolved.get("memory") if isinstance(resolved, dict) else {}
|
|
322
|
+
write = memory.get("write", {}) if isinstance(memory, dict) else {}
|
|
323
|
+
return (
|
|
324
|
+
str(write.get("mode", "candidate") or "candidate")
|
|
325
|
+
if isinstance(write, dict)
|
|
326
|
+
else "candidate"
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
def _resolved_memory_flush_before_compaction(resolved: Any) -> bool:
|
|
331
|
+
memory = resolved.get("memory") if isinstance(resolved, dict) else {}
|
|
332
|
+
write = memory.get("write", {}) if isinstance(memory, dict) else {}
|
|
333
|
+
return bool(write.get("flushBeforeCompaction", True)) if isinstance(write, dict) else True
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
def _resolved_memory_provider_ref(resolved: Any) -> str:
|
|
337
|
+
memory = resolved.get("memory") if isinstance(resolved, dict) else {}
|
|
338
|
+
return (
|
|
339
|
+
str(memory.get("providerRef", "local-default") or "local-default")
|
|
340
|
+
if isinstance(memory, dict)
|
|
341
|
+
else "local-default"
|
|
342
|
+
)
|