agentengine-sdk-python 0.8.2__py3-none-any.whl → 0.8.3__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.2.dist-info → agentengine_sdk_python-0.8.3.dist-info}/METADATA +18 -25
- {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.3.dist-info}/RECORD +224 -169
- ksadk/_build_provenance.json +1 -0
- ksadk/agui/_agent_helpers.py +4 -0
- ksadk/api/client.py +3 -0
- ksadk/builders/managed_runtime_builder.py +3 -0
- ksadk/cli/__init__.py +6 -0
- ksadk/cli/cmd_plugin.py +657 -0
- ksadk/codex/runtime.py +50 -8
- ksadk/configs/env_registry.py +31 -3
- ksadk/configs/settings.py +9 -0
- ksadk/context_engine/contributors.py +73 -8
- ksadk/conversations/__init__.py +19 -0
- ksadk/conversations/context.py +104 -24
- ksadk/conversations/contracts.py +266 -0
- ksadk/conversations/message_projection.py +19 -1
- ksadk/conversations/projector.py +616 -0
- ksadk/conversations/reducer.py +98 -0
- ksadk/events/_v1_compat/projection.py +2 -0
- ksadk/events/adapters/codex.py +190 -0
- ksadk/harness/__init__.py +45 -35
- ksadk/harness/runtime.py +60 -1
- ksadk/kernel/contract_fingerprints.py +5 -4
- ksadk/kernel/contracts.py +8 -0
- ksadk/kernel/control.py +1 -0
- ksadk/kernel/ingress.py +21 -0
- ksadk/kernel/memory_store.py +1 -0
- ksadk/kernel/postgres_store.py +1 -0
- ksadk/kernel/sqlite_store.py +1 -0
- ksadk/kernel/worker.py +11 -0
- ksadk/memory/providers/local_sqlite.py +7 -0
- ksadk/plugins/__init__.py +167 -0
- ksadk/plugins/bridges/__init__.py +45 -0
- ksadk/plugins/bridges/codex.py +552 -0
- ksadk/plugins/bridges/dsh.py +1116 -0
- ksadk/plugins/builtins.py +747 -0
- ksadk/plugins/bundle.py +246 -0
- ksadk/plugins/bundle_security.py +167 -0
- ksadk/plugins/composition.py +529 -0
- ksadk/plugins/context_contributor.py +437 -0
- ksadk/plugins/contracts.py +451 -0
- ksadk/plugins/dsh_toolchain.py +935 -0
- ksadk/plugins/ecosystem_bridge.py +1105 -0
- ksadk/plugins/ecosystem_probe.py +191 -0
- ksadk/plugins/host.py +724 -0
- ksadk/plugins/providers/__init__.py +85 -0
- ksadk/plugins/providers/bundles/ksadk-codex/cordis.patch.yml +3 -0
- ksadk/plugins/providers/bundles/ksadk-codex/index.mjs +18 -0
- ksadk/plugins/providers/bundles/ksadk-codex/package.json +19 -0
- ksadk/plugins/providers/bundles/ksadk-harness/cordis.patch.yml +3 -0
- ksadk/plugins/providers/bundles/ksadk-harness/index.mjs +19 -0
- ksadk/plugins/providers/bundles/ksadk-harness/package.json +19 -0
- ksadk/plugins/providers/codex.py +722 -0
- ksadk/plugins/providers/codex_dsh.py +83 -0
- ksadk/plugins/providers/dsh.py +951 -0
- ksadk/plugins/providers/dsh_descriptor_host.py +226 -0
- ksadk/plugins/providers/harness.py +627 -0
- ksadk/plugins/providers/harness_dsh.py +91 -0
- ksadk/plugins/providers/legacy.py +215 -0
- ksadk/plugins/providers/legacy_catalog.py +100 -0
- ksadk/plugins/providers/shipped_dsh.py +370 -0
- ksadk/plugins/resolver.py +331 -0
- ksadk/plugins/subagent_providers/__init__.py +12 -0
- ksadk/plugins/subagent_providers/codex.py +443 -0
- ksadk/plugins/subagents.py +333 -0
- ksadk/runtime/_runner_adapter/stream_mapping.py +51 -42
- ksadk/runtime/adapter.py +1 -0
- ksadk/runtime/factory.py +76 -2
- ksadk/runtime/framework_adapters.py +18 -0
- ksadk/runtime/runner_adapter.py +5 -0
- ksadk/sandbox/__init__.py +2 -1
- ksadk/sandbox/factory.py +72 -0
- ksadk/scheduler/__init__.py +18 -0
- ksadk/scheduler/calendar.py +102 -0
- ksadk/scheduler/contracts.py +254 -0
- ksadk/scheduler/dispatcher.py +129 -0
- ksadk/scheduler/engine.py +416 -0
- ksadk/scheduler/sqlite_store.py +563 -0
- ksadk/server/static/assets/{ArtifactsPanel-DSU1sWD_.js → ArtifactsPanel-10GPXIJ6.js} +1 -1
- ksadk/server/static/assets/{CodeBlock-DOH6MVcn.js → CodeBlock-BXk1l-G1.js} +1 -1
- ksadk/server/static/assets/{MathMessageMarkdown-BL8my1R2.js → MathMessageMarkdown-D9uB55Oh.js} +1 -1
- ksadk/server/static/assets/{MermaidBlock-Dz4IP-Tx.js → MermaidBlock--OEYoXIJ.js} +6 -6
- ksadk/server/static/assets/{NativeTerminalPanel-DUrK0JpZ.js → NativeTerminalPanel-DrEe1syq.js} +1 -1
- ksadk/server/static/assets/{abnfDiagram-VCTEODGH-g20pFzNV.js → abnfDiagram-VCTEODGH-eeTFJLvo.js} +1 -1
- ksadk/server/static/assets/{arc-C4FzinUA.js → arc-S3ZNbIAd.js} +1 -1
- ksadk/server/static/assets/architecture-7GRP2DOG-Dk9nRQ6-.js +1 -0
- ksadk/server/static/assets/{architectureDiagram-5GKGNRK7-DpIqL5h4.js → architectureDiagram-5GKGNRK7-CRjgEJDX.js} +1 -1
- ksadk/server/static/assets/{blockDiagram-NRAW4CY4-BjkljTNz.js → blockDiagram-NRAW4CY4-C7bsBoNH.js} +1 -1
- ksadk/server/static/assets/{c4Diagram-UCG6FXSJ-Dk_ieq2X.js → c4Diagram-UCG6FXSJ-BX3c33Ob.js} +1 -1
- ksadk/server/static/assets/channel-s354Yo6o.js +1 -0
- ksadk/server/static/assets/chunk-2Q5K7J3B-CDpPpKR5.js +1 -0
- ksadk/server/static/assets/{chunk-5VM5RSS4-BVHAchFb.js → chunk-5VM5RSS4-bZ7ws-8m.js} +1 -1
- ksadk/server/static/assets/{chunk-F27PBJKO-C-ipQzuS.js → chunk-F27PBJKO-D2r0pvhY.js} +1 -1
- ksadk/server/static/assets/{chunk-G27WJ6UU-C2EyJbIK.js → chunk-G27WJ6UU-CZwF3oUP.js} +1 -1
- ksadk/server/static/assets/{chunk-JWPE2WC7-vYvVJb_M.js → chunk-JWPE2WC7-DigFYCML.js} +1 -1
- ksadk/server/static/assets/{chunk-LCL6LL3I-BcI6ysPT.js → chunk-LCL6LL3I-CnorGV5q.js} +1 -1
- ksadk/server/static/assets/{chunk-POPQ4Y6H-C030x_Z1.js → chunk-POPQ4Y6H-CexntQA-.js} +1 -1
- ksadk/server/static/assets/{chunk-RHFEMEQ7-yyGpsz4n.js → chunk-RHFEMEQ7-CHTC7UxA.js} +1 -1
- ksadk/server/static/assets/{chunk-SVP7TREG-BLTlmMU7.js → chunk-SVP7TREG-BC1EWt_-.js} +1 -1
- ksadk/server/static/assets/{chunk-XXDRQBXY-C_32ArgP.js → chunk-XXDRQBXY-BTG24xN0.js} +1 -1
- ksadk/server/static/assets/classDiagram-DTDB5LWJ-Dd0nucl9.js +1 -0
- ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-Dd0nucl9.js +1 -0
- ksadk/server/static/assets/{cose-bilkent-JH36ORCC-9YQYwdl0.js → cose-bilkent-JH36ORCC-CkonRdAS.js} +1 -1
- ksadk/server/static/assets/cynefin-OW5HDTMX-BBlT4uMf.js +1 -0
- ksadk/server/static/assets/{cynefinDiagram-5FMLGOSQ-ErLF5N13.js → cynefinDiagram-5FMLGOSQ-DEOCBe15.js} +1 -1
- ksadk/server/static/assets/{dagre-3AP2YEHR-DFiQF-6f.js → dagre-3AP2YEHR-DBThPuLa.js} +1 -1
- ksadk/server/static/assets/{dagre-BuhGnRI1.js → dagre-ClTPrTht.js} +1 -1
- ksadk/server/static/assets/{diagram-S7CK7UJ4-Bt1v8-GC.js → diagram-S7CK7UJ4-DsZHrnpJ.js} +1 -1
- ksadk/server/static/assets/{diagram-UQ7AKVKN-DSCxJdBK.js → diagram-UQ7AKVKN-BJR4nhVr.js} +1 -1
- ksadk/server/static/assets/{diagram-VSXAHHWV-DHfYwp_9.js → diagram-VSXAHHWV-xzcERX0a.js} +1 -1
- ksadk/server/static/assets/{diagram-VX7I27RA-DdzD-4Le.js → diagram-VX7I27RA-tn2xM1xu.js} +1 -1
- ksadk/server/static/assets/{diagram-Z3DM3KII-Du-nAJ9F.js → diagram-Z3DM3KII-BZPGBkw5.js} +1 -1
- ksadk/server/static/assets/{dist-ClxGviKw.js → dist-4zN1_tq5.js} +1 -1
- ksadk/server/static/assets/{dist-BE7bu-DL.js → dist-8VWI-2bZ.js} +1 -1
- ksadk/server/static/assets/{dist-BX8z72IC.js → dist-B-46q3Hk.js} +1 -1
- ksadk/server/static/assets/{dist-BjU6y-A2.js → dist-B0gdk4rl.js} +1 -1
- ksadk/server/static/assets/{dist-C_wsv-Qd.js → dist-B1oWRmrH.js} +1 -1
- ksadk/server/static/assets/{dist-ngtN0DJB.js → dist-BI1qQH4n.js} +1 -1
- ksadk/server/static/assets/{dist-dydu68Fl.js → dist-BJLUwH6W.js} +1 -1
- ksadk/server/static/assets/{dist-Dq9gLD7L.js → dist-Bbwqa8TG.js} +1 -1
- ksadk/server/static/assets/{dist-CttYUqzS.js → dist-Btyo4vX4.js} +1 -1
- ksadk/server/static/assets/{dist-CXYYBw3_.js → dist-C71CsujO.js} +1 -1
- ksadk/server/static/assets/{dist-dDdADKFA.js → dist-CXpH_Rdd.js} +1 -1
- ksadk/server/static/assets/{dist-CSh_DE14.js → dist-Cq4OL6nO.js} +1 -1
- ksadk/server/static/assets/{dist-8hqcx0sU.js → dist-D1V3f1B4.js} +1 -1
- ksadk/server/static/assets/{dist-BVDffZ0U.js → dist-DJmCPRVB.js} +1 -1
- ksadk/server/static/assets/{dist-DnfXs8Vn.js → dist-DQAB0qn_.js} +1 -1
- ksadk/server/static/assets/{dist-DNp6rLRA.js → dist-DUwKa_l6.js} +1 -1
- ksadk/server/static/assets/{dist-B7seoj3d.js → dist-DdRBIceA.js} +1 -1
- ksadk/server/static/assets/{dist-BytlxIDT.js → dist-DfGFrb0v.js} +1 -1
- ksadk/server/static/assets/{dist-Bf2M8m3N.js → dist-DjhwGUgZ.js} +1 -1
- ksadk/server/static/assets/{dist-W-TIVntx.js → dist-DyqV4fL4.js} +1 -1
- ksadk/server/static/assets/{dist-DUX-id_F.js → dist-M67Hwu0n.js} +1 -1
- ksadk/server/static/assets/{dist-DmldrHd_.js → dist-u8tVH5Ak.js} +1 -1
- ksadk/server/static/assets/{ebnfDiagram-PWID7BFC-Da9C9NO1.js → ebnfDiagram-PWID7BFC-DVfMsLge.js} +1 -1
- ksadk/server/static/assets/{erDiagram-SSCWMZ5O-EAGqqR79.js → erDiagram-SSCWMZ5O-CWEZSYaw.js} +1 -1
- ksadk/server/static/assets/eventmodeling-NTZA5JFV-Dr5okd8V.js +1 -0
- ksadk/server/static/assets/flowDiagram-A5DVABFB-VEO-cVcO.js +1 -0
- ksadk/server/static/assets/{ganttDiagram-EL5Y4UJY-DqJsKb59.js → ganttDiagram-EL5Y4UJY-TWIxoyYL.js} +1 -1
- ksadk/server/static/assets/gitGraph-4MIJSDKK-CKiKY9Cf.js +1 -0
- ksadk/server/static/assets/{gitGraphDiagram-WWUBYQGX-B6g4dtDi.js → gitGraphDiagram-WWUBYQGX-DDh2hd2S.js} +1 -1
- ksadk/server/static/assets/index-B2k_urY8.js +241 -0
- ksadk/server/static/assets/index-ILPt6IWF.css +2 -0
- ksadk/server/static/assets/info-A6RAGUB7-ubA4Nm_p.js +1 -0
- ksadk/server/static/assets/{infoDiagram-RXCK75RN-Djm_nbd5.js → infoDiagram-RXCK75RN-CgoyWiDR.js} +1 -1
- ksadk/server/static/assets/{ishikawaDiagram-5VMMS53U-DWya9SG2.js → ishikawaDiagram-5VMMS53U-CyRIu_om.js} +1 -1
- ksadk/server/static/assets/{journeyDiagram-EYS64GPL-DutxhSNI.js → journeyDiagram-EYS64GPL-DN5JXHzN.js} +1 -1
- ksadk/server/static/assets/{kanban-definition-3QL26DDD-DJdOF8Fm.js → kanban-definition-3QL26DDD-CNP3ui66.js} +1 -1
- ksadk/server/static/assets/{katex-vFWytM5c.js → katex-DWEzQy1d.js} +1 -1
- ksadk/server/static/assets/{linear-BHjG8b-J.js → linear-C-qHp7d2.js} +1 -1
- ksadk/server/static/assets/{mermaid-parser.core-KGSy4jWT.js → mermaid-parser.core-Cl-K943T.js} +2 -2
- ksadk/server/static/assets/{mindmap-definition-FBJOCRG2-9-HC88D4.js → mindmap-definition-FBJOCRG2-D5DB5mYm.js} +1 -1
- ksadk/server/static/assets/packet-AYTQ26CC-C7R3NUlK.js +1 -0
- ksadk/server/static/assets/{pegDiagram-XKGWAZYB-DrEZd4fD.js → pegDiagram-XKGWAZYB-BQVc9ia_.js} +1 -1
- ksadk/server/static/assets/pie-WAS4IAKB-BIT6qjr3.js +1 -0
- ksadk/server/static/assets/{pieDiagram-E7YTZNPT-DpjqOFFp.js → pieDiagram-E7YTZNPT-B6UCAvtY.js} +1 -1
- ksadk/server/static/assets/{quadrantDiagram-AXDQQJYC-BiNhgOXX.js → quadrantDiagram-AXDQQJYC-mIr2d3eb.js} +1 -1
- ksadk/server/static/assets/radar-RG4KPBEZ-l5noef9X.js +1 -0
- ksadk/server/static/assets/railroad-74A4TZTK-Baea6ZvM.js +1 -0
- ksadk/server/static/assets/railroad-abnf-HS5TGJTU-OKn8zZnU.js +1 -0
- ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-DdKAKC4l.js +1 -0
- ksadk/server/static/assets/railroad-peg-WCYAUIDC-Bds8udlG.js +1 -0
- ksadk/server/static/assets/{railroadDiagram-O6MQD6OU-_Y3Ojg6G.js → railroadDiagram-O6MQD6OU-Dt3FFDmK.js} +1 -1
- ksadk/server/static/assets/{requirementDiagram-EFPCY7ZU-DeCFdg9K.js → requirementDiagram-EFPCY7ZU-Cz_vQtgF.js} +1 -1
- ksadk/server/static/assets/{sankeyDiagram-P5KCCOFB-CPH75rhw.js → sankeyDiagram-P5KCCOFB-wlO1TsH5.js} +1 -1
- ksadk/server/static/assets/{sequenceDiagram-WJ2MYXX4-OEpQQdr4.js → sequenceDiagram-WJ2MYXX4-CHRbElYq.js} +1 -1
- ksadk/server/static/assets/{sizeCapture-X5ZJPWSS-heUErzhI.js → sizeCapture-X5ZJPWSS-DXX54iyO.js} +1 -1
- ksadk/server/static/assets/{stateDiagram-HBIQ2CUA-DvA3jSMB.js → stateDiagram-HBIQ2CUA-Dp_lw9II.js} +1 -1
- ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-5b-8o2iS.js +1 -0
- ksadk/server/static/assets/{swimlanes-XN3QIQJK-CR-dfN_t.js → swimlanes-XN3QIQJK-D8O5UlLG.js} +1 -1
- ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-uf6WPRA4.js +8 -0
- ksadk/server/static/assets/{timeline-definition-24CTP7MA-DAVJf1TX.js → timeline-definition-24CTP7MA-8mfKcxvG.js} +1 -1
- ksadk/server/static/assets/treeView-Q6P3EWNA-CK5CSrSO.js +1 -0
- ksadk/server/static/assets/treemap-WGGIJYW6-Ch2BKgAM.js +1 -0
- ksadk/server/static/assets/{vennDiagram-4TSXK5OY-DwM8eDkh.js → vennDiagram-4TSXK5OY-EnNl0DE7.js} +1 -1
- ksadk/server/static/assets/wardley-WFR3VGLG-YW3Q0ml_.js +1 -0
- ksadk/server/static/assets/{wardleyDiagram-VM6X3IG4-DZL-Zz2t.js → wardleyDiagram-VM6X3IG4-DBu5fbYr.js} +1 -1
- ksadk/server/static/assets/{xychartDiagram-S5SC5T6Z-Dy6Yh_hu.js → xychartDiagram-S5SC5T6Z-BSVXs4IY.js} +1 -1
- ksadk/server/static/index.html +2 -2
- ksadk/skills/service_client.py +48 -0
- ksadk/studio/agent_lifecycle.py +26 -20
- ksadk/studio/api.py +513 -71
- ksadk/studio/api_catalog_routes.py +5 -0
- ksadk/studio/api_contracts.py +34 -1
- ksadk/studio/api_plugin_routes.py +480 -0
- ksadk/studio/attachment_store.py +187 -0
- ksadk/studio/authoring.py +10 -4
- ksadk/studio/authoring_coordinator.py +12 -2
- ksadk/studio/builder.py +123 -43
- ksadk/studio/cloud.py +4 -0
- ksadk/studio/codex_agent_service.py +12 -1
- ksadk/studio/codex_builder.py +54 -15
- ksadk/studio/codex_manifest.py +21 -1
- ksadk/studio/codex_run.py +16 -4
- ksadk/studio/compatibility_report.py +445 -0
- ksadk/studio/compiler.py +6 -1
- ksadk/studio/contracts.py +123 -4
- ksadk/studio/dsh_provider_registration.py +768 -0
- ksadk/studio/event_store.py +54 -6
- ksadk/studio/framework_run.py +37 -4
- ksadk/studio/hosted_kernel.py +1 -1
- ksadk/studio/operations.py +12 -2
- ksadk/studio/plugin_composition.py +301 -0
- ksadk/studio/plugin_kernel_adapter.py +128 -0
- ksadk/studio/plugin_runtime.py +652 -0
- ksadk/studio/resource_catalog.py +6 -1
- ksadk/studio/run_service.py +713 -75
- ksadk/studio/runtime_source.py +9 -1
- ksadk/studio/scheduler_runtime.py +374 -0
- ksadk/studio/scheduler_service.py +211 -0
- ksadk/studio/service.py +672 -82
- ksadk/studio/shared_web.py +167 -28
- ksadk/studio/soul.py +52 -0
- ksadk/studio/static/assets/index-DXs1Eq4M.css +1 -0
- ksadk/studio/static/assets/index-DeDqwTsD.js +283 -0
- ksadk/studio/static/index.html +2 -2
- ksadk/studio/validator.py +1 -1
- ksadk/studio/workspace.py +1 -0
- ksadk/version.py +1 -1
- ksadk_runtime_common/workspace_files/path_utils.py +41 -0
- ksadk/server/static/assets/architecture-7GRP2DOG-DjKratdf.js +0 -1
- ksadk/server/static/assets/channel-4cQHKtx1.js +0 -1
- ksadk/server/static/assets/chunk-2Q5K7J3B-DmgWkESh.js +0 -1
- ksadk/server/static/assets/classDiagram-DTDB5LWJ-DLFd9Xi0.js +0 -1
- ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-DLFd9Xi0.js +0 -1
- ksadk/server/static/assets/cynefin-OW5HDTMX-DjEM48Qp.js +0 -1
- ksadk/server/static/assets/eventmodeling-NTZA5JFV-CMgMaJrC.js +0 -1
- ksadk/server/static/assets/flowDiagram-A5DVABFB-BBKL0x3P.js +0 -1
- ksadk/server/static/assets/gitGraph-4MIJSDKK-Dw63mrhw.js +0 -1
- ksadk/server/static/assets/index-8ipRcQ-M.js +0 -240
- ksadk/server/static/assets/index-ByFCqjlh.css +0 -2
- ksadk/server/static/assets/info-A6RAGUB7-B6iAblII.js +0 -1
- ksadk/server/static/assets/packet-AYTQ26CC-BOYAipuq.js +0 -1
- ksadk/server/static/assets/pie-WAS4IAKB-Ctq0Kbku.js +0 -1
- ksadk/server/static/assets/radar-RG4KPBEZ-DN0-ul_0.js +0 -1
- ksadk/server/static/assets/railroad-74A4TZTK-C6cC_to0.js +0 -1
- ksadk/server/static/assets/railroad-abnf-HS5TGJTU-BimjIuRc.js +0 -1
- ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-CvY65ABq.js +0 -1
- ksadk/server/static/assets/railroad-peg-WCYAUIDC-D72Iq_Tv.js +0 -1
- ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-BgQY03nz.js +0 -1
- ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-DLVw3q5Q.js +0 -8
- ksadk/server/static/assets/treeView-Q6P3EWNA-BMpO0wsB.js +0 -1
- ksadk/server/static/assets/treemap-WGGIJYW6-Et0aqzU3.js +0 -1
- ksadk/server/static/assets/wardley-WFR3VGLG-CbY0mhpl.js +0 -1
- ksadk/studio/static/assets/index-BLpcdrgW.css +0 -1
- ksadk/studio/static/assets/index-CYekR2Xv.js +0 -260
- {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.3.dist-info}/WHEEL +0 -0
- {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.3.dist-info}/entry_points.txt +0 -0
- {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.3.dist-info}/licenses/LICENSE +0 -0
- {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.3.dist-info}/top_level.txt +0 -0
ksadk/studio/event_store.py
CHANGED
|
@@ -43,16 +43,64 @@ class RunEventStore:
|
|
|
43
43
|
stored in the run JSON so the Studio events timeline survives restarts.
|
|
44
44
|
Runs that never call ``append`` keep ``set(run_payload) == {"record"}``.
|
|
45
45
|
"""
|
|
46
|
+
return self.append_many(run_id, [(event_type, data)])[0]
|
|
47
|
+
|
|
48
|
+
def append_many(
|
|
49
|
+
self,
|
|
50
|
+
run_id: str,
|
|
51
|
+
entries: list[tuple[str, dict[str, Any]]],
|
|
52
|
+
) -> list[RunEvent]:
|
|
53
|
+
"""Persist one logical Studio transition with a single file replace."""
|
|
46
54
|
record, events = self._read(run_id)
|
|
47
|
-
|
|
48
|
-
|
|
55
|
+
appended: list[RunEvent] = []
|
|
56
|
+
for event_type, data in entries:
|
|
57
|
+
event = RunEvent(
|
|
58
|
+
id=len(events) + 1,
|
|
59
|
+
run_id=run_id,
|
|
60
|
+
type=event_type,
|
|
61
|
+
data=data,
|
|
62
|
+
)
|
|
63
|
+
events.append(event)
|
|
64
|
+
appended.append(event)
|
|
65
|
+
if appended:
|
|
66
|
+
self._write(record, events)
|
|
67
|
+
return appended
|
|
68
|
+
|
|
69
|
+
def append_interaction_resolution(
|
|
70
|
+
self,
|
|
71
|
+
run_id: str,
|
|
72
|
+
*,
|
|
73
|
+
resolved_type: str,
|
|
74
|
+
resolved_data: dict[str, Any],
|
|
75
|
+
action_data: dict[str, Any],
|
|
76
|
+
) -> tuple[RunEvent, RunEvent, dict[str, Any]]:
|
|
77
|
+
"""Atomically persist a terminal interaction and its replay receipt."""
|
|
78
|
+
record, events = self._read(run_id)
|
|
79
|
+
resolution_event_id = len(events) + 1
|
|
80
|
+
action_event_id = resolution_event_id + 1
|
|
81
|
+
receipt = {
|
|
82
|
+
"runId": run_id,
|
|
83
|
+
"interactionId": str(action_data.get("interactionId") or ""),
|
|
84
|
+
"status": "resolved",
|
|
85
|
+
"revision": int(action_data.get("revision") or 0),
|
|
86
|
+
"resolutionEventId": resolution_event_id,
|
|
87
|
+
"eventId": action_event_id,
|
|
88
|
+
}
|
|
89
|
+
resolved = RunEvent(
|
|
90
|
+
id=resolution_event_id,
|
|
91
|
+
run_id=run_id,
|
|
92
|
+
type=resolved_type,
|
|
93
|
+
data=resolved_data,
|
|
94
|
+
)
|
|
95
|
+
action = RunEvent(
|
|
96
|
+
id=action_event_id,
|
|
49
97
|
run_id=run_id,
|
|
50
|
-
type=
|
|
51
|
-
data=
|
|
98
|
+
type="a2ui.action",
|
|
99
|
+
data={**action_data, "receipt": receipt},
|
|
52
100
|
)
|
|
53
|
-
events.
|
|
101
|
+
events.extend((resolved, action))
|
|
54
102
|
self._write(record, events)
|
|
55
|
-
return
|
|
103
|
+
return resolved, action, receipt
|
|
56
104
|
|
|
57
105
|
def events(self, run_id: str, *, after: int = 0) -> list[RunEvent]:
|
|
58
106
|
_, events = self._read(run_id)
|
ksadk/studio/framework_run.py
CHANGED
|
@@ -8,6 +8,7 @@ from pathlib import Path
|
|
|
8
8
|
from typing import Any
|
|
9
9
|
|
|
10
10
|
from ksadk.detection.detector import FrameworkDetector
|
|
11
|
+
from ksadk.plugins.bundle_security import BundleSecurityError, assert_bundle_security
|
|
11
12
|
from ksadk.runtime import RuntimeLaunchContext
|
|
12
13
|
from ksadk.studio.capabilities import compute_bundle_digest
|
|
13
14
|
from ksadk.studio.contracts import BundleManifest
|
|
@@ -120,9 +121,11 @@ class FrameworkRunSpecResolver:
|
|
|
120
121
|
raise StudioError("BUILD_NOT_READY", "Build 尚未生成制品", status_code=409)
|
|
121
122
|
artifact_root = self.workspace.resolve(build.artifact_path, must_exist=True).parent
|
|
122
123
|
bundle_root = artifact_root / "agent-bundle"
|
|
123
|
-
self._verify_bundle_integrity(
|
|
124
|
-
|
|
125
|
-
|
|
124
|
+
self._verify_bundle_integrity(bundle_root, expected_bundle_digest=build.bundle_digest)
|
|
125
|
+
# v1 artifacts predate the no-literal-secret Bundle admission rule and
|
|
126
|
+
# must stay runnable. Every v2 bundle is checked again before local
|
|
127
|
+
# execution, including an externally restored but integrity-valid ZIP.
|
|
128
|
+
self._verify_bundle_security(bundle_root)
|
|
126
129
|
project_dir = bundle_root / "runtime"
|
|
127
130
|
if not project_dir.is_dir():
|
|
128
131
|
raise StudioError(
|
|
@@ -301,6 +304,37 @@ class FrameworkRunSpecResolver:
|
|
|
301
304
|
},
|
|
302
305
|
)
|
|
303
306
|
|
|
307
|
+
@staticmethod
|
|
308
|
+
def _verify_bundle_security(bundle_dir: Path) -> None:
|
|
309
|
+
try:
|
|
310
|
+
manifest = BundleManifest.model_validate_json(
|
|
311
|
+
(bundle_dir / "manifest.json").read_text(encoding="utf-8")
|
|
312
|
+
)
|
|
313
|
+
except (OSError, ValueError):
|
|
314
|
+
# Integrity verification reports the canonical error for a malformed
|
|
315
|
+
# manifest; do not mask it with a second diagnostic path.
|
|
316
|
+
return
|
|
317
|
+
if manifest.bundle_format != "agentkit.bundle/v2":
|
|
318
|
+
return
|
|
319
|
+
try:
|
|
320
|
+
assert_bundle_security(bundle_dir)
|
|
321
|
+
except BundleSecurityError as exc:
|
|
322
|
+
raise StudioError(
|
|
323
|
+
"BUILD_ARTIFACT_INVALID",
|
|
324
|
+
"Bundle 包含不允许的明文凭证或本机路径",
|
|
325
|
+
status_code=422,
|
|
326
|
+
details={
|
|
327
|
+
"securityFindings": [
|
|
328
|
+
{
|
|
329
|
+
"path": finding.path,
|
|
330
|
+
"kind": finding.kind,
|
|
331
|
+
**({"field": finding.field} if finding.field else {}),
|
|
332
|
+
}
|
|
333
|
+
for finding in exc.findings
|
|
334
|
+
]
|
|
335
|
+
},
|
|
336
|
+
) from exc
|
|
337
|
+
|
|
304
338
|
|
|
305
339
|
__all__ = ["FrameworkRunSpecResolver"]
|
|
306
340
|
|
|
@@ -309,7 +343,6 @@ def _resolved_memory_enabled(resolved: Any) -> bool:
|
|
|
309
343
|
memory = resolved.get("memory") if isinstance(resolved, dict) else {}
|
|
310
344
|
return bool(memory.get("enabled", False)) if isinstance(memory, dict) else False
|
|
311
345
|
|
|
312
|
-
|
|
313
346
|
memory = resolved.get("memory") if isinstance(resolved, dict) else {}
|
|
314
347
|
if not isinstance(memory, dict) or not memory.get("enabled", False):
|
|
315
348
|
return False
|
ksadk/studio/hosted_kernel.py
CHANGED
|
@@ -21,7 +21,7 @@ from ksadk.studio.errors import StudioError
|
|
|
21
21
|
AGENT_KERNEL_V1_CONTRACT_SET = "agent-kernel/v1"
|
|
22
22
|
# This mirrors contracts/agent-kernel/v1/manifest.json. A Studio test compares
|
|
23
23
|
# the two, so a frozen-contract update cannot leave packaged preflight stale.
|
|
24
|
-
AGENT_KERNEL_V1_CONTRACT_DIGEST = "
|
|
24
|
+
AGENT_KERNEL_V1_CONTRACT_DIGEST = "b610a25aae957306b9f84a2cc2c948b30d1ce6218585cfd2a91f96736b92d102"
|
|
25
25
|
HOSTED_KERNEL_REQUIREMENTS_PATH = "hosted-kernel-requirements.json"
|
|
26
26
|
HOSTED_KERNEL_REQUIREMENTS_FORMAT = "agentkit.hosted-kernel-requirements/v1"
|
|
27
27
|
HOSTED_KERNEL_RUNTIME_CONTRACT = "agentkit.runtime/v1"
|
ksadk/studio/operations.py
CHANGED
|
@@ -12,6 +12,7 @@ from uuid import uuid4
|
|
|
12
12
|
|
|
13
13
|
from pydantic import ValidationError
|
|
14
14
|
|
|
15
|
+
from ksadk.api import AgentEngineAPIError
|
|
15
16
|
from ksadk.studio.contracts import (
|
|
16
17
|
Operation,
|
|
17
18
|
OperationEvent,
|
|
@@ -108,10 +109,19 @@ class OperationManager:
|
|
|
108
109
|
"exceptionType": type(exc).__name__,
|
|
109
110
|
}
|
|
110
111
|
# TypeError carries only Python call-shape information and is safe
|
|
111
|
-
# to surface to the local operator.
|
|
112
|
-
#
|
|
112
|
+
# to surface to the local operator. AgentEngineAPIError carries
|
|
113
|
+
# a structured server-side Action API message (not credentials),
|
|
114
|
+
# so surface it to help the operator diagnose a failed deployment.
|
|
113
115
|
if isinstance(exc, TypeError):
|
|
114
116
|
operation.error["exceptionMessage"] = str(exc)
|
|
117
|
+
elif isinstance(exc, StudioError):
|
|
118
|
+
operation.error["code"] = exc.code
|
|
119
|
+
operation.error["message"] = exc.message
|
|
120
|
+
elif isinstance(exc, AgentEngineAPIError):
|
|
121
|
+
operation.error["code"] = f"AGENT_ENGINE_API_ERROR_{exc.code}"
|
|
122
|
+
operation.error["message"] = exc.message
|
|
123
|
+
if exc.details:
|
|
124
|
+
operation.error["details"] = exc.details
|
|
115
125
|
operation.completed_at = datetime.now(timezone.utc)
|
|
116
126
|
self._save_record(operation)
|
|
117
127
|
self.append(operation_id, "operation.failed", operation.error)
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
"""Studio Agent revision -> immutable PluginHost composition binding.
|
|
2
|
+
|
|
3
|
+
This is the production build seam for Phase 2. It admits built-in providers
|
|
4
|
+
or one exact AgentProvider registration emitted by the active DSH host,
|
|
5
|
+
then delegates the deterministic Profile/Lock construction to
|
|
6
|
+
``CompositionCompiler``. Legacy ADK/LangGraph drafts intentionally bypass
|
|
7
|
+
this module and retain their established source-build behavior.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from collections.abc import Mapping
|
|
13
|
+
from copy import deepcopy
|
|
14
|
+
|
|
15
|
+
from ksadk.plugins.builtins import (
|
|
16
|
+
BUILTIN_PLUGIN_VERSION,
|
|
17
|
+
CORE_RENDERER_PLUGIN_ID,
|
|
18
|
+
READ_ONLY_CONTEXT_PLUGIN_ID,
|
|
19
|
+
SQLITE_SESSION_STORE_PLUGIN_ID,
|
|
20
|
+
WORKSPACE_MCP_PLUGIN_ID,
|
|
21
|
+
WORKSPACE_SKILL_PLUGIN_ID,
|
|
22
|
+
builtin_capability_manifests,
|
|
23
|
+
)
|
|
24
|
+
from ksadk.plugins.composition import (
|
|
25
|
+
CompositionCompileError,
|
|
26
|
+
CompositionCompiler,
|
|
27
|
+
CompositionPolicy,
|
|
28
|
+
PluginCapabilitySelection,
|
|
29
|
+
ResourcePluginMaterialization,
|
|
30
|
+
RuntimePluginSelection,
|
|
31
|
+
)
|
|
32
|
+
from ksadk.plugins.contracts import PluginManifest
|
|
33
|
+
from ksadk.plugins.providers.legacy_catalog import (
|
|
34
|
+
BUILTIN_PROVIDER_VERSION,
|
|
35
|
+
KSADK_HARNESS_AGENT_PROVIDER_PLUGIN_ID,
|
|
36
|
+
builtin_agent_provider_manifests,
|
|
37
|
+
)
|
|
38
|
+
from ksadk.plugins.resolver import PluginRegistry, ResolvedComposition
|
|
39
|
+
from ksadk.studio.contracts import AgentDraft, CapabilityBinding
|
|
40
|
+
from ksadk.studio.errors import StudioError
|
|
41
|
+
from ksadk.studio.resource_catalog import LocalResourceCatalog
|
|
42
|
+
from ksadk.studio.workspace import Workspace
|
|
43
|
+
|
|
44
|
+
_COMPOSED_RUNTIME_TYPES = frozenset({"harness", "plugin"})
|
|
45
|
+
_PROVIDER_DEFINITION = "agent.provider/v1"
|
|
46
|
+
_PROVIDER_SLOT = "agent.execution"
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _plugin_ref(plugin_id: str, version: str) -> str:
|
|
50
|
+
return f"plugin://{plugin_id}@{version}"
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _selection(
|
|
54
|
+
plugin_id: str,
|
|
55
|
+
definition: str,
|
|
56
|
+
slot: str,
|
|
57
|
+
*,
|
|
58
|
+
config: Mapping[str, object] | None = None,
|
|
59
|
+
) -> PluginCapabilitySelection:
|
|
60
|
+
return PluginCapabilitySelection(
|
|
61
|
+
ref=_plugin_ref(plugin_id, BUILTIN_PLUGIN_VERSION),
|
|
62
|
+
definition=definition,
|
|
63
|
+
slot=slot,
|
|
64
|
+
config=deepcopy(dict(config or {})),
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class StudioPluginCompositionCompiler:
|
|
69
|
+
"""Bind a Studio revision to installed/built-in provider manifests."""
|
|
70
|
+
|
|
71
|
+
def __init__(
|
|
72
|
+
self,
|
|
73
|
+
workspace: Workspace,
|
|
74
|
+
catalog: LocalResourceCatalog,
|
|
75
|
+
*,
|
|
76
|
+
provider_manifests: Mapping[str, PluginManifest] | None = None,
|
|
77
|
+
) -> None:
|
|
78
|
+
self._workspace = workspace
|
|
79
|
+
self._catalog = catalog
|
|
80
|
+
self._provider_manifests = dict(provider_manifests or {})
|
|
81
|
+
|
|
82
|
+
def replace_provider_registrations(
|
|
83
|
+
self, provider_manifests: Mapping[str, PluginManifest]
|
|
84
|
+
) -> None:
|
|
85
|
+
"""Bind the exact startup registration snapshot before any build."""
|
|
86
|
+
|
|
87
|
+
self._provider_manifests = dict(provider_manifests)
|
|
88
|
+
|
|
89
|
+
@staticmethod
|
|
90
|
+
def required_for(draft: AgentDraft) -> bool:
|
|
91
|
+
runtime = draft.spec.runtime
|
|
92
|
+
return runtime is not None and runtime.type in _COMPOSED_RUNTIME_TYPES
|
|
93
|
+
|
|
94
|
+
def compile_if_required(self, draft: AgentDraft) -> ResolvedComposition | None:
|
|
95
|
+
if not self.required_for(draft):
|
|
96
|
+
return None
|
|
97
|
+
return self.compile(draft)
|
|
98
|
+
|
|
99
|
+
def compile(self, draft: AgentDraft) -> ResolvedComposition:
|
|
100
|
+
runtime = draft.spec.runtime
|
|
101
|
+
if runtime is None or runtime.type not in _COMPOSED_RUNTIME_TYPES:
|
|
102
|
+
raise StudioError(
|
|
103
|
+
"PLUGIN_COMPOSITION_NOT_REQUIRED",
|
|
104
|
+
"当前 Runtime 继续使用既有构建链,不应声明 PluginHost composition",
|
|
105
|
+
status_code=422,
|
|
106
|
+
field="spec.runtime.type",
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
manifests = [
|
|
110
|
+
*builtin_agent_provider_manifests(),
|
|
111
|
+
*builtin_capability_manifests(),
|
|
112
|
+
]
|
|
113
|
+
harness_ref = _plugin_ref(
|
|
114
|
+
KSADK_HARNESS_AGENT_PROVIDER_PLUGIN_ID,
|
|
115
|
+
BUILTIN_PROVIDER_VERSION,
|
|
116
|
+
)
|
|
117
|
+
harness_manifest = self._provider_manifests.get(harness_ref)
|
|
118
|
+
if runtime.type == "harness":
|
|
119
|
+
if harness_manifest is None:
|
|
120
|
+
raise StudioError(
|
|
121
|
+
"AGENT_PROVIDER_NOT_REGISTERED",
|
|
122
|
+
"KsADK Harness 尚未由受管理 DSH Profile 完成预检与注册",
|
|
123
|
+
status_code=503,
|
|
124
|
+
field="spec.runtime.type",
|
|
125
|
+
)
|
|
126
|
+
manifests.append(harness_manifest)
|
|
127
|
+
providers: dict[str, RuntimePluginSelection] = {}
|
|
128
|
+
if runtime.type == "plugin":
|
|
129
|
+
assert runtime.provider_ref is not None # RuntimeRef validates this boundary.
|
|
130
|
+
external = self._registered_provider(runtime.provider_ref, draft)
|
|
131
|
+
manifests.append(external)
|
|
132
|
+
providers[runtime.provider_ref] = RuntimePluginSelection(
|
|
133
|
+
provider_ref=runtime.provider_ref,
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
policy = CompositionPolicy(
|
|
137
|
+
runtimes={"harness": RuntimePluginSelection(provider_ref=harness_ref)},
|
|
138
|
+
providers=providers,
|
|
139
|
+
session_store=_selection(
|
|
140
|
+
SQLITE_SESSION_STORE_PLUGIN_ID,
|
|
141
|
+
"session.event-store/v1",
|
|
142
|
+
"session.events",
|
|
143
|
+
),
|
|
144
|
+
resource_materializations=self._resource_materializations(draft),
|
|
145
|
+
context_contributors={
|
|
146
|
+
"workspace_rules": _selection(
|
|
147
|
+
READ_ONLY_CONTEXT_PLUGIN_ID,
|
|
148
|
+
"context.contributor/v1",
|
|
149
|
+
"context.bundle",
|
|
150
|
+
config={
|
|
151
|
+
"paths": ["instructions/soul.md"]
|
|
152
|
+
if draft.spec.soul is not None
|
|
153
|
+
else [],
|
|
154
|
+
"maxChars": draft.spec.context.max_input_tokens * 4,
|
|
155
|
+
},
|
|
156
|
+
)
|
|
157
|
+
},
|
|
158
|
+
renderers=(
|
|
159
|
+
_selection(
|
|
160
|
+
CORE_RENDERER_PLUGIN_ID,
|
|
161
|
+
"session.item.renderer/v1",
|
|
162
|
+
"renderer.core",
|
|
163
|
+
),
|
|
164
|
+
),
|
|
165
|
+
default_runtime="harness",
|
|
166
|
+
)
|
|
167
|
+
try:
|
|
168
|
+
return CompositionCompiler(
|
|
169
|
+
PluginRegistry(manifests), self._catalog, policy
|
|
170
|
+
).compile(draft)
|
|
171
|
+
except CompositionCompileError as error:
|
|
172
|
+
raise StudioError(
|
|
173
|
+
error.code.upper(),
|
|
174
|
+
str(error),
|
|
175
|
+
status_code=422,
|
|
176
|
+
field=error.field,
|
|
177
|
+
) from error
|
|
178
|
+
|
|
179
|
+
def bind_build(self, composition: ResolvedComposition, *, agent_id: str, build_id: str) -> None:
|
|
180
|
+
"""Keep the API seam while DSH owns package/Profile references."""
|
|
181
|
+
|
|
182
|
+
del composition, agent_id, build_id
|
|
183
|
+
|
|
184
|
+
def unbind_builds(self, builds: list[object]) -> tuple[tuple[str, str, str], ...]:
|
|
185
|
+
"""Remove exact Bundle bindings before deleting an Agent.
|
|
186
|
+
|
|
187
|
+
The returned tokens let the caller restore protection if its filesystem
|
|
188
|
+
deletion transaction fails after the receipt updates.
|
|
189
|
+
"""
|
|
190
|
+
|
|
191
|
+
del builds
|
|
192
|
+
return ()
|
|
193
|
+
|
|
194
|
+
def restore_bindings(self, bindings: tuple[tuple[str, str, str], ...]) -> None:
|
|
195
|
+
"""Best-effort-safe rollback for a failed Agent deletion."""
|
|
196
|
+
|
|
197
|
+
del bindings
|
|
198
|
+
|
|
199
|
+
@staticmethod
|
|
200
|
+
def build_reference(agent_id: str, build_id: str) -> str:
|
|
201
|
+
return f"bundle://{agent_id}@{build_id}"
|
|
202
|
+
|
|
203
|
+
def _registered_provider(self, provider_ref: str, draft: AgentDraft) -> PluginManifest:
|
|
204
|
+
plugin_id, version = provider_ref.removeprefix("plugin://").rsplit("@", 1)
|
|
205
|
+
if plugin_id == KSADK_HARNESS_AGENT_PROVIDER_PLUGIN_ID:
|
|
206
|
+
raise StudioError(
|
|
207
|
+
"AGENT_PROVIDER_REFERENCE_RESERVED",
|
|
208
|
+
"Harness Runtime 必须选择受管理的默认 Provider 引用",
|
|
209
|
+
status_code=422,
|
|
210
|
+
field="spec.runtime.providerRef",
|
|
211
|
+
)
|
|
212
|
+
manifest = self._provider_manifests.get(provider_ref)
|
|
213
|
+
if manifest is None:
|
|
214
|
+
raise StudioError(
|
|
215
|
+
"AGENT_PROVIDER_NOT_REGISTERED",
|
|
216
|
+
"所选 AgentProvider 尚未由当前 DSH Profile 完成预检与注册",
|
|
217
|
+
status_code=422,
|
|
218
|
+
field="spec.runtime.providerRef",
|
|
219
|
+
)
|
|
220
|
+
if (
|
|
221
|
+
manifest.metadata.id != plugin_id
|
|
222
|
+
or manifest.metadata.version != version
|
|
223
|
+
):
|
|
224
|
+
raise StudioError(
|
|
225
|
+
"AGENT_PROVIDER_REGISTRATION_MISMATCH",
|
|
226
|
+
"DSH AgentProvider 注册信息与精确引用不一致",
|
|
227
|
+
status_code=409,
|
|
228
|
+
field="spec.runtime.providerRef",
|
|
229
|
+
)
|
|
230
|
+
offers = [
|
|
231
|
+
offer
|
|
232
|
+
for offer in manifest.spec.provides
|
|
233
|
+
if offer.definition == _PROVIDER_DEFINITION
|
|
234
|
+
]
|
|
235
|
+
if (
|
|
236
|
+
len(offers) != 1
|
|
237
|
+
or offers[0].slot != _PROVIDER_SLOT
|
|
238
|
+
or offers[0].mode != "unique"
|
|
239
|
+
):
|
|
240
|
+
raise StudioError(
|
|
241
|
+
"AGENT_PROVIDER_MANIFEST_INVALID",
|
|
242
|
+
"插件必须唯一提供 agent.provider/v1 的 agent.execution 槽位",
|
|
243
|
+
status_code=422,
|
|
244
|
+
field="spec.runtime.providerRef",
|
|
245
|
+
)
|
|
246
|
+
if manifest.spec.isolation != "sidecar":
|
|
247
|
+
raise StudioError(
|
|
248
|
+
"AGENT_PROVIDER_ISOLATION_INVALID",
|
|
249
|
+
"DSH AgentProvider 必须使用 sidecar 隔离",
|
|
250
|
+
status_code=422,
|
|
251
|
+
field="spec.runtime.providerRef",
|
|
252
|
+
)
|
|
253
|
+
missing_permissions = sorted(
|
|
254
|
+
set(manifest.spec.permissions)
|
|
255
|
+
- set(draft.spec.security.allowed_permissions)
|
|
256
|
+
)
|
|
257
|
+
if missing_permissions:
|
|
258
|
+
raise StudioError(
|
|
259
|
+
"AGENT_PROVIDER_PERMISSION_DENIED",
|
|
260
|
+
"Agent 未批准 Provider 请求的权限",
|
|
261
|
+
status_code=422,
|
|
262
|
+
field="spec.security.allowedPermissions",
|
|
263
|
+
details={"missingPermissions": missing_permissions},
|
|
264
|
+
)
|
|
265
|
+
return manifest
|
|
266
|
+
|
|
267
|
+
def _resource_materializations(
|
|
268
|
+
self, draft: AgentDraft
|
|
269
|
+
) -> dict[str, ResourcePluginMaterialization]:
|
|
270
|
+
materializations: dict[str, ResourcePluginMaterialization] = {}
|
|
271
|
+
groups: tuple[tuple[str, list[CapabilityBinding]], ...] = (
|
|
272
|
+
("mcp", draft.spec.bindings.mcp_servers),
|
|
273
|
+
("skill", draft.spec.bindings.skills),
|
|
274
|
+
)
|
|
275
|
+
for kind, bindings in groups:
|
|
276
|
+
for binding in bindings:
|
|
277
|
+
if not binding.enabled:
|
|
278
|
+
continue
|
|
279
|
+
# Catalog lookup is deliberate even though CompositionCompiler
|
|
280
|
+
# repeats the final kind/readiness check: it makes this product
|
|
281
|
+
# materializer fail at the authoritative Studio resource seam.
|
|
282
|
+
descriptor = self._catalog.get(binding.resource_id)
|
|
283
|
+
if descriptor.kind != kind:
|
|
284
|
+
raise StudioError(
|
|
285
|
+
"RESOURCE_KIND_INVALID",
|
|
286
|
+
f"{kind.upper()} binding 引用了错误类型的资源",
|
|
287
|
+
status_code=422,
|
|
288
|
+
field=f"spec.bindings.{kind}",
|
|
289
|
+
details={"resourceId": binding.resource_id},
|
|
290
|
+
)
|
|
291
|
+
plugin_id = (
|
|
292
|
+
WORKSPACE_MCP_PLUGIN_ID if kind == "mcp" else WORKSPACE_SKILL_PLUGIN_ID
|
|
293
|
+
)
|
|
294
|
+
materializations[binding.resource_id] = ResourcePluginMaterialization(
|
|
295
|
+
kind=kind, # type: ignore[arg-type]
|
|
296
|
+
plugin_ref=_plugin_ref(plugin_id, BUILTIN_PLUGIN_VERSION),
|
|
297
|
+
config=deepcopy(binding.config),
|
|
298
|
+
)
|
|
299
|
+
return materializations
|
|
300
|
+
|
|
301
|
+
__all__ = ["StudioPluginCompositionCompiler"]
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"""AgentKernel adapter for an immutable Studio PluginHost Build."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from ksadk.kernel.contracts import InjectPayload, SteerPayload
|
|
8
|
+
from ksadk.kernel.errors import UnsupportedControlError
|
|
9
|
+
from ksadk.runtime import (
|
|
10
|
+
BaseRuntime,
|
|
11
|
+
CancelResult,
|
|
12
|
+
CheckpointDescriptor,
|
|
13
|
+
PauseResult,
|
|
14
|
+
ResumePayload,
|
|
15
|
+
ResumeTarget,
|
|
16
|
+
RunHandle,
|
|
17
|
+
RuntimeAdapter,
|
|
18
|
+
StartRequest,
|
|
19
|
+
)
|
|
20
|
+
from ksadk.studio.run_service import StudioRunSpec
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class _PluginKernelRuntime(BaseRuntime):
|
|
24
|
+
def __init__(self, runtime_type: str) -> None:
|
|
25
|
+
self.runtime_type = runtime_type
|
|
26
|
+
|
|
27
|
+
def native_capabilities(self) -> dict[str, Any]:
|
|
28
|
+
return {
|
|
29
|
+
"provider_owned": True,
|
|
30
|
+
"runtime_adapter": True,
|
|
31
|
+
"session_continuity": {"durable": False, "scope": "process"},
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class StudioPluginKernelAdapter(RuntimeAdapter):
|
|
36
|
+
"""Lazily bind one Worker run to its profile-fenced provider activation."""
|
|
37
|
+
|
|
38
|
+
def __init__(self, plugin_runtime: Any, spec: StudioRunSpec) -> None:
|
|
39
|
+
super().__init__(_PluginKernelRuntime(spec.launch_context.runtime_type))
|
|
40
|
+
self._plugin_runtime = plugin_runtime
|
|
41
|
+
self._spec = spec
|
|
42
|
+
self._delegate: RuntimeAdapter | None = None
|
|
43
|
+
|
|
44
|
+
async def start(self, request: StartRequest) -> RunHandle:
|
|
45
|
+
delegate = await self._plugin_runtime.kernel_adapter(
|
|
46
|
+
self._spec,
|
|
47
|
+
session_id=request.session_id,
|
|
48
|
+
)
|
|
49
|
+
if not isinstance(delegate, RuntimeAdapter):
|
|
50
|
+
raise RuntimeError("AgentProvider returned an invalid RuntimeAdapter")
|
|
51
|
+
self._delegate = delegate
|
|
52
|
+
metadata = dict(request.metadata)
|
|
53
|
+
if not metadata.get("invocation_id") and metadata.get("run_id"):
|
|
54
|
+
metadata["invocation_id"] = metadata["run_id"]
|
|
55
|
+
return await delegate.start(request.model_copy(update={"metadata": metadata}))
|
|
56
|
+
|
|
57
|
+
def stream(self, handle: RunHandle): # type: ignore[no-untyped-def]
|
|
58
|
+
return self._require_delegate().stream(handle)
|
|
59
|
+
|
|
60
|
+
async def cancel(self, handle: RunHandle) -> CancelResult:
|
|
61
|
+
return await self._require_delegate().cancel(handle)
|
|
62
|
+
|
|
63
|
+
async def pause(self, handle: RunHandle) -> PauseResult:
|
|
64
|
+
return await self._require_delegate().pause(handle)
|
|
65
|
+
|
|
66
|
+
async def submit(self, handle: RunHandle, payload: ResumePayload) -> None:
|
|
67
|
+
await self._require_delegate().submit(handle, payload)
|
|
68
|
+
|
|
69
|
+
async def resume(
|
|
70
|
+
self,
|
|
71
|
+
handle: RunHandle,
|
|
72
|
+
target: ResumeTarget,
|
|
73
|
+
payload: ResumePayload | None,
|
|
74
|
+
) -> RunHandle:
|
|
75
|
+
return await self._require_delegate().resume(handle, target, payload)
|
|
76
|
+
|
|
77
|
+
async def attach(self, handle: RunHandle) -> RunHandle:
|
|
78
|
+
delegate = await self._plugin_runtime.kernel_adapter(
|
|
79
|
+
self._spec,
|
|
80
|
+
session_id=handle.session_id,
|
|
81
|
+
)
|
|
82
|
+
if not isinstance(delegate, RuntimeAdapter):
|
|
83
|
+
raise RuntimeError("AgentProvider returned an invalid RuntimeAdapter")
|
|
84
|
+
self._delegate = delegate
|
|
85
|
+
return await delegate.attach(handle)
|
|
86
|
+
|
|
87
|
+
async def steer(self, handle: RunHandle, payload: SteerPayload) -> None:
|
|
88
|
+
await self._require_delegate().steer(handle, payload)
|
|
89
|
+
|
|
90
|
+
async def inject(self, handle: RunHandle, payload: InjectPayload) -> None:
|
|
91
|
+
await self._require_delegate().inject(handle, payload)
|
|
92
|
+
|
|
93
|
+
async def checkpoint(self, handle: RunHandle) -> CheckpointDescriptor:
|
|
94
|
+
return await self._require_delegate().checkpoint(handle)
|
|
95
|
+
|
|
96
|
+
async def durable_restore(self, handle: RunHandle) -> RunHandle:
|
|
97
|
+
delegate = await self._plugin_runtime.kernel_adapter(
|
|
98
|
+
self._spec,
|
|
99
|
+
session_id=handle.session_id,
|
|
100
|
+
)
|
|
101
|
+
if not isinstance(delegate, RuntimeAdapter):
|
|
102
|
+
raise RuntimeError("AgentProvider returned an invalid RuntimeAdapter")
|
|
103
|
+
self._delegate = delegate
|
|
104
|
+
return await delegate.durable_restore(handle)
|
|
105
|
+
|
|
106
|
+
def is_handle_attached(self, handle: RunHandle) -> bool:
|
|
107
|
+
return self._delegate is not None and self._delegate.is_handle_attached(handle)
|
|
108
|
+
|
|
109
|
+
async def close(self, handle: RunHandle) -> None:
|
|
110
|
+
await self._require_delegate().close(handle)
|
|
111
|
+
|
|
112
|
+
def capabilities(self): # type: ignore[no-untyped-def]
|
|
113
|
+
# Before ``start`` the provider activation is async and not yet bound.
|
|
114
|
+
# Keep admission conservative; enqueue remains available and the live
|
|
115
|
+
# execution delegates supported controls after binding.
|
|
116
|
+
if self._delegate is None:
|
|
117
|
+
return super().capabilities()
|
|
118
|
+
return self._delegate.capabilities()
|
|
119
|
+
|
|
120
|
+
def _require_delegate(self) -> RuntimeAdapter:
|
|
121
|
+
if self._delegate is None:
|
|
122
|
+
raise UnsupportedControlError(
|
|
123
|
+
"PluginHost RuntimeAdapter has not started a provider activation"
|
|
124
|
+
)
|
|
125
|
+
return self._delegate
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
__all__ = ["StudioPluginKernelAdapter"]
|