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
|
@@ -0,0 +1,529 @@
|
|
|
1
|
+
"""Compile an Agent revision into one resolvable plugin composition.
|
|
2
|
+
|
|
3
|
+
This module is the build-time boundary between Studio's editable bindings and
|
|
4
|
+
the immutable plugin graph. It deliberately does not install or execute
|
|
5
|
+
plugins. Every selected capability must already have an exact ``plugin://``
|
|
6
|
+
materialization whose manifest provides the expected Definition; the existing
|
|
7
|
+
``PluginRegistry`` then produces the authoritative lock.
|
|
8
|
+
|
|
9
|
+
In particular, ``mcp://`` and ``skill://`` are catalog identities, not active
|
|
10
|
+
PluginHost owners. Accepting them in a profile without a materializer would
|
|
11
|
+
make a Studio binding look enabled while the resolver silently omitted it.
|
|
12
|
+
This compiler therefore rejects that state before a Bundle is built.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from collections.abc import Mapping
|
|
18
|
+
from copy import deepcopy
|
|
19
|
+
from dataclasses import dataclass, field
|
|
20
|
+
from typing import Literal, Protocol
|
|
21
|
+
|
|
22
|
+
from pydantic import ValidationError
|
|
23
|
+
|
|
24
|
+
from ksadk.plugins.contracts import (
|
|
25
|
+
CompositionCapability,
|
|
26
|
+
CompositionProfile,
|
|
27
|
+
PluginReference,
|
|
28
|
+
)
|
|
29
|
+
from ksadk.plugins.resolver import (
|
|
30
|
+
PluginRegistry,
|
|
31
|
+
PluginResolutionError,
|
|
32
|
+
ResolvedComposition,
|
|
33
|
+
)
|
|
34
|
+
from ksadk.studio.contracts import AgentDraft, CapabilityBinding, ResourceDescriptor
|
|
35
|
+
from ksadk.studio.errors import StudioError
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class CompositionCompileError(ValueError):
|
|
39
|
+
"""Stable, typed failure while normalizing one Agent revision."""
|
|
40
|
+
|
|
41
|
+
def __init__(self, code: str, message: str, *, field: str | None = None) -> None:
|
|
42
|
+
super().__init__(message)
|
|
43
|
+
self.code = code
|
|
44
|
+
self.field = field
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class StudioResourceCatalog(Protocol):
|
|
48
|
+
"""Narrow catalog seam implemented by ``LocalResourceCatalog``."""
|
|
49
|
+
|
|
50
|
+
def get(self, resource: str) -> ResourceDescriptor: ...
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@dataclass(frozen=True)
|
|
54
|
+
class PluginCapabilitySelection:
|
|
55
|
+
"""One exact platform capability selected by build/deployment policy."""
|
|
56
|
+
|
|
57
|
+
ref: str
|
|
58
|
+
definition: str
|
|
59
|
+
slot: str | None = None
|
|
60
|
+
required: bool = True
|
|
61
|
+
config: Mapping[str, object] = field(default_factory=dict)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@dataclass(frozen=True)
|
|
65
|
+
class RuntimePluginSelection:
|
|
66
|
+
"""One coarse-grained AgentProvider selected by trusted product policy.
|
|
67
|
+
|
|
68
|
+
Execution semantics remain inside the provider. ``supported_strategies``
|
|
69
|
+
is admission metadata, not another executable plugin slot.
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
provider_ref: str
|
|
73
|
+
provider_config: Mapping[str, object] = field(default_factory=dict)
|
|
74
|
+
supported_strategies: frozenset[str] = frozenset({"direct"})
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@dataclass(frozen=True)
|
|
78
|
+
class ResourcePluginMaterialization:
|
|
79
|
+
"""Proof that one Studio MCP/Skill resource has an executable plugin owner."""
|
|
80
|
+
|
|
81
|
+
kind: Literal["mcp", "skill"]
|
|
82
|
+
plugin_ref: str
|
|
83
|
+
config: Mapping[str, object] = field(default_factory=dict)
|
|
84
|
+
required: bool = True
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@dataclass(frozen=True)
|
|
88
|
+
class CompositionPolicy:
|
|
89
|
+
"""Trusted build policy used to normalize an Agent revision.
|
|
90
|
+
|
|
91
|
+
The policy is supplied by the product/runtime distribution, not generated
|
|
92
|
+
by an LLM and not stored as a second editable Agent specification.
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
runtimes: Mapping[str, RuntimePluginSelection]
|
|
96
|
+
session_store: PluginCapabilitySelection
|
|
97
|
+
providers: Mapping[str, RuntimePluginSelection] = field(default_factory=dict)
|
|
98
|
+
resource_materializations: Mapping[str, ResourcePluginMaterialization] = field(
|
|
99
|
+
default_factory=dict
|
|
100
|
+
)
|
|
101
|
+
memory_providers: Mapping[str, PluginCapabilitySelection] = field(default_factory=dict)
|
|
102
|
+
context_contributors: Mapping[str, PluginCapabilitySelection] = field(
|
|
103
|
+
default_factory=dict
|
|
104
|
+
)
|
|
105
|
+
renderers: tuple[PluginCapabilitySelection, ...] = ()
|
|
106
|
+
default_runtime: str = "codex"
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class CompositionCompiler:
|
|
110
|
+
"""Normalize Studio bindings and resolve the resulting immutable graph."""
|
|
111
|
+
|
|
112
|
+
def __init__(
|
|
113
|
+
self,
|
|
114
|
+
registry: PluginRegistry,
|
|
115
|
+
catalog: StudioResourceCatalog,
|
|
116
|
+
policy: CompositionPolicy,
|
|
117
|
+
) -> None:
|
|
118
|
+
self._registry = registry
|
|
119
|
+
self._catalog = catalog
|
|
120
|
+
self._policy = policy
|
|
121
|
+
|
|
122
|
+
def compile(self, revision: AgentDraft) -> ResolvedComposition:
|
|
123
|
+
runtime_type = (
|
|
124
|
+
revision.spec.runtime.type
|
|
125
|
+
if revision.spec.runtime is not None
|
|
126
|
+
else self._policy.default_runtime
|
|
127
|
+
)
|
|
128
|
+
provider_ref = (
|
|
129
|
+
revision.spec.runtime.provider_ref
|
|
130
|
+
if revision.spec.runtime is not None
|
|
131
|
+
and revision.spec.runtime.type == "plugin"
|
|
132
|
+
else None
|
|
133
|
+
)
|
|
134
|
+
runtime = (
|
|
135
|
+
self._policy.providers.get(provider_ref)
|
|
136
|
+
if provider_ref is not None
|
|
137
|
+
else self._policy.runtimes.get(runtime_type)
|
|
138
|
+
)
|
|
139
|
+
if runtime is None:
|
|
140
|
+
raise CompositionCompileError(
|
|
141
|
+
"agent_provider_unavailable",
|
|
142
|
+
(
|
|
143
|
+
f"provider {provider_ref!r} is not installed and enabled"
|
|
144
|
+
if provider_ref is not None
|
|
145
|
+
else f"runtime {runtime_type!r} has no materialized AgentProvider"
|
|
146
|
+
),
|
|
147
|
+
field=(
|
|
148
|
+
"spec.runtime.providerRef"
|
|
149
|
+
if provider_ref is not None
|
|
150
|
+
else "spec.runtime.type"
|
|
151
|
+
),
|
|
152
|
+
)
|
|
153
|
+
if provider_ref is not None and runtime.provider_ref != provider_ref:
|
|
154
|
+
raise CompositionCompileError(
|
|
155
|
+
"agent_provider_reference_mismatch",
|
|
156
|
+
"installed AgentProvider selection does not match runtime providerRef",
|
|
157
|
+
field="spec.runtime.providerRef",
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
provider_config = deepcopy(dict(runtime.provider_config))
|
|
161
|
+
if revision.spec.runtime is not None:
|
|
162
|
+
for key, value in revision.spec.runtime.provider_config.items():
|
|
163
|
+
if key in provider_config and provider_config[key] != value:
|
|
164
|
+
raise CompositionCompileError(
|
|
165
|
+
"agent_provider_config_conflict",
|
|
166
|
+
f"AgentProvider config {key!r} conflicts with installation policy",
|
|
167
|
+
field=f"spec.runtime.providerConfig.{key}",
|
|
168
|
+
)
|
|
169
|
+
provider_config[key] = deepcopy(value)
|
|
170
|
+
provider_config["runtimeType"] = runtime_type
|
|
171
|
+
if revision.spec.runtime is not None and revision.spec.runtime.version:
|
|
172
|
+
provider_config["runtimeVersion"] = revision.spec.runtime.version
|
|
173
|
+
|
|
174
|
+
capabilities: list[CompositionCapability] = []
|
|
175
|
+
self._validate_plugin_owner(
|
|
176
|
+
runtime.provider_ref,
|
|
177
|
+
definition="agent.provider/v1",
|
|
178
|
+
slot="agent.execution",
|
|
179
|
+
field="spec.runtime.type",
|
|
180
|
+
)
|
|
181
|
+
self._validate_provider_strategy(revision, runtime)
|
|
182
|
+
self._append_selection(
|
|
183
|
+
capabilities,
|
|
184
|
+
self._policy.session_store,
|
|
185
|
+
field="policy.sessionStore",
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
if revision.spec.memory.enabled:
|
|
189
|
+
memory = self._policy.memory_providers.get(revision.spec.memory.provider_ref)
|
|
190
|
+
if memory is None:
|
|
191
|
+
raise CompositionCompileError(
|
|
192
|
+
"memory_provider_unmaterialized",
|
|
193
|
+
"enabled memory provider has no materialized plugin owner",
|
|
194
|
+
field="spec.memory.providerRef",
|
|
195
|
+
)
|
|
196
|
+
self._append_selection(
|
|
197
|
+
capabilities,
|
|
198
|
+
memory,
|
|
199
|
+
field="spec.memory.providerRef",
|
|
200
|
+
extra_config={
|
|
201
|
+
"providerRef": revision.spec.memory.provider_ref,
|
|
202
|
+
"scopes": sorted(revision.spec.memory.scopes),
|
|
203
|
+
},
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
if revision.spec.context.rollout.context_engine != "off":
|
|
207
|
+
contributor_flags = revision.spec.context.contributors.model_dump(
|
|
208
|
+
mode="python"
|
|
209
|
+
)
|
|
210
|
+
for contributor, selection in sorted(self._policy.context_contributors.items()):
|
|
211
|
+
# ``None`` means policy-owned default. Supplying the selection
|
|
212
|
+
# in this trusted policy makes it active unless the revision
|
|
213
|
+
# explicitly disables it.
|
|
214
|
+
if contributor_flags.get(contributor) is False:
|
|
215
|
+
continue
|
|
216
|
+
self._append_selection(
|
|
217
|
+
capabilities,
|
|
218
|
+
selection,
|
|
219
|
+
field=f"spec.context.contributors.{contributor}",
|
|
220
|
+
extra_config={"contributor": contributor},
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
for selection in self._policy.renderers:
|
|
224
|
+
self._append_selection(
|
|
225
|
+
capabilities,
|
|
226
|
+
selection,
|
|
227
|
+
field="policy.renderers",
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
resource_entries: dict[str, list[dict[str, object]]] = {}
|
|
231
|
+
resource_required: dict[str, bool] = {}
|
|
232
|
+
resource_definitions: dict[str, set[str]] = {}
|
|
233
|
+
resource_groups: tuple[
|
|
234
|
+
tuple[Literal["mcp", "skill"], list[CapabilityBinding]], ...
|
|
235
|
+
] = (
|
|
236
|
+
("mcp", revision.spec.bindings.mcp_servers),
|
|
237
|
+
("skill", revision.spec.bindings.skills),
|
|
238
|
+
)
|
|
239
|
+
for kind, bindings in resource_groups:
|
|
240
|
+
for binding in bindings:
|
|
241
|
+
if not binding.enabled:
|
|
242
|
+
continue
|
|
243
|
+
materialization = self._materialization(binding, expected_kind=kind)
|
|
244
|
+
definition = (
|
|
245
|
+
"mcp.connector/v1" if kind == "mcp" else "skill.source/v1"
|
|
246
|
+
)
|
|
247
|
+
self._validate_plugin_owner(
|
|
248
|
+
materialization.plugin_ref,
|
|
249
|
+
definition=definition,
|
|
250
|
+
field=f"spec.bindings.{kind}",
|
|
251
|
+
)
|
|
252
|
+
descriptor = self._catalog_resource(
|
|
253
|
+
binding.resource_id,
|
|
254
|
+
field=f"spec.bindings.{kind}",
|
|
255
|
+
)
|
|
256
|
+
if descriptor.kind != kind:
|
|
257
|
+
raise CompositionCompileError(
|
|
258
|
+
"resource_kind_mismatch",
|
|
259
|
+
f"resource {binding.resource_id!r} is not a {kind} resource",
|
|
260
|
+
field=f"spec.bindings.{kind}",
|
|
261
|
+
)
|
|
262
|
+
if descriptor.status != "ready":
|
|
263
|
+
raise CompositionCompileError(
|
|
264
|
+
"resource_not_ready",
|
|
265
|
+
f"resource {binding.resource_id!r} is {descriptor.status!r}",
|
|
266
|
+
field=f"spec.bindings.{kind}",
|
|
267
|
+
)
|
|
268
|
+
entry: dict[str, object] = {
|
|
269
|
+
"resourceId": descriptor.resource_id,
|
|
270
|
+
"kind": kind,
|
|
271
|
+
"name": descriptor.name,
|
|
272
|
+
"version": descriptor.version,
|
|
273
|
+
"digest": descriptor.digest,
|
|
274
|
+
"binding": deepcopy(binding.config),
|
|
275
|
+
"materializer": deepcopy(dict(materialization.config)),
|
|
276
|
+
}
|
|
277
|
+
resource_entries.setdefault(materialization.plugin_ref, []).append(entry)
|
|
278
|
+
resource_required[materialization.plugin_ref] = (
|
|
279
|
+
resource_required.get(materialization.plugin_ref, False)
|
|
280
|
+
or materialization.required
|
|
281
|
+
)
|
|
282
|
+
resource_definitions.setdefault(materialization.plugin_ref, set()).add(
|
|
283
|
+
definition
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
for plugin_ref, resources in sorted(resource_entries.items()):
|
|
287
|
+
definitions = resource_definitions[plugin_ref]
|
|
288
|
+
if len(definitions) > 1:
|
|
289
|
+
raise CompositionCompileError(
|
|
290
|
+
"resource_materializer_ambiguous",
|
|
291
|
+
f"plugin {plugin_ref!r} cannot materialize MCP and Skill resources "
|
|
292
|
+
"in one capability entry",
|
|
293
|
+
field="spec.bindings",
|
|
294
|
+
)
|
|
295
|
+
resources.sort(key=lambda item: (str(item["kind"]), str(item["resourceId"])))
|
|
296
|
+
capabilities.append(
|
|
297
|
+
self._capability(
|
|
298
|
+
plugin_ref,
|
|
299
|
+
required=resource_required[plugin_ref],
|
|
300
|
+
config={"resources": resources},
|
|
301
|
+
field="spec.bindings",
|
|
302
|
+
)
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
capabilities = self._merge_capabilities(capabilities)
|
|
306
|
+
policies = {
|
|
307
|
+
"network": f"policy://{revision.spec.security.network.mode}@1",
|
|
308
|
+
"tool": f"policy://{revision.spec.bindings.policy_template}@1",
|
|
309
|
+
}
|
|
310
|
+
try:
|
|
311
|
+
profile = CompositionProfile(
|
|
312
|
+
agent_provider=PluginReference(
|
|
313
|
+
ref=runtime.provider_ref,
|
|
314
|
+
config=provider_config,
|
|
315
|
+
),
|
|
316
|
+
capabilities=capabilities,
|
|
317
|
+
policies=policies,
|
|
318
|
+
ui_contributions=sorted(selection.ref for selection in self._policy.renderers),
|
|
319
|
+
)
|
|
320
|
+
except ValidationError as exc:
|
|
321
|
+
raise CompositionCompileError(
|
|
322
|
+
"composition_profile_invalid",
|
|
323
|
+
f"normalized composition profile is invalid: {exc}",
|
|
324
|
+
) from exc
|
|
325
|
+
|
|
326
|
+
dangling = [
|
|
327
|
+
item.ref
|
|
328
|
+
for item in profile.capabilities
|
|
329
|
+
if item.ref.startswith(("mcp://", "skill://"))
|
|
330
|
+
]
|
|
331
|
+
if dangling:
|
|
332
|
+
raise CompositionCompileError(
|
|
333
|
+
"resource_capability_unmaterialized",
|
|
334
|
+
f"catalog references are not active plugin owners: {', '.join(dangling)}",
|
|
335
|
+
)
|
|
336
|
+
try:
|
|
337
|
+
return self._registry.resolve(profile)
|
|
338
|
+
except PluginResolutionError as exc:
|
|
339
|
+
raise CompositionCompileError(exc.code, str(exc)) from exc
|
|
340
|
+
|
|
341
|
+
def _validate_provider_strategy(
|
|
342
|
+
self,
|
|
343
|
+
revision: AgentDraft,
|
|
344
|
+
runtime: RuntimePluginSelection,
|
|
345
|
+
) -> None:
|
|
346
|
+
strategy_name = revision.spec.execution.strategy
|
|
347
|
+
if strategy_name not in runtime.supported_strategies:
|
|
348
|
+
raise CompositionCompileError(
|
|
349
|
+
"execution_strategy_unavailable",
|
|
350
|
+
f"AgentProvider does not support execution strategy {strategy_name!r}",
|
|
351
|
+
field="spec.execution.strategy",
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
def _materialization(
|
|
355
|
+
self,
|
|
356
|
+
binding: CapabilityBinding,
|
|
357
|
+
*,
|
|
358
|
+
expected_kind: Literal["mcp", "skill"],
|
|
359
|
+
) -> ResourcePluginMaterialization:
|
|
360
|
+
materialization = self._policy.resource_materializations.get(binding.resource_id)
|
|
361
|
+
if materialization is None:
|
|
362
|
+
raise CompositionCompileError(
|
|
363
|
+
"resource_capability_unmaterialized",
|
|
364
|
+
f"resource {binding.resource_id!r} has no active plugin materialization",
|
|
365
|
+
field=f"spec.bindings.{expected_kind}",
|
|
366
|
+
)
|
|
367
|
+
if materialization.kind != expected_kind:
|
|
368
|
+
raise CompositionCompileError(
|
|
369
|
+
"resource_materializer_kind_mismatch",
|
|
370
|
+
f"resource {binding.resource_id!r} is mapped as {materialization.kind!r}",
|
|
371
|
+
field=f"spec.bindings.{expected_kind}",
|
|
372
|
+
)
|
|
373
|
+
if materialization.plugin_ref.startswith(("mcp://", "skill://")):
|
|
374
|
+
raise CompositionCompileError(
|
|
375
|
+
"resource_capability_unmaterialized",
|
|
376
|
+
f"resource {binding.resource_id!r} still points at catalog identity "
|
|
377
|
+
f"{materialization.plugin_ref!r}",
|
|
378
|
+
field=f"spec.bindings.{expected_kind}",
|
|
379
|
+
)
|
|
380
|
+
return materialization
|
|
381
|
+
|
|
382
|
+
def _catalog_resource(self, resource_id: str, *, field: str) -> ResourceDescriptor:
|
|
383
|
+
try:
|
|
384
|
+
return self._catalog.get(resource_id)
|
|
385
|
+
except (KeyError, StudioError) as exc:
|
|
386
|
+
raise CompositionCompileError(
|
|
387
|
+
"resource_not_found",
|
|
388
|
+
f"materialized resource {resource_id!r} is absent from the revision catalog",
|
|
389
|
+
field=field,
|
|
390
|
+
) from exc
|
|
391
|
+
|
|
392
|
+
def _append_selection(
|
|
393
|
+
self,
|
|
394
|
+
capabilities: list[CompositionCapability],
|
|
395
|
+
selection: PluginCapabilitySelection,
|
|
396
|
+
*,
|
|
397
|
+
field: str,
|
|
398
|
+
extra_config: Mapping[str, object] | None = None,
|
|
399
|
+
) -> None:
|
|
400
|
+
self._validate_plugin_owner(
|
|
401
|
+
selection.ref,
|
|
402
|
+
definition=selection.definition,
|
|
403
|
+
slot=selection.slot,
|
|
404
|
+
field=field,
|
|
405
|
+
)
|
|
406
|
+
config = deepcopy(dict(selection.config))
|
|
407
|
+
if extra_config:
|
|
408
|
+
overlap = set(config).intersection(extra_config)
|
|
409
|
+
if overlap:
|
|
410
|
+
raise CompositionCompileError(
|
|
411
|
+
"composition_config_conflict",
|
|
412
|
+
f"compiler-owned config keys cannot be overridden: {sorted(overlap)}",
|
|
413
|
+
field=field,
|
|
414
|
+
)
|
|
415
|
+
config.update(deepcopy(dict(extra_config)))
|
|
416
|
+
capabilities.append(
|
|
417
|
+
self._capability(
|
|
418
|
+
selection.ref,
|
|
419
|
+
required=selection.required,
|
|
420
|
+
config=config,
|
|
421
|
+
field=field,
|
|
422
|
+
)
|
|
423
|
+
)
|
|
424
|
+
|
|
425
|
+
@staticmethod
|
|
426
|
+
def _merge_capabilities(
|
|
427
|
+
capabilities: list[CompositionCapability],
|
|
428
|
+
) -> list[CompositionCapability]:
|
|
429
|
+
"""Collapse multiple Definition selections owned by one plugin.
|
|
430
|
+
|
|
431
|
+
A single plugin can legitimately provide Store, Context, and renderer
|
|
432
|
+
Definitions. ``CompositionProfile`` pins that plugin once, so the
|
|
433
|
+
compiler merges disjoint (or identical) config keys before validation
|
|
434
|
+
rather than rejecting a valid multi-capability owner as a duplicate.
|
|
435
|
+
Conflicting values remain a typed build error instead of last-write
|
|
436
|
+
wins behavior.
|
|
437
|
+
"""
|
|
438
|
+
|
|
439
|
+
merged: dict[str, tuple[bool, dict[str, object]]] = {}
|
|
440
|
+
for capability in capabilities:
|
|
441
|
+
required, config = merged.get(capability.ref, (False, {}))
|
|
442
|
+
for key, value in capability.config.items():
|
|
443
|
+
if key in config and config[key] != value:
|
|
444
|
+
raise CompositionCompileError(
|
|
445
|
+
"composition_config_conflict",
|
|
446
|
+
f"plugin {capability.ref!r} received conflicting config for {key!r}",
|
|
447
|
+
)
|
|
448
|
+
config[key] = deepcopy(value)
|
|
449
|
+
merged[capability.ref] = (required or capability.required, config)
|
|
450
|
+
return [
|
|
451
|
+
CompositionCapability(ref=ref, required=required, config=config)
|
|
452
|
+
for ref, (required, config) in sorted(merged.items())
|
|
453
|
+
]
|
|
454
|
+
|
|
455
|
+
@staticmethod
|
|
456
|
+
def _capability(
|
|
457
|
+
ref: str,
|
|
458
|
+
*,
|
|
459
|
+
required: bool,
|
|
460
|
+
config: Mapping[str, object],
|
|
461
|
+
field: str,
|
|
462
|
+
) -> CompositionCapability:
|
|
463
|
+
if ref.startswith(("mcp://", "skill://")):
|
|
464
|
+
raise CompositionCompileError(
|
|
465
|
+
"resource_capability_unmaterialized",
|
|
466
|
+
f"catalog identity {ref!r} has no active plugin owner",
|
|
467
|
+
field=field,
|
|
468
|
+
)
|
|
469
|
+
try:
|
|
470
|
+
return CompositionCapability(
|
|
471
|
+
ref=ref,
|
|
472
|
+
required=required,
|
|
473
|
+
config=deepcopy(dict(config)),
|
|
474
|
+
)
|
|
475
|
+
except ValidationError as exc:
|
|
476
|
+
raise CompositionCompileError(
|
|
477
|
+
"plugin_reference_invalid",
|
|
478
|
+
f"invalid materialized plugin reference {ref!r}: {exc}",
|
|
479
|
+
field=field,
|
|
480
|
+
) from exc
|
|
481
|
+
|
|
482
|
+
def _validate_plugin_owner(
|
|
483
|
+
self,
|
|
484
|
+
ref: str,
|
|
485
|
+
*,
|
|
486
|
+
definition: str,
|
|
487
|
+
slot: str | None = None,
|
|
488
|
+
field: str,
|
|
489
|
+
) -> None:
|
|
490
|
+
if ref.startswith(("mcp://", "skill://")):
|
|
491
|
+
raise CompositionCompileError(
|
|
492
|
+
"resource_capability_unmaterialized",
|
|
493
|
+
f"catalog identity {ref!r} has no active plugin owner",
|
|
494
|
+
field=field,
|
|
495
|
+
)
|
|
496
|
+
try:
|
|
497
|
+
parsed = PluginReference(ref=ref)
|
|
498
|
+
except ValidationError as exc:
|
|
499
|
+
raise CompositionCompileError(
|
|
500
|
+
"plugin_reference_invalid",
|
|
501
|
+
f"invalid plugin reference {ref!r}",
|
|
502
|
+
field=field,
|
|
503
|
+
) from exc
|
|
504
|
+
plugin_id, version = parsed.ref.removeprefix("plugin://").rsplit("@", 1)
|
|
505
|
+
try:
|
|
506
|
+
manifest = self._registry.manifest_for(plugin_id, version)
|
|
507
|
+
except PluginResolutionError as exc:
|
|
508
|
+
raise CompositionCompileError(exc.code, str(exc), field=field) from exc
|
|
509
|
+
if any(
|
|
510
|
+
offer.definition == definition and (slot is None or offer.slot == slot)
|
|
511
|
+
for offer in manifest.spec.provides
|
|
512
|
+
):
|
|
513
|
+
return
|
|
514
|
+
slot_suffix = f" at slot {slot!r}" if slot is not None else ""
|
|
515
|
+
raise CompositionCompileError(
|
|
516
|
+
"plugin_capability_mismatch",
|
|
517
|
+
f"plugin {ref!r} does not provide {definition!r}{slot_suffix}",
|
|
518
|
+
field=field,
|
|
519
|
+
)
|
|
520
|
+
|
|
521
|
+
|
|
522
|
+
__all__ = [
|
|
523
|
+
"CompositionCompileError",
|
|
524
|
+
"CompositionCompiler",
|
|
525
|
+
"CompositionPolicy",
|
|
526
|
+
"PluginCapabilitySelection",
|
|
527
|
+
"ResourcePluginMaterialization",
|
|
528
|
+
"RuntimePluginSelection",
|
|
529
|
+
]
|