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
|
@@ -89,6 +89,11 @@ def register_catalog_routes(
|
|
|
89
89
|
async def catalog_runtimes():
|
|
90
90
|
return {"items": studio.runtime_catalog(), "nextCursor": None}
|
|
91
91
|
|
|
92
|
+
@app.get("/api/v1/agent-providers")
|
|
93
|
+
async def agent_providers():
|
|
94
|
+
await studio.start()
|
|
95
|
+
return {"items": studio.agent_provider_catalog(), "nextCursor": None}
|
|
96
|
+
|
|
92
97
|
@app.get("/api/v1/catalog/resources/{resource_id}")
|
|
93
98
|
async def get_catalog_resource(resource_id: str):
|
|
94
99
|
return studio.catalog.get(resource_id)
|
ksadk/studio/api_contracts.py
CHANGED
|
@@ -6,8 +6,10 @@ from typing import Any, Literal
|
|
|
6
6
|
|
|
7
7
|
from pydantic import Field, SecretStr, field_validator
|
|
8
8
|
|
|
9
|
+
from ksadk.conversations.contracts import ConversationInput
|
|
9
10
|
from ksadk.evaluation import EvaluationConfig as PublicEvaluationConfig
|
|
10
11
|
from ksadk.evaluation import TargetRef
|
|
12
|
+
from ksadk.scheduler.contracts import ScheduleSpec
|
|
11
13
|
from ksadk.studio.contracts import (
|
|
12
14
|
AgentBindings,
|
|
13
15
|
AgentSpec,
|
|
@@ -78,7 +80,7 @@ class MessageInput(ContractModel):
|
|
|
78
80
|
class QuickAuthoringRequest(ContractModel):
|
|
79
81
|
name: str = Field(min_length=1, max_length=128)
|
|
80
82
|
slug: str | None = Field(default=None, min_length=1, max_length=63)
|
|
81
|
-
runtime_type: Literal["codex", "adk", "langgraph"]
|
|
83
|
+
runtime_type: Literal["codex", "adk", "langgraph", "plugin"]
|
|
82
84
|
template: Literal["blank", "research"] = "blank"
|
|
83
85
|
description: str = Field(default="", max_length=1024)
|
|
84
86
|
spec: AgentSpec | None = None
|
|
@@ -135,9 +137,40 @@ class RunRequest(ContractModel):
|
|
|
135
137
|
sandbox: str | None = None
|
|
136
138
|
|
|
137
139
|
|
|
140
|
+
class ConversationTurnRequest(ContractModel):
|
|
141
|
+
"""A capability-gated local Studio turn.
|
|
142
|
+
|
|
143
|
+
Unlike the compatibility ``RunRequest`` this request deliberately contains
|
|
144
|
+
only the provider-neutral ConversationInput. The server resolves the
|
|
145
|
+
active Build's ConversationSurface and rejects undeclared intent before it
|
|
146
|
+
reaches a framework-specific runtime request.
|
|
147
|
+
"""
|
|
148
|
+
|
|
149
|
+
input: ConversationInput
|
|
150
|
+
sandbox: str | None = None
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
class AgentScheduleRequest(ContractModel):
|
|
154
|
+
"""Browser-safe authoring input for one local ``ScheduledTask``.
|
|
155
|
+
|
|
156
|
+
Stable Agent/Build/Kernel target fields are intentionally absent. Studio
|
|
157
|
+
resolves those from the active local Runtime binding and refuses creation
|
|
158
|
+
when it cannot prove that binding.
|
|
159
|
+
"""
|
|
160
|
+
|
|
161
|
+
display_name: str = Field(min_length=1, max_length=128)
|
|
162
|
+
prompt: str = Field(min_length=1, max_length=32_768)
|
|
163
|
+
schedule: ScheduleSpec
|
|
164
|
+
enabled: bool = True
|
|
165
|
+
continuity: Literal["new_session", "continue_session"] = "new_session"
|
|
166
|
+
session_id: str | None = Field(default=None, min_length=1, max_length=256)
|
|
167
|
+
|
|
168
|
+
|
|
138
169
|
class InteractionSubmitRequest(ContractModel):
|
|
139
170
|
name: str = Field(min_length=1, max_length=64)
|
|
140
171
|
data: dict[str, Any] = Field(default_factory=dict)
|
|
172
|
+
expected_revision: int = Field(alias="expectedRevision", ge=1)
|
|
173
|
+
idempotency_key: str = Field(alias="idempotencyKey", min_length=1, max_length=256)
|
|
141
174
|
|
|
142
175
|
|
|
143
176
|
class CloudChatMessageRequest(ContractModel):
|
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
"""Studio lifecycle API for DSH plugins and the Codex compatibility bridge."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import hashlib
|
|
7
|
+
import os
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Any, Callable
|
|
10
|
+
from urllib.parse import urlencode, urlparse
|
|
11
|
+
from uuid import uuid4
|
|
12
|
+
|
|
13
|
+
from fastapi import FastAPI, Query, Response
|
|
14
|
+
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
|
15
|
+
|
|
16
|
+
from ksadk.plugins.bridges.codex import (
|
|
17
|
+
CodexAppServerPluginBridge,
|
|
18
|
+
CodexBridgeHost,
|
|
19
|
+
CodexPluginApprovalRequired,
|
|
20
|
+
CodexPluginDetail,
|
|
21
|
+
CodexPluginInventory,
|
|
22
|
+
CodexPluginNotFoundError,
|
|
23
|
+
)
|
|
24
|
+
from ksadk.plugins.bridges.dsh import (
|
|
25
|
+
DshBridgeHost,
|
|
26
|
+
DshHostUnavailableError,
|
|
27
|
+
DshPluginApprovalRequired,
|
|
28
|
+
DshPluginInventory,
|
|
29
|
+
DshPluginMutationError,
|
|
30
|
+
DshPluginNotFoundError,
|
|
31
|
+
DshProfilePluginBridge,
|
|
32
|
+
)
|
|
33
|
+
from ksadk.plugins.dsh_toolchain import DshToolchainError, DshToolchainManager
|
|
34
|
+
from ksadk.studio.errors import StudioError
|
|
35
|
+
from ksadk.studio.service import StudioService
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class CodexPluginInstallRequest(BaseModel):
|
|
39
|
+
model_config = ConfigDict(extra="forbid", populate_by_name=True)
|
|
40
|
+
marketplace_name: str | None = Field(
|
|
41
|
+
default=None, alias="marketplaceName", min_length=1, max_length=256
|
|
42
|
+
)
|
|
43
|
+
accept_undeclared_permissions: bool = Field(default=False, alias="acceptUndeclaredPermissions")
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class DshPluginInstallRequest(BaseModel):
|
|
47
|
+
model_config = ConfigDict(extra="forbid", populate_by_name=True)
|
|
48
|
+
source: str = Field(min_length=1, max_length=2048)
|
|
49
|
+
accept_host_permissions: bool = Field(default=False, alias="acceptHostPermissions")
|
|
50
|
+
|
|
51
|
+
@field_validator("source")
|
|
52
|
+
@classmethod
|
|
53
|
+
def validate_source(cls, value: str) -> str:
|
|
54
|
+
normalized = value.strip()
|
|
55
|
+
if not normalized or any(character in value for character in ("\x00", "\r", "\n")):
|
|
56
|
+
raise ValueError("source must be one package, Git URL, or absolute local path")
|
|
57
|
+
return normalized
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class DshPluginUpdateRequest(BaseModel):
|
|
61
|
+
model_config = ConfigDict(extra="forbid", populate_by_name=True)
|
|
62
|
+
accept_host_permissions: bool = Field(default=False, alias="acceptHostPermissions")
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _studio_codex_home(studio: StudioService) -> tuple[Path, str]:
|
|
66
|
+
configured = os.environ.get("KSADK_CODEX_HOME", "").strip()
|
|
67
|
+
if configured:
|
|
68
|
+
return Path(configured).expanduser(), "explicit"
|
|
69
|
+
return studio.workspace.root / ".agentkit" / "codex-home", "workspace-isolated"
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _studio_dsh_options(studio: StudioService) -> tuple[Path, str, tuple[str, ...] | None, str]:
|
|
73
|
+
configured_home = os.environ.get("KSADK_DSH_HOME", "").strip()
|
|
74
|
+
home = (
|
|
75
|
+
Path(configured_home).expanduser()
|
|
76
|
+
if configured_home
|
|
77
|
+
else studio.workspace.root / ".agentkit" / "dsh-home"
|
|
78
|
+
)
|
|
79
|
+
configured_bin = os.environ.get("KSADK_DSH_BIN", "").strip()
|
|
80
|
+
if configured_bin:
|
|
81
|
+
command = (str(Path(configured_bin).expanduser()),)
|
|
82
|
+
else:
|
|
83
|
+
try:
|
|
84
|
+
command = DshToolchainManager().require_command()
|
|
85
|
+
except (DshToolchainError, OSError, ValueError):
|
|
86
|
+
# Keep the bridge's established PATH lookup when the optional
|
|
87
|
+
# pinned toolchain has not been installed or is unusable.
|
|
88
|
+
command = None
|
|
89
|
+
profile = os.environ.get("KSADK_DSH_PROFILE", "").strip() or "studio"
|
|
90
|
+
return home, profile, command, "explicit" if configured_home else "workspace-isolated"
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _public_host(kind: str, host: Any | None, *, home_mode: str) -> dict[str, Any]:
|
|
94
|
+
codex = kind == "codex"
|
|
95
|
+
return {
|
|
96
|
+
"hostId": "codex-app-server" if codex else "deepseek-harness",
|
|
97
|
+
"available": host is not None,
|
|
98
|
+
"status": "available" if host is not None else "unavailable",
|
|
99
|
+
"version": host.version if host is not None else None,
|
|
100
|
+
"protocol": host.protocol
|
|
101
|
+
if host is not None
|
|
102
|
+
else ("codex.app-server/v1" if codex else "dsh.profile/v1"),
|
|
103
|
+
"homeMode": home_mode,
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def _public_codex_source(source: BaseModel) -> dict[str, Any]:
|
|
108
|
+
raw = source.model_dump(by_alias=True, mode="json")
|
|
109
|
+
source_type = str(raw.get("type") or "remote")
|
|
110
|
+
payload: dict[str, Any] = {"type": source_type}
|
|
111
|
+
if source_type == "local":
|
|
112
|
+
payload["name"] = Path(str(raw.get("path") or "plugin")).name or "plugin"
|
|
113
|
+
elif source_type == "git":
|
|
114
|
+
payload["name"] = Path(urlparse(str(raw.get("url") or "")).path.rstrip("/")).name
|
|
115
|
+
for key in ("refName", "sha"):
|
|
116
|
+
if raw.get(key):
|
|
117
|
+
payload[key] = raw[key]
|
|
118
|
+
elif source_type == "npm":
|
|
119
|
+
payload.update(package=raw.get("package"), version=raw.get("version"))
|
|
120
|
+
return payload
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def _public_codex_inventory(
|
|
124
|
+
inventory: CodexPluginInventory, *, host: CodexBridgeHost, home_mode: str
|
|
125
|
+
) -> dict[str, Any]:
|
|
126
|
+
return {
|
|
127
|
+
"ecosystem": "codex",
|
|
128
|
+
"integrationMode": "bridged",
|
|
129
|
+
"pluginId": inventory.plugin_id,
|
|
130
|
+
"resolvedVersion": inventory.version,
|
|
131
|
+
"distributionName": inventory.name,
|
|
132
|
+
"displayName": inventory.name,
|
|
133
|
+
"marketplaceName": inventory.marketplace_name,
|
|
134
|
+
"source": _public_codex_source(inventory.source),
|
|
135
|
+
"installed": inventory.installed,
|
|
136
|
+
"state": "enabled" if inventory.enabled else "disabled",
|
|
137
|
+
"enabled": inventory.enabled,
|
|
138
|
+
"availability": inventory.availability,
|
|
139
|
+
"permissions": [],
|
|
140
|
+
"permissionsDeclared": False,
|
|
141
|
+
"riskDisclosures": list(inventory.risk_disclosures),
|
|
142
|
+
"isolation": "host-managed",
|
|
143
|
+
"runtimeState": None,
|
|
144
|
+
"host": _public_host("codex", host, home_mode=home_mode),
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def _public_codex_detail(
|
|
149
|
+
detail: CodexPluginDetail, *, host: CodexBridgeHost, home_mode: str
|
|
150
|
+
) -> dict[str, Any]:
|
|
151
|
+
return {
|
|
152
|
+
"item": _public_codex_inventory(detail.inventory, host=host, home_mode=home_mode),
|
|
153
|
+
"description": detail.description,
|
|
154
|
+
"capabilities": {
|
|
155
|
+
"skills": list(detail.skills),
|
|
156
|
+
"mcpServers": list(detail.mcp_servers),
|
|
157
|
+
"hooks": list(detail.hooks),
|
|
158
|
+
"apps": list(detail.apps),
|
|
159
|
+
"scheduledTasks": list(detail.scheduled_tasks),
|
|
160
|
+
},
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def _public_dsh_inventory(
|
|
165
|
+
inventory: DshPluginInventory,
|
|
166
|
+
*,
|
|
167
|
+
host: DshBridgeHost,
|
|
168
|
+
home_mode: str,
|
|
169
|
+
runtime_state: dict[str, Any] | None = None,
|
|
170
|
+
) -> dict[str, Any]:
|
|
171
|
+
client = inventory.client_bundle
|
|
172
|
+
return {
|
|
173
|
+
"ecosystem": "dsh",
|
|
174
|
+
"integrationMode": "bridged",
|
|
175
|
+
"pluginId": inventory.name,
|
|
176
|
+
"resolvedVersion": inventory.version,
|
|
177
|
+
"distributionName": inventory.name,
|
|
178
|
+
"displayName": inventory.display_name,
|
|
179
|
+
"description": inventory.description,
|
|
180
|
+
"profile": inventory.profile,
|
|
181
|
+
"source": {"type": "host-profile", "name": inventory.name},
|
|
182
|
+
"installed": True,
|
|
183
|
+
"state": "enabled" if inventory.enabled else "disabled",
|
|
184
|
+
"enabled": inventory.enabled,
|
|
185
|
+
"permissions": [],
|
|
186
|
+
"permissionsDeclared": False,
|
|
187
|
+
"riskDisclosures": list(inventory.risk_disclosures),
|
|
188
|
+
"isolation": "host-managed",
|
|
189
|
+
"runtimeState": runtime_state,
|
|
190
|
+
"clientBundle": (
|
|
191
|
+
{
|
|
192
|
+
"platform": client.platform,
|
|
193
|
+
"digest": client.digest,
|
|
194
|
+
"contentBytes": client.content_bytes,
|
|
195
|
+
"external": list(client.external),
|
|
196
|
+
"inject": list(client.inject),
|
|
197
|
+
"compatible": client.compatible,
|
|
198
|
+
"incompatibilityReason": client.incompatibility_reason or None,
|
|
199
|
+
}
|
|
200
|
+
if client is not None
|
|
201
|
+
else None
|
|
202
|
+
),
|
|
203
|
+
"host": _public_host("dsh", host, home_mode=home_mode),
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def _public_dsh_client_bundle(inventory: DshPluginInventory) -> dict[str, Any] | None:
|
|
208
|
+
client = inventory.client_bundle
|
|
209
|
+
if client is None:
|
|
210
|
+
return None
|
|
211
|
+
query = urlencode({"pluginName": inventory.name, "digest": client.digest})
|
|
212
|
+
return {
|
|
213
|
+
"pluginId": inventory.name,
|
|
214
|
+
"enabled": inventory.enabled,
|
|
215
|
+
"compatible": client.compatible,
|
|
216
|
+
"digest": client.digest,
|
|
217
|
+
"contentBytes": client.content_bytes,
|
|
218
|
+
"external": list(client.external),
|
|
219
|
+
"inject": list(client.inject),
|
|
220
|
+
"incompatibilityReason": client.incompatibility_reason or None,
|
|
221
|
+
"url": f"/api/v1/plugin-ecosystems/dsh/client-bundle?{query}",
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def _codex_error(error: Exception) -> StudioError:
|
|
226
|
+
if isinstance(error, CodexPluginNotFoundError):
|
|
227
|
+
return StudioError(
|
|
228
|
+
"CODEX_PLUGIN_NOT_FOUND", "Codex 插件不存在或来源不唯一", status_code=404
|
|
229
|
+
)
|
|
230
|
+
if isinstance(error, CodexPluginApprovalRequired):
|
|
231
|
+
return StudioError(
|
|
232
|
+
"CODEX_PLUGIN_RISK_CONFIRMATION_REQUIRED",
|
|
233
|
+
"安装 Codex 插件前必须确认宿主权限风险",
|
|
234
|
+
status_code=422,
|
|
235
|
+
)
|
|
236
|
+
return StudioError("CODEX_PLUGIN_HOST_UNAVAILABLE", "Codex 插件宿主当前不可用", status_code=503)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def _dsh_error(error: Exception) -> StudioError:
|
|
240
|
+
if isinstance(error, DshPluginNotFoundError):
|
|
241
|
+
return StudioError("DSH_PLUGIN_NOT_FOUND", "DSH 插件未安装", status_code=404)
|
|
242
|
+
if isinstance(error, DshPluginApprovalRequired):
|
|
243
|
+
return StudioError(
|
|
244
|
+
"DSH_PLUGIN_RISK_CONFIRMATION_REQUIRED",
|
|
245
|
+
"安装或升级 DSH 插件前必须确认宿主权限风险",
|
|
246
|
+
status_code=422,
|
|
247
|
+
)
|
|
248
|
+
if isinstance(error, DshPluginMutationError):
|
|
249
|
+
return StudioError(
|
|
250
|
+
"DSH_PLUGIN_MUTATION_FAILED", "DSH 插件操作失败,原 Profile 已保留", status_code=409
|
|
251
|
+
)
|
|
252
|
+
if isinstance(error, (DshHostUnavailableError, OSError)):
|
|
253
|
+
return StudioError("DSH_PLUGIN_HOST_UNAVAILABLE", "DSH 插件宿主当前不可用", status_code=503)
|
|
254
|
+
return StudioError("DSH_PLUGIN_OPERATION_FAILED", "DSH 插件操作失败", status_code=422)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def register_plugin_routes(app: FastAPI, studio: StudioService) -> None:
|
|
258
|
+
"""Register only DSH Profile and Codex App Server lifecycle routes."""
|
|
259
|
+
|
|
260
|
+
codex_home, codex_mode = _studio_codex_home(studio)
|
|
261
|
+
dsh_home, dsh_profile, dsh_command, dsh_mode = _studio_dsh_options(studio)
|
|
262
|
+
|
|
263
|
+
def public_dsh(item: DshPluginInventory, host: DshBridgeHost) -> dict[str, Any]:
|
|
264
|
+
return _public_dsh_inventory(
|
|
265
|
+
item,
|
|
266
|
+
host=host,
|
|
267
|
+
home_mode=dsh_mode,
|
|
268
|
+
runtime_state=studio.dsh_provider_runtime_state(item.name),
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
def call_dsh(operation: Callable[[DshProfilePluginBridge], Any]) -> Any:
|
|
272
|
+
try:
|
|
273
|
+
with DshProfilePluginBridge(
|
|
274
|
+
dsh_home=dsh_home, profile=dsh_profile, dsh_command=dsh_command
|
|
275
|
+
) as bridge:
|
|
276
|
+
return bridge.host, operation(bridge)
|
|
277
|
+
except Exception as error:
|
|
278
|
+
raise _dsh_error(error) from None
|
|
279
|
+
|
|
280
|
+
@app.get("/api/v1/plugin-ecosystems/codex/plugins")
|
|
281
|
+
async def list_codex_plugins(
|
|
282
|
+
installed_only: bool = Query(default=False), force_refetch: bool = Query(default=False)
|
|
283
|
+
):
|
|
284
|
+
try:
|
|
285
|
+
async with CodexAppServerPluginBridge(codex_home=codex_home) as bridge:
|
|
286
|
+
items = await bridge.list_plugins(force_refetch=force_refetch)
|
|
287
|
+
visible = [item for item in items if item.installed or not installed_only]
|
|
288
|
+
return {
|
|
289
|
+
"ecosystem": "codex",
|
|
290
|
+
"integrationMode": "bridged",
|
|
291
|
+
"host": _public_host("codex", bridge.host, home_mode=codex_mode),
|
|
292
|
+
"items": [
|
|
293
|
+
_public_codex_inventory(item, host=bridge.host, home_mode=codex_mode)
|
|
294
|
+
for item in visible
|
|
295
|
+
],
|
|
296
|
+
}
|
|
297
|
+
except Exception:
|
|
298
|
+
return {
|
|
299
|
+
"ecosystem": "codex",
|
|
300
|
+
"integrationMode": "bridged",
|
|
301
|
+
"host": _public_host("codex", None, home_mode=codex_mode),
|
|
302
|
+
"items": [],
|
|
303
|
+
"error": {
|
|
304
|
+
"code": "CODEX_PLUGIN_HOST_UNAVAILABLE",
|
|
305
|
+
"message": "Codex 插件宿主当前不可用",
|
|
306
|
+
},
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
@app.get("/api/v1/plugin-ecosystems/codex/plugins/{plugin_id}")
|
|
310
|
+
async def get_codex_plugin(
|
|
311
|
+
plugin_id: str, marketplace_name: str | None = Query(default=None, max_length=256)
|
|
312
|
+
):
|
|
313
|
+
try:
|
|
314
|
+
async with CodexAppServerPluginBridge(codex_home=codex_home) as bridge:
|
|
315
|
+
detail = await bridge.read_plugin(plugin_id, marketplace_name=marketplace_name)
|
|
316
|
+
return _public_codex_detail(detail, host=bridge.host, home_mode=codex_mode)
|
|
317
|
+
except Exception as error:
|
|
318
|
+
raise _codex_error(error) from None
|
|
319
|
+
|
|
320
|
+
@app.post("/api/v1/plugin-ecosystems/codex/plugins/{plugin_id}:install")
|
|
321
|
+
async def install_codex_plugin(plugin_id: str, payload: CodexPluginInstallRequest):
|
|
322
|
+
if not payload.accept_undeclared_permissions:
|
|
323
|
+
raise _codex_error(CodexPluginApprovalRequired("approval required"))
|
|
324
|
+
try:
|
|
325
|
+
async with CodexAppServerPluginBridge(codex_home=codex_home) as bridge:
|
|
326
|
+
result = await bridge.install_plugin(
|
|
327
|
+
plugin_id,
|
|
328
|
+
marketplace_name=payload.marketplace_name,
|
|
329
|
+
accept_undeclared_permissions=True,
|
|
330
|
+
install_attempt_id=f"studio-{uuid4().hex}",
|
|
331
|
+
)
|
|
332
|
+
return {
|
|
333
|
+
"item": _public_codex_inventory(
|
|
334
|
+
result.inventory, host=bridge.host, home_mode=codex_mode
|
|
335
|
+
),
|
|
336
|
+
"authPolicy": result.auth_policy,
|
|
337
|
+
"appsNeedingAuth": list(result.apps_needing_auth),
|
|
338
|
+
}
|
|
339
|
+
except Exception as error:
|
|
340
|
+
raise _codex_error(error) from None
|
|
341
|
+
|
|
342
|
+
@app.delete("/api/v1/plugin-ecosystems/codex/plugins/{plugin_id}", status_code=204)
|
|
343
|
+
async def uninstall_codex_plugin(plugin_id: str):
|
|
344
|
+
try:
|
|
345
|
+
async with CodexAppServerPluginBridge(codex_home=codex_home) as bridge:
|
|
346
|
+
await bridge.uninstall_plugin(plugin_id)
|
|
347
|
+
return Response(status_code=204)
|
|
348
|
+
except Exception as error:
|
|
349
|
+
raise _codex_error(error) from None
|
|
350
|
+
|
|
351
|
+
@app.get("/api/v1/plugin-ecosystems/dsh/plugins")
|
|
352
|
+
async def list_dsh_plugins():
|
|
353
|
+
try:
|
|
354
|
+
host, items = await asyncio.to_thread(call_dsh, lambda bridge: bridge.list_plugins())
|
|
355
|
+
return {
|
|
356
|
+
"ecosystem": "dsh",
|
|
357
|
+
"integrationMode": "bridged",
|
|
358
|
+
"profile": dsh_profile,
|
|
359
|
+
"host": _public_host("dsh", host, home_mode=dsh_mode),
|
|
360
|
+
"items": [public_dsh(item, host) for item in items],
|
|
361
|
+
}
|
|
362
|
+
except StudioError as error:
|
|
363
|
+
return {
|
|
364
|
+
"ecosystem": "dsh",
|
|
365
|
+
"integrationMode": "bridged",
|
|
366
|
+
"profile": dsh_profile,
|
|
367
|
+
"host": _public_host("dsh", None, home_mode=dsh_mode),
|
|
368
|
+
"items": [],
|
|
369
|
+
"error": {"code": error.code, "message": error.message},
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
@app.get("/api/v1/plugin-ecosystems/dsh/profile")
|
|
373
|
+
async def get_dsh_profile_projection():
|
|
374
|
+
host, result = await asyncio.to_thread(
|
|
375
|
+
call_dsh, lambda bridge: (bridge.project_profile(), bridge.list_plugins())
|
|
376
|
+
)
|
|
377
|
+
projection, items = result
|
|
378
|
+
bundles = [
|
|
379
|
+
projected
|
|
380
|
+
for item in items
|
|
381
|
+
if item.enabled
|
|
382
|
+
for projected in [_public_dsh_client_bundle(item)]
|
|
383
|
+
if projected is not None
|
|
384
|
+
]
|
|
385
|
+
graph_hash = hashlib.sha256(projection.config_digest.encode("utf-8"))
|
|
386
|
+
for bundle in bundles:
|
|
387
|
+
for value in (str(bundle["pluginId"]), str(bundle["digest"])):
|
|
388
|
+
encoded = value.encode("utf-8")
|
|
389
|
+
graph_hash.update(f"{len(encoded)}:".encode("ascii"))
|
|
390
|
+
graph_hash.update(encoded)
|
|
391
|
+
return {
|
|
392
|
+
"host": _public_host("dsh", host, home_mode=dsh_mode),
|
|
393
|
+
"profile": projection.model_dump(mode="json", by_alias=True),
|
|
394
|
+
"clientGraphDigest": f"sha256:{graph_hash.hexdigest()}",
|
|
395
|
+
"clientBundles": bundles,
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
@app.get("/api/v1/plugin-ecosystems/dsh/client-bundle")
|
|
399
|
+
async def get_dsh_client_bundle(
|
|
400
|
+
plugin_name: str = Query(alias="pluginName", min_length=1, max_length=256),
|
|
401
|
+
digest: str = Query(pattern=r"^sha256:[0-9a-f]{64}$"),
|
|
402
|
+
):
|
|
403
|
+
_, content = await asyncio.to_thread(
|
|
404
|
+
call_dsh,
|
|
405
|
+
lambda bridge: bridge.read_client_bundle(plugin_name, expected_digest=digest),
|
|
406
|
+
)
|
|
407
|
+
return Response(
|
|
408
|
+
content=content,
|
|
409
|
+
media_type="application/javascript; charset=utf-8",
|
|
410
|
+
headers={
|
|
411
|
+
"Cache-Control": "private, max-age=31536000, immutable",
|
|
412
|
+
"ETag": f'"{digest}"',
|
|
413
|
+
"X-Content-Type-Options": "nosniff",
|
|
414
|
+
},
|
|
415
|
+
)
|
|
416
|
+
|
|
417
|
+
@app.post("/api/v1/plugin-ecosystems/dsh/plugins:install", status_code=201)
|
|
418
|
+
async def install_dsh_plugin(payload: DshPluginInstallRequest):
|
|
419
|
+
if not payload.accept_host_permissions:
|
|
420
|
+
raise _dsh_error(DshPluginApprovalRequired("approval required"))
|
|
421
|
+
host, item = await asyncio.to_thread(
|
|
422
|
+
call_dsh,
|
|
423
|
+
lambda bridge: bridge.install_plugin(payload.source, accept_host_permissions=True),
|
|
424
|
+
)
|
|
425
|
+
await studio.refresh_dsh_provider_registrations()
|
|
426
|
+
return {"item": public_dsh(item, host)}
|
|
427
|
+
|
|
428
|
+
async def mutate_dsh(plugin_name: str, operation: str):
|
|
429
|
+
def action(bridge: DshProfilePluginBridge):
|
|
430
|
+
if operation == "enable":
|
|
431
|
+
return bridge.set_enabled(plugin_name, enabled=True)
|
|
432
|
+
if operation == "disable":
|
|
433
|
+
return bridge.set_enabled(plugin_name, enabled=False)
|
|
434
|
+
if operation == "uninstall":
|
|
435
|
+
return bridge.uninstall_plugin(plugin_name)
|
|
436
|
+
return bridge.get_plugin(plugin_name)
|
|
437
|
+
|
|
438
|
+
return await asyncio.to_thread(call_dsh, action)
|
|
439
|
+
|
|
440
|
+
@app.post("/api/v1/plugin-ecosystems/dsh/plugins/{plugin_name:path}:enable")
|
|
441
|
+
async def enable_dsh_plugin(plugin_name: str):
|
|
442
|
+
host, item = await mutate_dsh(plugin_name, "enable")
|
|
443
|
+
await studio.refresh_dsh_provider_registrations()
|
|
444
|
+
return {"item": public_dsh(item, host)}
|
|
445
|
+
|
|
446
|
+
@app.post("/api/v1/plugin-ecosystems/dsh/plugins/{plugin_name:path}:disable")
|
|
447
|
+
async def disable_dsh_plugin(plugin_name: str):
|
|
448
|
+
host, item = await mutate_dsh(plugin_name, "disable")
|
|
449
|
+
await studio.refresh_dsh_provider_registrations()
|
|
450
|
+
return {"item": public_dsh(item, host)}
|
|
451
|
+
|
|
452
|
+
@app.post("/api/v1/plugin-ecosystems/dsh/plugins/{plugin_name:path}:update")
|
|
453
|
+
async def update_dsh_plugin(plugin_name: str, payload: DshPluginUpdateRequest):
|
|
454
|
+
if not payload.accept_host_permissions:
|
|
455
|
+
raise _dsh_error(DshPluginApprovalRequired("approval required"))
|
|
456
|
+
host, item = await asyncio.to_thread(
|
|
457
|
+
call_dsh,
|
|
458
|
+
lambda bridge: bridge.update_plugin(plugin_name, accept_host_permissions=True),
|
|
459
|
+
)
|
|
460
|
+
await studio.refresh_dsh_provider_registrations()
|
|
461
|
+
return {"item": public_dsh(item, host)}
|
|
462
|
+
|
|
463
|
+
@app.get("/api/v1/plugin-ecosystems/dsh/plugins/{plugin_name:path}")
|
|
464
|
+
async def get_dsh_plugin(plugin_name: str):
|
|
465
|
+
host, item = await mutate_dsh(plugin_name, "get")
|
|
466
|
+
return {"item": public_dsh(item, host)}
|
|
467
|
+
|
|
468
|
+
@app.delete("/api/v1/plugin-ecosystems/dsh/plugins/{plugin_name:path}", status_code=204)
|
|
469
|
+
async def uninstall_dsh_plugin(plugin_name: str):
|
|
470
|
+
await mutate_dsh(plugin_name, "uninstall")
|
|
471
|
+
await studio.refresh_dsh_provider_registrations()
|
|
472
|
+
return Response(status_code=204)
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
__all__ = [
|
|
476
|
+
"CodexPluginInstallRequest",
|
|
477
|
+
"DshPluginInstallRequest",
|
|
478
|
+
"DshPluginUpdateRequest",
|
|
479
|
+
"register_plugin_routes",
|
|
480
|
+
]
|