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/codex_builder.py
CHANGED
|
@@ -51,6 +51,13 @@ class CodexBuildRecord(ContractModel):
|
|
|
51
51
|
# New builds always persist a mapping (possibly empty), so run resolution
|
|
52
52
|
# never consults mutable Catalog state after the build has been created.
|
|
53
53
|
model_profiles: dict[str, dict[str, Any]] | None = None
|
|
54
|
+
# Resource ids and model names are different namespaces. Keep the exact
|
|
55
|
+
# Studio bindings separately so currentness checks never compare a model
|
|
56
|
+
# name (``glm-5.2``) with a Catalog id (``model:provider:glm-5-2:live``).
|
|
57
|
+
# ``None`` only allows older local records to be read and rejected as
|
|
58
|
+
# stale with an actionable rebuild; Phase 2 has not shipped yet, so the
|
|
59
|
+
# deployment path does not carry a legacy identity-migration branch.
|
|
60
|
+
model_profile_ids: list[str] | None = None
|
|
54
61
|
created_at: datetime
|
|
55
62
|
|
|
56
63
|
|
|
@@ -272,7 +279,12 @@ class CodexStudioBuilder:
|
|
|
272
279
|
allowed_models=snapshot.manifest.allowed_models,
|
|
273
280
|
ignore_missing=True,
|
|
274
281
|
)
|
|
275
|
-
|
|
282
|
+
model_profile_ids = self._bound_model_profile_ids(snapshot.manifest.name)
|
|
283
|
+
build_id = self._build_id(
|
|
284
|
+
snapshot.manifest_sha256,
|
|
285
|
+
model_profiles,
|
|
286
|
+
model_profile_ids=model_profile_ids,
|
|
287
|
+
)
|
|
276
288
|
try:
|
|
277
289
|
existing = self.repository.get(build_id)
|
|
278
290
|
except StudioError as exc:
|
|
@@ -337,6 +349,7 @@ class CodexStudioBuilder:
|
|
|
337
349
|
proxy_mode=current_proxy_mode(),
|
|
338
350
|
runtime_lock=lock,
|
|
339
351
|
model_profiles=model_profiles,
|
|
352
|
+
model_profile_ids=model_profile_ids,
|
|
340
353
|
created_at=datetime.now(timezone.utc),
|
|
341
354
|
)
|
|
342
355
|
return self.repository.save(record)
|
|
@@ -347,29 +360,41 @@ class CodexStudioBuilder:
|
|
|
347
360
|
return False
|
|
348
361
|
if record.model_profiles is None:
|
|
349
362
|
return True
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
363
|
+
if record.model_profile_ids is None:
|
|
364
|
+
return False
|
|
365
|
+
draft = self.drafts.get(record.agent_name) if self.drafts is not None else None
|
|
366
|
+
if draft is None:
|
|
367
|
+
return not record.model_profiles
|
|
368
|
+
|
|
369
|
+
bound_ids = set(self._bound_model_profile_ids(record.agent_name))
|
|
370
|
+
if set(record.model_profile_ids) != bound_ids:
|
|
371
|
+
return False
|
|
372
|
+
current_profiles = self._model_profile_snapshot(
|
|
373
|
+
snapshot.manifest.name,
|
|
374
|
+
allowed_models=snapshot.manifest.allowed_models,
|
|
375
|
+
ignore_missing=True,
|
|
376
|
+
)
|
|
377
|
+
# Provider-discovered Catalog entries are process-local. A restart may
|
|
378
|
+
# temporarily remove them, but the Build still owns an immutable,
|
|
379
|
+
# runnable connection snapshot and must remain deployable.
|
|
380
|
+
if bound_ids and not current_profiles:
|
|
381
|
+
return True
|
|
362
382
|
return record.model_profiles == current_profiles
|
|
363
383
|
|
|
364
384
|
@staticmethod
|
|
365
385
|
def _build_id(
|
|
366
386
|
manifest_sha256: str,
|
|
367
387
|
model_profiles: dict[str, dict[str, Any]],
|
|
388
|
+
*,
|
|
389
|
+
model_profile_ids: list[str] | None = None,
|
|
368
390
|
) -> str:
|
|
369
|
-
if not model_profiles:
|
|
391
|
+
if not model_profiles and not model_profile_ids:
|
|
370
392
|
return f"build_{manifest_sha256[:20]}"
|
|
371
393
|
fingerprint = json.dumps(
|
|
372
|
-
|
|
394
|
+
{
|
|
395
|
+
"profiles": model_profiles,
|
|
396
|
+
"resourceIds": sorted(model_profile_ids or []),
|
|
397
|
+
},
|
|
373
398
|
ensure_ascii=False,
|
|
374
399
|
sort_keys=True,
|
|
375
400
|
separators=(",", ":"),
|
|
@@ -417,10 +442,24 @@ class CodexStudioBuilder:
|
|
|
417
442
|
by_alias=True,
|
|
418
443
|
exclude_defaults=True,
|
|
419
444
|
exclude_none=True,
|
|
445
|
+
exclude={"metadata", "discovery"},
|
|
420
446
|
mode="json",
|
|
421
447
|
)
|
|
422
448
|
return profiles
|
|
423
449
|
|
|
450
|
+
def _bound_model_profile_ids(self, agent_id: str) -> list[str]:
|
|
451
|
+
if self.drafts is None:
|
|
452
|
+
return []
|
|
453
|
+
draft = self.drafts.get(agent_id)
|
|
454
|
+
if draft is None:
|
|
455
|
+
return []
|
|
456
|
+
bindings = draft.spec.bindings
|
|
457
|
+
resource_ids = list(getattr(bindings, "model_profile_ids", []) or [])
|
|
458
|
+
default_id = getattr(bindings, "model_profile_id", None)
|
|
459
|
+
if not resource_ids and default_id:
|
|
460
|
+
resource_ids = [default_id]
|
|
461
|
+
return list(dict.fromkeys(resource_ids))
|
|
462
|
+
|
|
424
463
|
@staticmethod
|
|
425
464
|
def _runtime_lock(artifact_path: Path) -> dict:
|
|
426
465
|
if artifact_path.suffix == ".zip":
|
ksadk/studio/codex_manifest.py
CHANGED
|
@@ -13,8 +13,9 @@ import yaml # type: ignore[import-untyped]
|
|
|
13
13
|
from pydantic import BaseModel, ConfigDict, Field, ValidationError, model_validator
|
|
14
14
|
|
|
15
15
|
from ksadk.builders.managed_runtime_builder import serialize_managed_runtime_manifest
|
|
16
|
-
from ksadk.studio.contracts import ContextSpec, MemorySpec
|
|
16
|
+
from ksadk.studio.contracts import ContextSpec, MemorySpec, SoulDocument
|
|
17
17
|
from ksadk.studio.errors import StudioError, not_found
|
|
18
|
+
from ksadk.studio.soul import soul_digest as compute_soul_digest
|
|
18
19
|
from ksadk.studio.workspace import Workspace
|
|
19
20
|
|
|
20
21
|
|
|
@@ -43,6 +44,12 @@ class CodexAgentManifest(BaseModel):
|
|
|
43
44
|
# Codex Runtime 最终仍消费合并后的 base_instructions;该字段用于在 AgentVersion /
|
|
44
45
|
# Build 中保留任务契约来源,避免为了运行投影而破坏 PromptSection 审计。
|
|
45
46
|
task_prompt: str | None = Field(default=None, max_length=32768)
|
|
47
|
+
# Soul remains reviewed source in the ManagedRuntime manifest. Runtime
|
|
48
|
+
# launch deterministically compiles it before ``prompt``; these provenance
|
|
49
|
+
# fields prevent a Draft-only Soul from masquerading as deployed behavior.
|
|
50
|
+
soul: SoulDocument | None = None
|
|
51
|
+
soul_source: Literal["AgentSpec.soul"] | None = None
|
|
52
|
+
soul_digest: str | None = Field(default=None, pattern=r"^sha256:[0-9a-f]{64}$")
|
|
46
53
|
skills: list[str] | None = None
|
|
47
54
|
mcp_servers: list[dict[str, Any]] | None = None
|
|
48
55
|
sandbox: str | None = None
|
|
@@ -98,6 +105,17 @@ class CodexAgentManifest(BaseModel):
|
|
|
98
105
|
mcp_seen.add(name)
|
|
99
106
|
mcp_deduped.append(server)
|
|
100
107
|
self.mcp_servers = mcp_deduped
|
|
108
|
+
if self.soul is None:
|
|
109
|
+
if self.soul_source is not None or self.soul_digest is not None:
|
|
110
|
+
raise ValueError("soul source/digest require a SoulDocument")
|
|
111
|
+
else:
|
|
112
|
+
expected_digest = compute_soul_digest(self.soul)
|
|
113
|
+
if self.soul_source not in {None, "AgentSpec.soul"}:
|
|
114
|
+
raise ValueError("soul_source must identify AgentSpec.soul")
|
|
115
|
+
if self.soul_digest not in {None, expected_digest}:
|
|
116
|
+
raise ValueError("soul_digest does not match the SoulDocument")
|
|
117
|
+
self.soul_source = "AgentSpec.soul"
|
|
118
|
+
self.soul_digest = expected_digest
|
|
101
119
|
return self
|
|
102
120
|
|
|
103
121
|
@property
|
|
@@ -113,6 +131,8 @@ def normalized_manifest_bytes(manifest: CodexAgentManifest) -> bytes:
|
|
|
113
131
|
payload["context"] = manifest.context.model_dump(mode="python", by_alias=True)
|
|
114
132
|
if manifest.memory is not None:
|
|
115
133
|
payload["memory"] = manifest.memory.model_dump(mode="python", by_alias=True)
|
|
134
|
+
if manifest.soul is not None:
|
|
135
|
+
payload["soul"] = manifest.soul.model_dump(mode="python", by_alias=True)
|
|
116
136
|
return serialize_managed_runtime_manifest(payload)
|
|
117
137
|
|
|
118
138
|
|
ksadk/studio/codex_run.py
CHANGED
|
@@ -12,9 +12,10 @@ from ksadk.configs import ModelConfig
|
|
|
12
12
|
from ksadk.runtime import RuntimeLaunchContext
|
|
13
13
|
from ksadk.studio.codex_builder import CodexBuildRepository
|
|
14
14
|
from ksadk.studio.codex_manifest import CodexAgentManifest, CodexManifestRepository
|
|
15
|
-
from ksadk.studio.contracts import ModelSpec
|
|
15
|
+
from ksadk.studio.contracts import Instructions, ModelSpec
|
|
16
16
|
from ksadk.studio.errors import StudioError
|
|
17
17
|
from ksadk.studio.run_service import StudioRunSpec
|
|
18
|
+
from ksadk.studio.soul import compose_system_instruction
|
|
18
19
|
from ksadk.studio.workspace import Workspace
|
|
19
20
|
from ksadk.tools.gateway import normalize_tool_approval_mode
|
|
20
21
|
|
|
@@ -87,18 +88,22 @@ class CodexRunSpecResolver:
|
|
|
87
88
|
if runtime_env:
|
|
88
89
|
launch_config["env"] = runtime_env
|
|
89
90
|
agent_task = str(manifest.task_prompt or "").strip()
|
|
91
|
+
agent_system = compose_system_instruction(
|
|
92
|
+
Instructions(system=manifest.prompt),
|
|
93
|
+
manifest.soul,
|
|
94
|
+
).system
|
|
90
95
|
# PCM 策略从不可变 Manifest 读取(方案 §5.1:Build 锁定后 sidecar 修改不影响旧 Build)
|
|
91
96
|
# manifest.context/memory 由 _manifest() 从 AgentSpec 写入,随 Build 进入 Artifact
|
|
92
97
|
resolved_context = manifest.context
|
|
93
98
|
resolved_memory = manifest.memory
|
|
94
|
-
base_instructions =
|
|
99
|
+
base_instructions = agent_system
|
|
95
100
|
if agent_task:
|
|
96
|
-
base_instructions = f"{
|
|
101
|
+
base_instructions = f"{agent_system}\n\n{agent_task}"
|
|
97
102
|
request_config: dict[str, Any] = {
|
|
98
103
|
# Codex 原生只接收 base_instructions,因此运行前合并;PCM 证据仍使用下面
|
|
99
104
|
# 两个独立来源生成 agent_identity / agent_policy 的分段 hash。
|
|
100
105
|
"base_instructions": base_instructions,
|
|
101
|
-
"agent_system":
|
|
106
|
+
"agent_system": agent_system,
|
|
102
107
|
"agent_task": agent_task,
|
|
103
108
|
"cwd": str(project_dir),
|
|
104
109
|
"skills": skills,
|
|
@@ -136,6 +141,13 @@ class CodexRunSpecResolver:
|
|
|
136
141
|
}
|
|
137
142
|
if approval_profile:
|
|
138
143
|
request_config["tool_approval_mode"] = approval_profile
|
|
144
|
+
if manifest.soul is not None:
|
|
145
|
+
request_config.update(
|
|
146
|
+
{
|
|
147
|
+
"soul_source": manifest.soul_source,
|
|
148
|
+
"soul_digest": manifest.soul_digest,
|
|
149
|
+
}
|
|
150
|
+
)
|
|
139
151
|
return StudioRunSpec(
|
|
140
152
|
launch_context=RuntimeLaunchContext(
|
|
141
153
|
runtime_type="codex",
|
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
"""Deterministic build-time compatibility report for AgentBundle v2.
|
|
2
|
+
|
|
3
|
+
The report contains only immutable, already-resolved facts. It deliberately
|
|
4
|
+
does not inspect environment variables, import plugin entrypoints, or claim
|
|
5
|
+
that a process is healthy. Runtime readiness remains an Activation concern.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import hashlib
|
|
11
|
+
import json
|
|
12
|
+
from collections.abc import Callable, Mapping
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
from ksadk.plugins.contracts import LockedCapability, PluginLockEntry, PluginManifest
|
|
16
|
+
from ksadk.plugins.resolver import (
|
|
17
|
+
PluginResolutionError,
|
|
18
|
+
ResolvedComposition,
|
|
19
|
+
version_satisfies,
|
|
20
|
+
)
|
|
21
|
+
from ksadk.studio.contracts import AgentDraft
|
|
22
|
+
|
|
23
|
+
COMPATIBILITY_REPORT_FORMAT = "agentkit.compatibility-report/v1"
|
|
24
|
+
CURRENT_KERNEL_API_VERSION = "1.0.0"
|
|
25
|
+
CURRENT_RUNTIME_CONTRACT = "agentkit.runtime/v1"
|
|
26
|
+
SUPPORTED_RUNTIME_PROTOCOLS = (CURRENT_RUNTIME_CONTRACT,)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def compatibility_facts_digest(
|
|
30
|
+
*,
|
|
31
|
+
draft: AgentDraft,
|
|
32
|
+
composition: ResolvedComposition | None,
|
|
33
|
+
runtime_lock: Mapping[str, Any],
|
|
34
|
+
) -> str:
|
|
35
|
+
"""Address every static input that can change a compatibility conclusion."""
|
|
36
|
+
|
|
37
|
+
payload: dict[str, Any] = {
|
|
38
|
+
"allowedPermissions": sorted(set(draft.spec.security.allowed_permissions)),
|
|
39
|
+
"runtime": {
|
|
40
|
+
"type": str(runtime_lock.get("type") or ""),
|
|
41
|
+
"version": str(runtime_lock.get("version") or ""),
|
|
42
|
+
},
|
|
43
|
+
"composition": None,
|
|
44
|
+
}
|
|
45
|
+
if composition is not None:
|
|
46
|
+
payload["composition"] = {
|
|
47
|
+
"profileDigest": composition.profile_digest,
|
|
48
|
+
"pluginLockDigest": composition.plugin_lock_digest,
|
|
49
|
+
"manifests": [
|
|
50
|
+
manifest.model_dump(
|
|
51
|
+
by_alias=True,
|
|
52
|
+
exclude_none=True,
|
|
53
|
+
mode="json",
|
|
54
|
+
)
|
|
55
|
+
for manifest in sorted(
|
|
56
|
+
composition.manifests,
|
|
57
|
+
key=lambda item: (item.metadata.id, item.metadata.version),
|
|
58
|
+
)
|
|
59
|
+
],
|
|
60
|
+
}
|
|
61
|
+
canonical = json.dumps(
|
|
62
|
+
payload,
|
|
63
|
+
ensure_ascii=False,
|
|
64
|
+
sort_keys=True,
|
|
65
|
+
separators=(",", ":"),
|
|
66
|
+
).encode("utf-8")
|
|
67
|
+
return f"sha256:{hashlib.sha256(canonical).hexdigest()}"
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def build_bundle_compatibility_report(
|
|
71
|
+
*,
|
|
72
|
+
draft: AgentDraft,
|
|
73
|
+
composition: ResolvedComposition | None,
|
|
74
|
+
runtime_lock: Mapping[str, Any],
|
|
75
|
+
resolved_digest: str,
|
|
76
|
+
facts_digest: str,
|
|
77
|
+
plugin_lock_digest: str,
|
|
78
|
+
composition_profile_digest: str | None,
|
|
79
|
+
) -> dict[str, Any]:
|
|
80
|
+
"""Project auditable static compatibility without reading host secrets."""
|
|
81
|
+
|
|
82
|
+
bundle = {
|
|
83
|
+
"bundleFormat": "agentkit.bundle/v2",
|
|
84
|
+
"compatibilityFactsDigest": facts_digest,
|
|
85
|
+
"resolvedDigest": resolved_digest,
|
|
86
|
+
"pluginLockDigest": plugin_lock_digest,
|
|
87
|
+
**(
|
|
88
|
+
{"compositionProfileDigest": composition_profile_digest}
|
|
89
|
+
if composition_profile_digest is not None
|
|
90
|
+
else {}
|
|
91
|
+
),
|
|
92
|
+
}
|
|
93
|
+
allowed_permissions = sorted(set(draft.spec.security.allowed_permissions))
|
|
94
|
+
if composition is None:
|
|
95
|
+
return _legacy_report(
|
|
96
|
+
bundle=bundle,
|
|
97
|
+
runtime_lock=runtime_lock,
|
|
98
|
+
allowed_permissions=allowed_permissions,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
manifests = {manifest.metadata.id: manifest for manifest in composition.manifests}
|
|
102
|
+
locked = {entry.id: entry for entry in composition.plugin_lock.plugins}
|
|
103
|
+
blockers: list[dict[str, str]] = []
|
|
104
|
+
|
|
105
|
+
def block(code: str, subject: str, reason: str) -> None:
|
|
106
|
+
blockers.append({"code": code, "subject": subject, "reason": reason})
|
|
107
|
+
|
|
108
|
+
permission_items: list[dict[str, Any]] = []
|
|
109
|
+
protocol_items: list[dict[str, Any]] = []
|
|
110
|
+
kernel_items: list[dict[str, str]] = []
|
|
111
|
+
capability_items: list[dict[str, str]] = []
|
|
112
|
+
|
|
113
|
+
for entry in composition.plugin_lock.plugins:
|
|
114
|
+
manifest = manifests.get(entry.id)
|
|
115
|
+
if manifest is None:
|
|
116
|
+
block(
|
|
117
|
+
"plugin_manifest_facts_missing",
|
|
118
|
+
entry.id,
|
|
119
|
+
"The exact manifest used to resolve this lock entry is unavailable.",
|
|
120
|
+
)
|
|
121
|
+
permission_items.append(
|
|
122
|
+
{
|
|
123
|
+
"pluginId": entry.id,
|
|
124
|
+
"required": [],
|
|
125
|
+
"unapproved": [],
|
|
126
|
+
"status": "blocked",
|
|
127
|
+
}
|
|
128
|
+
)
|
|
129
|
+
protocol_items.append(
|
|
130
|
+
{
|
|
131
|
+
"pluginId": entry.id,
|
|
132
|
+
"required": [],
|
|
133
|
+
"supported": list(SUPPORTED_RUNTIME_PROTOCOLS),
|
|
134
|
+
"status": "blocked",
|
|
135
|
+
}
|
|
136
|
+
)
|
|
137
|
+
kernel_items.append(
|
|
138
|
+
{
|
|
139
|
+
"pluginId": entry.id,
|
|
140
|
+
"required": "unknown",
|
|
141
|
+
"resolved": CURRENT_KERNEL_API_VERSION,
|
|
142
|
+
"status": "blocked",
|
|
143
|
+
}
|
|
144
|
+
)
|
|
145
|
+
for capability in entry.provides:
|
|
146
|
+
capability_items.append(
|
|
147
|
+
_capability_item(entry, capability, mode="unknown", status="blocked")
|
|
148
|
+
)
|
|
149
|
+
continue
|
|
150
|
+
|
|
151
|
+
_append_manifest_conclusions(
|
|
152
|
+
entry=entry,
|
|
153
|
+
manifest=manifest,
|
|
154
|
+
allowed_permissions=allowed_permissions,
|
|
155
|
+
permission_items=permission_items,
|
|
156
|
+
protocol_items=protocol_items,
|
|
157
|
+
kernel_items=kernel_items,
|
|
158
|
+
capability_items=capability_items,
|
|
159
|
+
block=block,
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
provider_ref = composition.profile.agent_provider.ref
|
|
163
|
+
provider_id, requested_version = _plugin_ref_parts(provider_ref)
|
|
164
|
+
provider_entry = locked.get(provider_id)
|
|
165
|
+
provider_manifest = manifests.get(provider_id)
|
|
166
|
+
if provider_entry is None:
|
|
167
|
+
block(
|
|
168
|
+
"agent_provider_lock_missing",
|
|
169
|
+
provider_id,
|
|
170
|
+
"The CompositionProfile AgentProvider has no exact PluginLock entry.",
|
|
171
|
+
)
|
|
172
|
+
elif provider_entry.version != requested_version:
|
|
173
|
+
block(
|
|
174
|
+
"agent_provider_version_mismatch",
|
|
175
|
+
provider_id,
|
|
176
|
+
(
|
|
177
|
+
f"Profile requests {requested_version}, but the lock resolves "
|
|
178
|
+
f"{provider_entry.version}."
|
|
179
|
+
),
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
blockers.sort(key=lambda item: (item["code"], item["subject"], item["reason"]))
|
|
183
|
+
blocked_subjects = {item["subject"] for item in blockers}
|
|
184
|
+
overall = "blocked" if blockers else "compatible"
|
|
185
|
+
provider_status = "blocked" if provider_id in blocked_subjects else "compatible"
|
|
186
|
+
|
|
187
|
+
return {
|
|
188
|
+
"format": COMPATIBILITY_REPORT_FORMAT,
|
|
189
|
+
"scope": "build-time-static",
|
|
190
|
+
"overallStatus": overall,
|
|
191
|
+
"bundle": bundle,
|
|
192
|
+
"host": {
|
|
193
|
+
"kind": _host_kind(provider_manifest),
|
|
194
|
+
"kernelApiVersion": CURRENT_KERNEL_API_VERSION,
|
|
195
|
+
"runtimeContract": CURRENT_RUNTIME_CONTRACT,
|
|
196
|
+
"readiness": "notEvaluated",
|
|
197
|
+
"status": overall,
|
|
198
|
+
},
|
|
199
|
+
"provider": _provider_conclusion(
|
|
200
|
+
provider_ref=provider_ref,
|
|
201
|
+
provider_id=provider_id,
|
|
202
|
+
requested_version=requested_version,
|
|
203
|
+
entry=provider_entry,
|
|
204
|
+
manifest=provider_manifest,
|
|
205
|
+
status=provider_status,
|
|
206
|
+
),
|
|
207
|
+
"kernelApi": sorted(kernel_items, key=lambda item: item["pluginId"]),
|
|
208
|
+
"protocols": sorted(protocol_items, key=lambda item: item["pluginId"]),
|
|
209
|
+
"permissions": {
|
|
210
|
+
"allowed": allowed_permissions,
|
|
211
|
+
"plugins": sorted(permission_items, key=lambda item: item["pluginId"]),
|
|
212
|
+
"status": (
|
|
213
|
+
"blocked"
|
|
214
|
+
if any(item["status"] == "blocked" for item in permission_items)
|
|
215
|
+
else "compatible"
|
|
216
|
+
),
|
|
217
|
+
},
|
|
218
|
+
"capabilities": sorted(
|
|
219
|
+
capability_items,
|
|
220
|
+
key=lambda item: (item["definition"], item["slot"], item["owner"]),
|
|
221
|
+
),
|
|
222
|
+
"blockingReasons": blockers,
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def _legacy_report(
|
|
227
|
+
*,
|
|
228
|
+
bundle: dict[str, Any],
|
|
229
|
+
runtime_lock: Mapping[str, Any],
|
|
230
|
+
allowed_permissions: list[str],
|
|
231
|
+
) -> dict[str, Any]:
|
|
232
|
+
runtime_type = str(runtime_lock.get("type") or "")
|
|
233
|
+
version = str(runtime_lock.get("version") or "")
|
|
234
|
+
return {
|
|
235
|
+
"format": COMPATIBILITY_REPORT_FORMAT,
|
|
236
|
+
"scope": "build-time-static",
|
|
237
|
+
"overallStatus": "compatible",
|
|
238
|
+
"bundle": bundle,
|
|
239
|
+
"host": {
|
|
240
|
+
"kind": "legacy-runtime",
|
|
241
|
+
"kernelApiVersion": CURRENT_KERNEL_API_VERSION,
|
|
242
|
+
"runtimeContract": CURRENT_RUNTIME_CONTRACT,
|
|
243
|
+
"readiness": "notEvaluated",
|
|
244
|
+
"status": "compatible",
|
|
245
|
+
},
|
|
246
|
+
"provider": {
|
|
247
|
+
"ref": None,
|
|
248
|
+
"id": runtime_type or "builtin.legacy",
|
|
249
|
+
"hostRuntime": runtime_type or "unknown",
|
|
250
|
+
"isolation": "legacy",
|
|
251
|
+
"source": "builtin",
|
|
252
|
+
"digest": None,
|
|
253
|
+
"version": {
|
|
254
|
+
"requested": version or None,
|
|
255
|
+
"resolved": version or None,
|
|
256
|
+
"status": "compatible" if version else "unknown",
|
|
257
|
+
},
|
|
258
|
+
"status": "compatible",
|
|
259
|
+
},
|
|
260
|
+
"kernelApi": [],
|
|
261
|
+
"protocols": [
|
|
262
|
+
{
|
|
263
|
+
"pluginId": runtime_type or "builtin.legacy",
|
|
264
|
+
"required": [CURRENT_RUNTIME_CONTRACT],
|
|
265
|
+
"supported": list(SUPPORTED_RUNTIME_PROTOCOLS),
|
|
266
|
+
"status": "compatible",
|
|
267
|
+
}
|
|
268
|
+
],
|
|
269
|
+
"permissions": {
|
|
270
|
+
"allowed": allowed_permissions,
|
|
271
|
+
"plugins": [],
|
|
272
|
+
"status": "compatible",
|
|
273
|
+
},
|
|
274
|
+
"capabilities": [],
|
|
275
|
+
"blockingReasons": [],
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
def _append_manifest_conclusions(
|
|
280
|
+
*,
|
|
281
|
+
entry: PluginLockEntry,
|
|
282
|
+
manifest: PluginManifest,
|
|
283
|
+
allowed_permissions: list[str],
|
|
284
|
+
permission_items: list[dict[str, Any]],
|
|
285
|
+
protocol_items: list[dict[str, Any]],
|
|
286
|
+
kernel_items: list[dict[str, str]],
|
|
287
|
+
capability_items: list[dict[str, str]],
|
|
288
|
+
block: Callable[[str, str, str], None],
|
|
289
|
+
) -> None:
|
|
290
|
+
if (
|
|
291
|
+
manifest.metadata.id != entry.id
|
|
292
|
+
or manifest.metadata.version != entry.version
|
|
293
|
+
or manifest.spec.provenance.digest != entry.digest
|
|
294
|
+
):
|
|
295
|
+
block(
|
|
296
|
+
"plugin_manifest_lock_mismatch",
|
|
297
|
+
entry.id,
|
|
298
|
+
"Resolved manifest identity or digest does not match the PluginLock entry.",
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
required_permissions = sorted(set(manifest.spec.permissions))
|
|
302
|
+
unapproved = sorted(set(required_permissions) - set(allowed_permissions))
|
|
303
|
+
permission_status = "blocked" if unapproved else "compatible"
|
|
304
|
+
permission_items.append(
|
|
305
|
+
{
|
|
306
|
+
"pluginId": entry.id,
|
|
307
|
+
"required": required_permissions,
|
|
308
|
+
"unapproved": unapproved,
|
|
309
|
+
"status": permission_status,
|
|
310
|
+
}
|
|
311
|
+
)
|
|
312
|
+
if unapproved:
|
|
313
|
+
block(
|
|
314
|
+
"plugin_permission_unapproved",
|
|
315
|
+
entry.id,
|
|
316
|
+
"Unapproved permissions: " + ", ".join(unapproved),
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
protocols = sorted(set(manifest.spec.compatibility.runtime_protocols))
|
|
320
|
+
protocol_status = (
|
|
321
|
+
"compatible" if not protocols or CURRENT_RUNTIME_CONTRACT in protocols else "blocked"
|
|
322
|
+
)
|
|
323
|
+
protocol_items.append(
|
|
324
|
+
{
|
|
325
|
+
"pluginId": entry.id,
|
|
326
|
+
"required": protocols,
|
|
327
|
+
"supported": list(SUPPORTED_RUNTIME_PROTOCOLS),
|
|
328
|
+
"status": protocol_status,
|
|
329
|
+
}
|
|
330
|
+
)
|
|
331
|
+
if protocol_status == "blocked":
|
|
332
|
+
block(
|
|
333
|
+
"runtime_protocol_incompatible",
|
|
334
|
+
entry.id,
|
|
335
|
+
f"Plugin accepts {', '.join(protocols)}, host provides {CURRENT_RUNTIME_CONTRACT}.",
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
kernel_constraint = manifest.spec.compatibility.kernel_api
|
|
339
|
+
try:
|
|
340
|
+
kernel_compatible = version_satisfies(
|
|
341
|
+
CURRENT_KERNEL_API_VERSION,
|
|
342
|
+
kernel_constraint,
|
|
343
|
+
)
|
|
344
|
+
except PluginResolutionError:
|
|
345
|
+
kernel_compatible = False
|
|
346
|
+
kernel_items.append(
|
|
347
|
+
{
|
|
348
|
+
"pluginId": entry.id,
|
|
349
|
+
"required": kernel_constraint,
|
|
350
|
+
"resolved": CURRENT_KERNEL_API_VERSION,
|
|
351
|
+
"status": "compatible" if kernel_compatible else "blocked",
|
|
352
|
+
}
|
|
353
|
+
)
|
|
354
|
+
if not kernel_compatible:
|
|
355
|
+
block(
|
|
356
|
+
"kernel_api_incompatible",
|
|
357
|
+
entry.id,
|
|
358
|
+
f"Plugin requires {kernel_constraint}, host provides {CURRENT_KERNEL_API_VERSION}.",
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
offers = {(offer.definition, offer.slot): offer for offer in manifest.spec.provides}
|
|
362
|
+
for capability in entry.provides:
|
|
363
|
+
offer = offers.get((capability.definition, capability.slot))
|
|
364
|
+
status = "compatible" if capability.owner == entry.id and offer is not None else "blocked"
|
|
365
|
+
capability_items.append(
|
|
366
|
+
_capability_item(
|
|
367
|
+
entry,
|
|
368
|
+
capability,
|
|
369
|
+
mode=offer.mode if offer is not None else "unknown",
|
|
370
|
+
status=status,
|
|
371
|
+
)
|
|
372
|
+
)
|
|
373
|
+
if status == "blocked":
|
|
374
|
+
block(
|
|
375
|
+
"capability_lock_mismatch",
|
|
376
|
+
entry.id,
|
|
377
|
+
f"Locked capability {capability.definition} at {capability.slot} "
|
|
378
|
+
"does not match the resolved manifest owner.",
|
|
379
|
+
)
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
def _capability_item(
|
|
383
|
+
entry: PluginLockEntry,
|
|
384
|
+
capability: LockedCapability,
|
|
385
|
+
*,
|
|
386
|
+
mode: str,
|
|
387
|
+
status: str,
|
|
388
|
+
) -> dict[str, str]:
|
|
389
|
+
return {
|
|
390
|
+
"definition": capability.definition,
|
|
391
|
+
"slot": capability.slot,
|
|
392
|
+
"owner": capability.owner,
|
|
393
|
+
"version": entry.version,
|
|
394
|
+
"mode": mode,
|
|
395
|
+
"status": status,
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
def _provider_conclusion(
|
|
400
|
+
*,
|
|
401
|
+
provider_ref: str,
|
|
402
|
+
provider_id: str,
|
|
403
|
+
requested_version: str,
|
|
404
|
+
entry: PluginLockEntry | None,
|
|
405
|
+
manifest: PluginManifest | None,
|
|
406
|
+
status: str,
|
|
407
|
+
) -> dict[str, Any]:
|
|
408
|
+
return {
|
|
409
|
+
"ref": provider_ref,
|
|
410
|
+
"id": provider_id,
|
|
411
|
+
"hostRuntime": manifest.spec.runtime if manifest is not None else "unknown",
|
|
412
|
+
"isolation": manifest.spec.isolation if manifest is not None else "unknown",
|
|
413
|
+
"source": entry.source if entry is not None else "unknown",
|
|
414
|
+
"digest": entry.digest if entry is not None else None,
|
|
415
|
+
"version": {
|
|
416
|
+
"requested": requested_version,
|
|
417
|
+
"resolved": entry.version if entry is not None else None,
|
|
418
|
+
"status": (
|
|
419
|
+
"compatible"
|
|
420
|
+
if entry is not None and entry.version == requested_version
|
|
421
|
+
else "blocked"
|
|
422
|
+
),
|
|
423
|
+
},
|
|
424
|
+
"status": status,
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
def _host_kind(provider: PluginManifest | None) -> str:
|
|
429
|
+
if provider is not None and provider.spec.domain == "runtime-native":
|
|
430
|
+
return "runtime-native"
|
|
431
|
+
return "composition-host"
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
def _plugin_ref_parts(value: str) -> tuple[str, str]:
|
|
435
|
+
plugin_id, version = value.removeprefix("plugin://").rsplit("@", 1)
|
|
436
|
+
return plugin_id, version
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
__all__ = [
|
|
440
|
+
"COMPATIBILITY_REPORT_FORMAT",
|
|
441
|
+
"CURRENT_KERNEL_API_VERSION",
|
|
442
|
+
"CURRENT_RUNTIME_CONTRACT",
|
|
443
|
+
"build_bundle_compatibility_report",
|
|
444
|
+
"compatibility_facts_digest",
|
|
445
|
+
]
|
ksadk/studio/compiler.py
CHANGED
|
@@ -20,6 +20,7 @@ from ksadk.studio.contracts import (
|
|
|
20
20
|
)
|
|
21
21
|
from ksadk.studio.errors import StudioError
|
|
22
22
|
from ksadk.studio.resource_catalog import LocalResourceCatalog
|
|
23
|
+
from ksadk.studio.soul import compose_system_instruction
|
|
23
24
|
from ksadk.studio.validator import AgentValidator
|
|
24
25
|
from ksadk.studio.workspace import Workspace
|
|
25
26
|
|
|
@@ -72,7 +73,11 @@ class AgentCompiler:
|
|
|
72
73
|
resolved = ResolvedAgentSpec(
|
|
73
74
|
agent_id=draft.metadata.id,
|
|
74
75
|
source_revision=draft.metadata.revision,
|
|
75
|
-
instructions=
|
|
76
|
+
instructions=compose_system_instruction(
|
|
77
|
+
materialized.spec.instructions,
|
|
78
|
+
materialized.spec.soul,
|
|
79
|
+
),
|
|
80
|
+
soul=materialized.spec.soul,
|
|
76
81
|
model=self.resolver.resolve_model(materialized.spec.model),
|
|
77
82
|
capabilities=ResolvedCapabilities(
|
|
78
83
|
skills=skills,
|