agentengine-sdk-python 0.8.3__py3-none-any.whl → 0.8.4__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.3.dist-info → agentengine_sdk_python-0.8.4.dist-info}/METADATA +9 -8
- {agentengine_sdk_python-0.8.3.dist-info → agentengine_sdk_python-0.8.4.dist-info}/RECORD +482 -245
- ksadk/_build_provenance.json +1 -1
- ksadk/api/client.py +105 -91
- ksadk/builders/code_builder.py +36 -9
- ksadk/builders/framework_requirements.py +2 -1
- ksadk/builders/ks3_uploader.py +36 -7
- ksadk/builders/managed_runtime_builder.py +1 -0
- ksadk/cli/__init__.py +32 -3
- ksadk/cli/cmd_managed_runtime.py +13 -1
- ksadk/cli/cmd_plugin.py +6 -1
- ksadk/cli/cmd_web.py +2 -5
- ksadk/cli/runtime_bootstrap.py +23 -1
- ksadk/codex/client.py +424 -96
- ksadk/codex/projection.py +24 -0
- ksadk/codex/runtime.py +56 -298
- ksadk/common/auth.py +16 -10
- ksadk/configs/env_registry.py +29 -1
- ksadk/conversations/message_projection.py +135 -14
- ksadk/conversations/projector.py +4 -6
- ksadk/conversations/runtime_invocation.py +5 -0
- ksadk/conversations/runtime_payloads.py +1 -0
- ksadk/conversations/runtime_preparation.py +30 -27
- ksadk/conversations/runtime_resume.py +50 -2
- ksadk/conversations/runtime_stream_events.py +5 -0
- ksadk/conversations/runtime_streaming.py +25 -7
- ksadk/deployment/env_forward.py +2 -2
- ksadk/deployment/providers/serverless.py +1 -1
- ksadk/events/adapters/_codex_validators.py +18 -7
- ksadk/events/adapters/langgraph.py +15 -1
- ksadk/events/canonical_store.py +3 -1
- ksadk/events/projections.py +1 -1
- ksadk/harness/config.py +2 -2
- ksadk/harness/runtime.py +27 -27
- ksadk/harness/tools.py +38 -13
- ksadk/interaction/provider.py +1 -0
- ksadk/interaction/providers/langgraph.py +1 -0
- ksadk/kernel/bootstrap.py +28 -4
- ksadk/kernel/ingress.py +15 -2
- ksadk/kernel/sqlite_store.py +27 -0
- ksadk/kernel/store.py +3 -0
- ksadk/kernel/worker.py +65 -10
- ksadk/knowledge_base/client.py +57 -27
- ksadk/mcp_runtime/__init__.py +12 -4
- ksadk/memory/adk/backends/sdk_ltm_backend.py +161 -41
- ksadk/memory/adk/resilient_session_service.py +25 -17
- ksadk/memory/adk/short_term_memory.py +26 -9
- ksadk/memory/models.py +7 -4
- ksadk/memory/provider_resolver.py +3 -0
- ksadk/model_proxy/server.py +10 -5
- ksadk/plugins/__init__.py +4 -0
- ksadk/plugins/artifacts.py +275 -0
- ksadk/plugins/bridges/__init__.py +4 -2
- ksadk/plugins/bridges/codex.py +120 -13
- ksadk/plugins/bridges/dsh.py +340 -156
- ksadk/plugins/builtins.py +35 -36
- ksadk/plugins/bundle_security.py +28 -4
- ksadk/plugins/codex_manifest.py +983 -0
- ksadk/plugins/composition.py +8 -0
- ksadk/plugins/contracts.py +118 -0
- ksadk/plugins/delivery.py +153 -0
- ksadk/plugins/dsh_installation_digest.py +71 -0
- ksadk/plugins/dsh_toolchain.py +110 -21
- ksadk/plugins/ecosystem_probe.py +6 -6
- ksadk/plugins/host.py +102 -39
- ksadk/plugins/kernel_adapter.py +205 -0
- ksadk/plugins/providers/__init__.py +23 -0
- ksadk/plugins/providers/bundles/dsh-knowledge/cordis.patch.yml +3 -0
- ksadk/plugins/providers/bundles/dsh-knowledge/index.mjs +53 -0
- ksadk/plugins/providers/bundles/dsh-knowledge/package.json +16 -0
- ksadk/plugins/providers/bundles/dsh-memory/cordis.patch.yml +3 -0
- ksadk/plugins/providers/bundles/dsh-memory/index.mjs +175 -0
- ksadk/plugins/providers/bundles/dsh-memory/package.json +16 -0
- ksadk/plugins/providers/bundles/dsh-platform-resources/client.mjs +166 -0
- ksadk/plugins/providers/bundles/dsh-platform-resources/cordis.patch.yml +3 -0
- ksadk/plugins/providers/bundles/dsh-platform-resources/index.mjs +9 -0
- ksadk/plugins/providers/bundles/dsh-platform-resources/package.json +12 -0
- ksadk/plugins/providers/bundles/dsh-skill-center/cordis.patch.yml +3 -0
- ksadk/plugins/providers/bundles/dsh-skill-center/index.mjs +125 -0
- ksadk/plugins/providers/bundles/dsh-skill-center/package.json +16 -0
- ksadk/plugins/providers/bundles/ksadk-dsh-capability-host/cordis.patch.yml +3 -0
- ksadk/plugins/providers/bundles/ksadk-dsh-capability-host/index.mjs +870 -0
- ksadk/plugins/providers/bundles/ksadk-dsh-capability-host/package.json +27 -0
- ksadk/plugins/providers/bundles/ksadk-dsh-studio/client.js +92 -0
- ksadk/plugins/providers/bundles/ksadk-dsh-studio/index.mjs +15 -0
- ksadk/plugins/providers/bundles/ksadk-dsh-studio/package.json +7 -0
- ksadk/plugins/providers/codex.py +335 -69
- ksadk/plugins/providers/codex_native.py +368 -0
- ksadk/plugins/providers/codex_turn.py +301 -0
- ksadk/plugins/providers/dsh_capabilities.py +1389 -0
- ksadk/plugins/providers/dsh_mcp.py +467 -0
- ksadk/plugins/providers/harness.py +118 -113
- ksadk/plugins/providers/mcp_projection.py +150 -0
- ksadk/plugins/providers/platform_resources.py +657 -0
- ksadk/plugins/resolver.py +8 -1
- ksadk/resource_runtime/__init__.py +4 -0
- ksadk/resource_runtime/broker.py +616 -0
- ksadk/resource_runtime/build_artifacts.py +165 -0
- ksadk/resource_runtime/contracts.py +138 -0
- ksadk/resource_runtime/discovery_receipts.py +100 -0
- ksadk/resource_runtime/discovery_skills.py +172 -0
- ksadk/resource_runtime/errors.py +6 -0
- ksadk/resource_runtime/ipc.py +142 -0
- ksadk/resource_runtime/kernel_approval.py +165 -0
- ksadk/resource_runtime/knowledge.py +114 -0
- ksadk/resource_runtime/langgraph.py +94 -0
- ksadk/resource_runtime/leases.py +191 -0
- ksadk/resource_runtime/managed_projection.py +186 -0
- ksadk/resource_runtime/mcp_server.py +138 -0
- ksadk/resource_runtime/memory_provider.py +318 -0
- ksadk/resource_runtime/memory_receipts.py +34 -0
- ksadk/resource_runtime/operation_ledger.py +211 -0
- ksadk/resource_runtime/plugin_config.py +48 -0
- ksadk/resource_runtime/policy_authorization.py +54 -0
- ksadk/resource_runtime/process.py +110 -0
- ksadk/resource_runtime/skill_artifacts.py +153 -0
- ksadk/resource_runtime/skill_runtime.py +42 -0
- ksadk/resource_runtime/skill_workspace.py +118 -0
- ksadk/resource_runtime/skills.py +215 -0
- ksadk/resource_runtime/snapshots.py +180 -0
- ksadk/resource_runtime/socket_server.py +103 -0
- ksadk/resource_runtime/supervisor.py +380 -0
- ksadk/resource_runtime/worker.py +504 -0
- ksadk/runners/_langgraph_runner_streams.py +74 -6
- ksadk/runners/adk_runner.py +149 -11
- ksadk/runners/base_runner.py +29 -1
- ksadk/runners/langgraph_runner.py +475 -145
- ksadk/runtime/_runner_adapter/stream_mapping.py +142 -18
- ksadk/runtime/adapter.py +2 -0
- ksadk/runtime/conversation_execution.py +92 -16
- ksadk/runtime/executor.py +78 -2
- ksadk/runtime/factory.py +29 -273
- ksadk/runtime/framework_adapters.py +23 -0
- ksadk/runtime/preprocessing.py +10 -2
- ksadk/runtime/runner_adapter.py +73 -14
- ksadk/runtime_context.py +40 -2
- ksadk/sandbox/backends/e2b.py +52 -11
- ksadk/sandbox/backends/local_process.py +9 -0
- ksadk/sandbox/base.py +2 -0
- ksadk/sandbox/e2b_connection.py +66 -0
- ksadk/scheduler/sqlite_store.py +18 -0
- ksadk/server/composition.py +2 -0
- ksadk/server/factory.py +5 -0
- ksadk/server/persistence_capability.py +516 -0
- ksadk/server/routes/control.py +210 -46
- ksadk/server/routes/dependencies.py +15 -0
- ksadk/server/routes/models.py +47 -4
- ksadk/server/routes/projection.py +252 -12
- ksadk/server/routes/sessions.py +284 -107
- ksadk/server/routes/streaming.py +43 -9
- ksadk/server/static/assets/{ArtifactsPanel-10GPXIJ6.js → ArtifactsPanel-CGbWlMNh.js} +1 -1
- ksadk/server/static/assets/{CodeBlock-BXk1l-G1.js → CodeBlock-b4C7upmO.js} +3 -3
- ksadk/server/static/assets/{MathMessageMarkdown-D9uB55Oh.js → MathMessageMarkdown-DbdW5A4_.js} +4 -4
- ksadk/server/static/assets/{MermaidBlock--OEYoXIJ.js → MermaidBlock-BEBN4Ksz.js} +6 -6
- ksadk/server/static/assets/{NativeTerminalPanel-DrEe1syq.js → NativeTerminalPanel-zvL-WpAn.js} +1 -1
- ksadk/server/static/assets/{abnfDiagram-VCTEODGH-eeTFJLvo.js → abnfDiagram-VCTEODGH-BYafW7Za.js} +1 -1
- ksadk/server/static/assets/{arc-S3ZNbIAd.js → arc-bTohInsS.js} +1 -1
- ksadk/server/static/assets/architecture-7GRP2DOG-BW5UtSnx.js +1 -0
- ksadk/server/static/assets/{architectureDiagram-5GKGNRK7-CRjgEJDX.js → architectureDiagram-5GKGNRK7-Ch5Lbzsi.js} +1 -1
- ksadk/server/static/assets/{blockDiagram-NRAW4CY4-C7bsBoNH.js → blockDiagram-NRAW4CY4-kqF4MDOG.js} +1 -1
- ksadk/server/static/assets/{c4Diagram-UCG6FXSJ-BX3c33Ob.js → c4Diagram-UCG6FXSJ-8uSRIODv.js} +1 -1
- ksadk/server/static/assets/channel-CF5Up3hQ.js +1 -0
- ksadk/server/static/assets/chunk-2Q5K7J3B-KkXX47WI.js +1 -0
- ksadk/server/static/assets/{chunk-5VM5RSS4-bZ7ws-8m.js → chunk-5VM5RSS4-DkhehZDr.js} +1 -1
- ksadk/server/static/assets/{chunk-F27PBJKO-D2r0pvhY.js → chunk-F27PBJKO-BdXhtPe9.js} +1 -1
- ksadk/server/static/assets/{chunk-G27WJ6UU-CZwF3oUP.js → chunk-G27WJ6UU-DPTpvpwi.js} +1 -1
- ksadk/server/static/assets/{chunk-JWPE2WC7-DigFYCML.js → chunk-JWPE2WC7-Pqoh38el.js} +1 -1
- ksadk/server/static/assets/{chunk-LCL6LL3I-CnorGV5q.js → chunk-LCL6LL3I-DeU00qC-.js} +1 -1
- ksadk/server/static/assets/{chunk-POPQ4Y6H-CexntQA-.js → chunk-POPQ4Y6H-CzxScFkr.js} +1 -1
- ksadk/server/static/assets/{chunk-RHFEMEQ7-CHTC7UxA.js → chunk-RHFEMEQ7-DpqMx-ux.js} +1 -1
- ksadk/server/static/assets/{chunk-SVP7TREG-BC1EWt_-.js → chunk-SVP7TREG-C6t0SypQ.js} +1 -1
- ksadk/server/static/assets/{chunk-XXDRQBXY-BTG24xN0.js → chunk-XXDRQBXY-DVaeafZk.js} +1 -1
- ksadk/server/static/assets/classDiagram-DTDB5LWJ-Cz81acRQ.js +1 -0
- ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-Cz81acRQ.js +1 -0
- ksadk/server/static/assets/{cose-bilkent-JH36ORCC-CkonRdAS.js → cose-bilkent-JH36ORCC-Bf9D3tzJ.js} +1 -1
- ksadk/server/static/assets/cynefin-OW5HDTMX-DVWs8a2t.js +1 -0
- ksadk/server/static/assets/{cynefinDiagram-5FMLGOSQ-DEOCBe15.js → cynefinDiagram-5FMLGOSQ-B9cY3iTz.js} +1 -1
- ksadk/server/static/assets/{dagre-3AP2YEHR-DBThPuLa.js → dagre-3AP2YEHR-CSwlx3CB.js} +1 -1
- ksadk/server/static/assets/{dagre-ClTPrTht.js → dagre-UBpgon5q.js} +1 -1
- ksadk/server/static/assets/{diagram-S7CK7UJ4-DsZHrnpJ.js → diagram-S7CK7UJ4-C9akhN9a.js} +1 -1
- ksadk/server/static/assets/{diagram-UQ7AKVKN-BJR4nhVr.js → diagram-UQ7AKVKN-CgedhTPI.js} +1 -1
- ksadk/server/static/assets/{diagram-VSXAHHWV-xzcERX0a.js → diagram-VSXAHHWV-Cjucz5BY.js} +1 -1
- ksadk/server/static/assets/{diagram-VX7I27RA-tn2xM1xu.js → diagram-VX7I27RA-Dd4Vleyn.js} +1 -1
- ksadk/server/static/assets/{diagram-Z3DM3KII-BZPGBkw5.js → diagram-Z3DM3KII-CZ2jGtYW.js} +1 -1
- ksadk/server/static/assets/{dist-DdRBIceA.js → dist-B2_CVgKv.js} +1 -1
- ksadk/server/static/assets/{dist-Cq4OL6nO.js → dist-B3FR1SKK.js} +1 -1
- ksadk/server/static/assets/{dist-M67Hwu0n.js → dist-BIr4DSRq.js} +1 -1
- ksadk/server/static/assets/{dist-B1oWRmrH.js → dist-BgV_owcB.js} +1 -1
- ksadk/server/static/assets/{dist-DyqV4fL4.js → dist-Bj730Ib4.js} +1 -1
- ksadk/server/static/assets/{dist-DfGFrb0v.js → dist-BnaTiyzN.js} +1 -1
- ksadk/server/static/assets/{dist-C71CsujO.js → dist-C1NMAY5a.js} +1 -1
- ksadk/server/static/assets/{dist-CXpH_Rdd.js → dist-C5_ZAZsG.js} +1 -1
- ksadk/server/static/assets/{dist-DJmCPRVB.js → dist-CB9iJrvg.js} +1 -1
- ksadk/server/static/assets/{dist-DjhwGUgZ.js → dist-CFzsn6BG.js} +1 -1
- ksadk/server/static/assets/{dist-BI1qQH4n.js → dist-Cf125P_m.js} +1 -1
- ksadk/server/static/assets/{dist-8VWI-2bZ.js → dist-ClYUxfeK.js} +1 -1
- ksadk/server/static/assets/{dist-DUwKa_l6.js → dist-DFD6Qa6T.js} +1 -1
- ksadk/server/static/assets/{dist-B-46q3Hk.js → dist-DVCOWtha.js} +1 -1
- ksadk/server/static/assets/{dist-BJLUwH6W.js → dist-D_ctSS2i.js} +1 -1
- ksadk/server/static/assets/{dist-4zN1_tq5.js → dist-DiixqL0J.js} +1 -1
- ksadk/server/static/assets/{dist-B0gdk4rl.js → dist-DoVSwoDb.js} +1 -1
- ksadk/server/static/assets/{dist-Bbwqa8TG.js → dist-DvFK7p5S.js} +1 -1
- ksadk/server/static/assets/{dist-D1V3f1B4.js → dist-QfkEHOlb.js} +1 -1
- ksadk/server/static/assets/{dist-Btyo4vX4.js → dist-btbmmX5O.js} +1 -1
- ksadk/server/static/assets/{dist-u8tVH5Ak.js → dist-fBO2v5Kt.js} +1 -1
- ksadk/server/static/assets/{dist-DQAB0qn_.js → dist-ufY3F5p6.js} +1 -1
- ksadk/server/static/assets/{ebnfDiagram-PWID7BFC-DVfMsLge.js → ebnfDiagram-PWID7BFC-Ci8NqqZu.js} +1 -1
- ksadk/server/static/assets/{erDiagram-SSCWMZ5O-CWEZSYaw.js → erDiagram-SSCWMZ5O-CCIOhLZG.js} +1 -1
- ksadk/server/static/assets/eventmodeling-NTZA5JFV-CQqR2hg3.js +1 -0
- ksadk/server/static/assets/flowDiagram-A5DVABFB-DDRRbGPm.js +1 -0
- ksadk/server/static/assets/{ganttDiagram-EL5Y4UJY-TWIxoyYL.js → ganttDiagram-EL5Y4UJY-Cp_r9Hb6.js} +1 -1
- ksadk/server/static/assets/gitGraph-4MIJSDKK-fgWEf7UD.js +1 -0
- ksadk/server/static/assets/{gitGraphDiagram-WWUBYQGX-DDh2hd2S.js → gitGraphDiagram-WWUBYQGX-Dlhc8Wr8.js} +1 -1
- ksadk/server/static/assets/index-DcTML1Up.css +2 -0
- ksadk/server/static/assets/index-Dh2XHqPK.js +244 -0
- ksadk/server/static/assets/info-A6RAGUB7-BUecLTdt.js +1 -0
- ksadk/server/static/assets/{infoDiagram-RXCK75RN-CgoyWiDR.js → infoDiagram-RXCK75RN-CO0rRTRA.js} +1 -1
- ksadk/server/static/assets/{ishikawaDiagram-5VMMS53U-CyRIu_om.js → ishikawaDiagram-5VMMS53U-CHiaedSS.js} +1 -1
- ksadk/server/static/assets/{journeyDiagram-EYS64GPL-DN5JXHzN.js → journeyDiagram-EYS64GPL-CHcCIB09.js} +1 -1
- ksadk/server/static/assets/{kanban-definition-3QL26DDD-CNP3ui66.js → kanban-definition-3QL26DDD-CJ_ebBZf.js} +1 -1
- ksadk/server/static/assets/{katex-DWEzQy1d.js → katex-B4weu383.js} +1 -1
- ksadk/server/static/assets/{linear-C-qHp7d2.js → linear-V-MgYHW1.js} +1 -1
- ksadk/server/static/assets/{mermaid-parser.core-Cl-K943T.js → mermaid-parser.core-CBijEX_c.js} +2 -2
- ksadk/server/static/assets/{mindmap-definition-FBJOCRG2-D5DB5mYm.js → mindmap-definition-FBJOCRG2-Bc-pQvpp.js} +1 -1
- ksadk/server/static/assets/packet-AYTQ26CC-BeW-btFv.js +1 -0
- ksadk/server/static/assets/{pegDiagram-XKGWAZYB-BQVc9ia_.js → pegDiagram-XKGWAZYB-D7genGLl.js} +1 -1
- ksadk/server/static/assets/pie-WAS4IAKB-X0xh4SaT.js +1 -0
- ksadk/server/static/assets/{pieDiagram-E7YTZNPT-B6UCAvtY.js → pieDiagram-E7YTZNPT-Bxj32zwD.js} +1 -1
- ksadk/server/static/assets/{quadrantDiagram-AXDQQJYC-mIr2d3eb.js → quadrantDiagram-AXDQQJYC-BURv2mGh.js} +1 -1
- ksadk/server/static/assets/radar-RG4KPBEZ-DzRMSqjd.js +1 -0
- ksadk/server/static/assets/railroad-74A4TZTK-Cc44icX-.js +1 -0
- ksadk/server/static/assets/railroad-abnf-HS5TGJTU-D6S4BdV-.js +1 -0
- ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-vD3aVE2o.js +1 -0
- ksadk/server/static/assets/railroad-peg-WCYAUIDC-CYbW_b4T.js +1 -0
- ksadk/server/static/assets/{railroadDiagram-O6MQD6OU-Dt3FFDmK.js → railroadDiagram-O6MQD6OU-CCsh3avW.js} +1 -1
- ksadk/server/static/assets/{requirementDiagram-EFPCY7ZU-Cz_vQtgF.js → requirementDiagram-EFPCY7ZU-_FRRBKEd.js} +1 -1
- ksadk/server/static/assets/{sankeyDiagram-P5KCCOFB-wlO1TsH5.js → sankeyDiagram-P5KCCOFB-C-gr2o9M.js} +1 -1
- ksadk/server/static/assets/{sequenceDiagram-WJ2MYXX4-CHRbElYq.js → sequenceDiagram-WJ2MYXX4-D97NmfKg.js} +1 -1
- ksadk/server/static/assets/{sizeCapture-X5ZJPWSS-DXX54iyO.js → sizeCapture-X5ZJPWSS-DjrPC5FX.js} +1 -1
- ksadk/server/static/assets/{stateDiagram-HBIQ2CUA-Dp_lw9II.js → stateDiagram-HBIQ2CUA-DzMNg1hh.js} +1 -1
- ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-BIcjKFhF.js +1 -0
- ksadk/server/static/assets/{swimlanes-XN3QIQJK-D8O5UlLG.js → swimlanes-XN3QIQJK-Cssf_CsU.js} +1 -1
- ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-tq3K3Ybl.js +8 -0
- ksadk/server/static/assets/{timeline-definition-24CTP7MA-8mfKcxvG.js → timeline-definition-24CTP7MA-BWTHzyS1.js} +1 -1
- ksadk/server/static/assets/treeView-Q6P3EWNA-DBXt3GdU.js +1 -0
- ksadk/server/static/assets/treemap-WGGIJYW6-DrCy4E_l.js +1 -0
- ksadk/server/static/assets/{vennDiagram-4TSXK5OY-EnNl0DE7.js → vennDiagram-4TSXK5OY-BSKgJsmR.js} +1 -1
- ksadk/server/static/assets/wardley-WFR3VGLG-CefhOliM.js +1 -0
- ksadk/server/static/assets/{wardleyDiagram-VM6X3IG4-DBu5fbYr.js → wardleyDiagram-VM6X3IG4-eflHNoaZ.js} +1 -1
- ksadk/server/static/assets/{xychartDiagram-S5SC5T6Z-BSVXs4IY.js → xychartDiagram-S5SC5T6Z-eYqrQ-v4.js} +1 -1
- ksadk/server/static/index.html +2 -2
- ksadk/session_context.py +66 -0
- ksadk/sessions/__init__.py +11 -21
- ksadk/sessions/_local_service_sync.py +263 -1
- ksadk/sessions/base.py +176 -0
- ksadk/sessions/errors.py +4 -0
- ksadk/sessions/in_memory.py +309 -19
- ksadk/sessions/local_service.py +83 -1
- ksadk/sessions/persistence.py +275 -0
- ksadk/sessions/postgres_service.py +358 -0
- ksadk/sessions/resilience.py +8 -0
- ksadk/sessions/resilient.py +362 -4
- ksadk/sessions/topology.py +135 -0
- ksadk/skills/models.py +26 -4
- ksadk/skills/package_store.py +186 -38
- ksadk/skills/runtime/agent.py +31 -6
- ksadk/skills/runtime/artifact_delivery.py +139 -0
- ksadk/skills/runtime/backends/e2b.py +98 -6
- ksadk/skills/runtime/backends/local.py +73 -8
- ksadk/skills/runtime/base.py +3 -0
- ksadk/skills/runtime/executor.py +2 -0
- ksadk/skills/runtime/loader.py +10 -2
- ksadk/skills/runtime/pinned.py +114 -0
- ksadk/skills/runtime/request.py +31 -0
- ksadk/skills/service_client.py +167 -28
- ksadk/studio/api.py +224 -42
- ksadk/studio/api_catalog_routes.py +18 -0
- ksadk/studio/api_plugin_routes.py +526 -95
- ksadk/studio/api_resource_connections.py +183 -0
- ksadk/studio/authoring_coordinator.py +19 -14
- ksadk/studio/builder.py +76 -0
- ksadk/studio/cloud.py +342 -104
- ksadk/studio/cloud_shared_web.py +565 -0
- ksadk/studio/codex_agent_service.py +128 -26
- ksadk/studio/codex_builder.py +241 -2
- ksadk/studio/codex_credentials.py +90 -0
- ksadk/studio/codex_manifest.py +31 -4
- ksadk/studio/codex_plugin_store.py +746 -0
- ksadk/studio/codex_provider_build.py +231 -0
- ksadk/studio/codex_run.py +184 -25
- ksadk/studio/compatibility_report.py +12 -1
- ksadk/studio/compiler.py +78 -14
- ksadk/studio/contracts.py +132 -6
- ksadk/studio/dsh_application.py +137 -0
- ksadk/studio/dsh_capability_service.py +1107 -0
- ksadk/studio/dsh_models.py +59 -0
- ksadk/studio/dsh_provider_registration.py +320 -13
- ksadk/studio/hosted_kernel.py +88 -13
- ksadk/studio/mcp_runtime.py +11 -3
- ksadk/studio/model_client.py +2 -2
- ksadk/studio/plugin_composition.py +190 -23
- ksadk/studio/plugin_kernel_adapter.py +12 -112
- ksadk/studio/plugin_runtime.py +224 -45
- ksadk/studio/resource_authority.py +637 -0
- ksadk/studio/resource_binding_validation.py +77 -0
- ksadk/studio/resource_build_admission.py +196 -0
- ksadk/studio/resource_build_materializer.py +149 -0
- ksadk/studio/resource_catalog.py +143 -2
- ksadk/studio/resource_connections.py +220 -0
- ksadk/studio/run_service.py +462 -52
- ksadk/studio/runtime_source.py +15 -7
- ksadk/studio/scheduler_assistant.py +317 -0
- ksadk/studio/scheduler_runtime.py +9 -0
- ksadk/studio/scheduler_service.py +3 -0
- ksadk/studio/service.py +490 -44
- ksadk/studio/shared_web.py +446 -62
- ksadk/studio/static/assets/CodeBlock-DCUUY0PL-BLjA7kbS.js +41 -0
- ksadk/studio/static/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- ksadk/studio/static/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- ksadk/studio/static/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- ksadk/studio/static/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- ksadk/studio/static/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- ksadk/studio/static/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- ksadk/studio/static/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- ksadk/studio/static/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- ksadk/studio/static/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- ksadk/studio/static/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- ksadk/studio/static/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- ksadk/studio/static/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- ksadk/studio/static/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- ksadk/studio/static/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- ksadk/studio/static/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- ksadk/studio/static/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- ksadk/studio/static/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- ksadk/studio/static/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- ksadk/studio/static/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- ksadk/studio/static/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- ksadk/studio/static/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- ksadk/studio/static/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- ksadk/studio/static/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- ksadk/studio/static/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- ksadk/studio/static/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- ksadk/studio/static/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- ksadk/studio/static/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- ksadk/studio/static/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- ksadk/studio/static/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- ksadk/studio/static/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- ksadk/studio/static/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- ksadk/studio/static/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- ksadk/studio/static/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- ksadk/studio/static/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- ksadk/studio/static/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- ksadk/studio/static/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- ksadk/studio/static/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- ksadk/studio/static/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- ksadk/studio/static/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- ksadk/studio/static/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- ksadk/studio/static/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- ksadk/studio/static/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- ksadk/studio/static/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- ksadk/studio/static/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- ksadk/studio/static/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- ksadk/studio/static/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- ksadk/studio/static/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- ksadk/studio/static/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- ksadk/studio/static/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- ksadk/studio/static/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- ksadk/studio/static/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- ksadk/studio/static/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- ksadk/studio/static/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- ksadk/studio/static/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- ksadk/studio/static/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- ksadk/studio/static/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- ksadk/studio/static/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- ksadk/studio/static/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- ksadk/studio/static/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- ksadk/studio/static/assets/MathMessageMarkdown-CBcDrAw--BEOyPC3w.css +1 -0
- ksadk/studio/static/assets/MathMessageMarkdown-CBcDrAw--CUYIXwgI.js +8 -0
- ksadk/studio/static/assets/MermaidBlock-DBFTztfQ-BTYKWEbD.js +44 -0
- ksadk/studio/static/assets/PrismRenderer-wiXRHURw.js +3 -0
- ksadk/studio/static/assets/abnfDiagram-VCTEODGH-CLETGjKq.js +1 -0
- ksadk/studio/static/assets/arc-Pry-7G1_.js +1 -0
- ksadk/studio/static/assets/architecture-7GRP2DOG-hXMiO_AU.js +1 -0
- ksadk/studio/static/assets/architectureDiagram-5GKGNRK7-B5EQysk6.js +36 -0
- ksadk/studio/static/assets/array-BifhSqXX.js +1 -0
- ksadk/studio/static/assets/blockDiagram-I7D4REHJ-CFmPl1de.js +129 -0
- ksadk/studio/static/assets/c4Diagram-7LVT6UL2-BRrGu8qt.js +38 -0
- ksadk/studio/static/assets/channel-BqO-gtEw.js +1 -0
- ksadk/studio/static/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
- ksadk/studio/static/assets/chunk-4HAMMTFA-D220vUtq.js +62 -0
- ksadk/studio/static/assets/chunk-5VM5RSS4-ZNzvKenW.js +15 -0
- ksadk/studio/static/assets/chunk-75Z2AOVW-C8lLv_qc.js +2 -0
- ksadk/studio/static/assets/chunk-DU6HZSFF-C4DtVpCu.js +128 -0
- ksadk/studio/static/assets/chunk-F27PBJKO-Cpw14SNG.js +1 -0
- ksadk/studio/static/assets/chunk-FOHPRMQF-DHwB1DNv.js +161 -0
- ksadk/studio/static/assets/chunk-GMAD6QVW-DiQA-u2N.js +72 -0
- ksadk/studio/static/assets/chunk-GVQU2GXP-DUdNBUCi.js +1 -0
- ksadk/studio/static/assets/chunk-IMKFNOWR-BSlbjT_b.js +231 -0
- ksadk/studio/static/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
- ksadk/studio/static/assets/chunk-L3NEJ4N5-Db8Ab22W.js +1 -0
- ksadk/studio/static/assets/chunk-OSK3NFVY-M2m6G3j4.js +10 -0
- ksadk/studio/static/assets/chunk-P2QGCYS3-DezaQxiK.js +1 -0
- ksadk/studio/static/assets/chunk-POPQ4Y6H-DOpufJ3t.js +1 -0
- ksadk/studio/static/assets/chunk-PWAF6VOD-CfLb1gSc.js +1 -0
- ksadk/studio/static/assets/chunk-SHT3W25Y-DAyIVp5H.js +168 -0
- ksadk/studio/static/assets/chunk-SVP7TREG-DulomOrS.js +88 -0
- ksadk/studio/static/assets/chunk-TICWLB2K-bHJYoflj.js +206 -0
- ksadk/studio/static/assets/chunk-XXDRQBXY-7PcdR2B1.js +1 -0
- ksadk/studio/static/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
- ksadk/studio/static/assets/classDiagram-ZZMXUADV-D_bW8JjA.js +1 -0
- ksadk/studio/static/assets/classDiagram-v2-VYDZK3BY-D_bW8JjA.js +1 -0
- ksadk/studio/static/assets/cose-bilkent-JH36ORCC-snL88wkX.js +1 -0
- ksadk/studio/static/assets/cynefin-OW5HDTMX-Bd1YhRo1.js +1 -0
- ksadk/studio/static/assets/cynefinDiagram-5FMLGOSQ-BBrIG_mI.js +62 -0
- ksadk/studio/static/assets/cytoscape.esm-CGd-uY3x.js +321 -0
- ksadk/studio/static/assets/dagre-GXQ25YYZ-DtF1nGdY.js +4 -0
- ksadk/studio/static/assets/dagre-PrKaheQc.js +1 -0
- ksadk/studio/static/assets/defaultLocale-BFoDCU3G.js +1 -0
- ksadk/studio/static/assets/diagram-S7CK7UJ4-0BZ98mya.js +30 -0
- ksadk/studio/static/assets/diagram-UQ7AKVKN-6mLKEo6L.js +41 -0
- ksadk/studio/static/assets/diagram-VSXAHHWV-CJBIaiZ2.js +3 -0
- ksadk/studio/static/assets/diagram-VX7I27RA-BohLEE1C.js +24 -0
- ksadk/studio/static/assets/diagram-Z3DM3KII-D8KIGonG.js +24 -0
- ksadk/studio/static/assets/dist-v5Q1xZ2K.js +1 -0
- ksadk/studio/static/assets/ebnfDiagram-PWID7BFC-C99HU61t.js +1 -0
- ksadk/studio/static/assets/erDiagram-RLTQ6QDP-DLGry2Ap.js +99 -0
- ksadk/studio/static/assets/eventmodeling-NTZA5JFV-B1_5Ac8j.js +1 -0
- ksadk/studio/static/assets/flowDiagram-HODETNUW-DD5hmicn.js +1 -0
- ksadk/studio/static/assets/ganttDiagram-EL5Y4UJY-BPJrVLSG.js +292 -0
- ksadk/studio/static/assets/gitGraph-4MIJSDKK-Cy_ZQBGi.js +1 -0
- ksadk/studio/static/assets/gitGraphDiagram-WWUBYQGX-CZCUz4MT.js +106 -0
- ksadk/studio/static/assets/graphlib-DS17s2tU.js +1 -0
- ksadk/studio/static/assets/index-CeHL9ARV.css +2 -0
- ksadk/studio/static/assets/index-D9QEcVpL.js +320 -0
- ksadk/studio/static/assets/info-A6RAGUB7-DBzDQB_I.js +1 -0
- ksadk/studio/static/assets/infoDiagram-27XIBGKW-B-sq07Hi.js +2 -0
- ksadk/studio/static/assets/init-C-OQMol4.js +1 -0
- ksadk/studio/static/assets/ishikawaDiagram-5VMMS53U-CljI2wyf.js +70 -0
- ksadk/studio/static/assets/journeyDiagram-3NMN7TZE-D50Fo2sL.js +139 -0
- ksadk/studio/static/assets/kanban-definition-UXKFOSKX-DimfOTam.js +89 -0
- ksadk/studio/static/assets/katex-DhON-x74.js +257 -0
- ksadk/studio/static/assets/line-CX5BOOUP.js +1 -0
- ksadk/studio/static/assets/linear-BCxN9JLv.js +1 -0
- ksadk/studio/static/assets/mermaid-parser.core-BdCz8fkS.js +7 -0
- ksadk/studio/static/assets/mindmap-definition-YA3MSWOX-Bizzqy5R.js +96 -0
- ksadk/studio/static/assets/ordinal-BDEzSJ7C.js +1 -0
- ksadk/studio/static/assets/packet-AYTQ26CC-gPln-_kG.js +1 -0
- ksadk/studio/static/assets/path-fybaL0A-.js +1 -0
- ksadk/studio/static/assets/pegDiagram-XKGWAZYB-Dy3fB-gW.js +1 -0
- ksadk/studio/static/assets/pie-WAS4IAKB-qZdHMr7B.js +1 -0
- ksadk/studio/static/assets/pieDiagram-E7YTZNPT-B9mrFSDF.js +39 -0
- ksadk/studio/static/assets/quadrantDiagram-AXDQQJYC-NzUfCbMR.js +7 -0
- ksadk/studio/static/assets/radar-RG4KPBEZ-BZlnaea9.js +1 -0
- ksadk/studio/static/assets/railroad-74A4TZTK-Ce3__H9c.js +1 -0
- ksadk/studio/static/assets/railroad-abnf-HS5TGJTU-DqQn7EzD.js +1 -0
- ksadk/studio/static/assets/railroad-ebnf-LZEXJU2U-B55kCA8F.js +1 -0
- ksadk/studio/static/assets/railroad-peg-WCYAUIDC-DfQnvkHd.js +1 -0
- ksadk/studio/static/assets/railroadDiagram-O6MQD6OU-DnhMjZCk.js +1 -0
- ksadk/studio/static/assets/requirementDiagram-BXWQKSXE-BF3d103U.js +84 -0
- ksadk/studio/static/assets/rolldown-runtime-Dy4uBu1J-DK3Fl9T5.js +1 -0
- ksadk/studio/static/assets/rough.esm-Dy-Kn_BL.js +1 -0
- ksadk/studio/static/assets/sankeyDiagram-P5KCCOFB-Bo-JTwt0.js +40 -0
- ksadk/studio/static/assets/sequenceDiagram-WJ2MYXX4-Dh4wZtUm.js +162 -0
- ksadk/studio/static/assets/sizeCapture-INFHLROL-B0uUizjq.js +1 -0
- ksadk/studio/static/assets/src-SFn9St9H.js +1 -0
- ksadk/studio/static/assets/stateDiagram-D77RDMKH-DH774G6d.js +1 -0
- ksadk/studio/static/assets/stateDiagram-v2-MP3YSRHH-DZvVWPBo.js +1 -0
- ksadk/studio/static/assets/swimlanes-42K2YHIH-Bl13OvTX.js +1 -0
- ksadk/studio/static/assets/swimlanesDiagram-VR7AAH4N-BnFOTALJ.js +8 -0
- ksadk/studio/static/assets/timeline-definition-24CTP7MA-DxmSSjRB.js +120 -0
- ksadk/studio/static/assets/treeView-Q6P3EWNA-D5Nn9Swz.js +1 -0
- ksadk/studio/static/assets/treemap-WGGIJYW6-CgHgnQhE.js +1 -0
- ksadk/studio/static/assets/vennDiagram-4TSXK5OY-B9QEXcJq.js +34 -0
- ksadk/studio/static/assets/wardley-WFR3VGLG-DXrK2RRY.js +1 -0
- ksadk/studio/static/assets/wardleyDiagram-VM6X3IG4-Ba1AOWoe.js +78 -0
- ksadk/studio/static/assets/xychartDiagram-S5SC5T6Z-Cr5pt5Y-.js +7 -0
- ksadk/studio/static/index.html +2 -2
- ksadk/version.py +1 -1
- ksadk/server/static/assets/architecture-7GRP2DOG-Dk9nRQ6-.js +0 -1
- ksadk/server/static/assets/channel-s354Yo6o.js +0 -1
- ksadk/server/static/assets/chunk-2Q5K7J3B-CDpPpKR5.js +0 -1
- ksadk/server/static/assets/classDiagram-DTDB5LWJ-Dd0nucl9.js +0 -1
- ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-Dd0nucl9.js +0 -1
- ksadk/server/static/assets/cynefin-OW5HDTMX-BBlT4uMf.js +0 -1
- ksadk/server/static/assets/eventmodeling-NTZA5JFV-Dr5okd8V.js +0 -1
- ksadk/server/static/assets/flowDiagram-A5DVABFB-VEO-cVcO.js +0 -1
- ksadk/server/static/assets/gitGraph-4MIJSDKK-CKiKY9Cf.js +0 -1
- ksadk/server/static/assets/index-B2k_urY8.js +0 -241
- ksadk/server/static/assets/index-ILPt6IWF.css +0 -2
- ksadk/server/static/assets/info-A6RAGUB7-ubA4Nm_p.js +0 -1
- ksadk/server/static/assets/packet-AYTQ26CC-C7R3NUlK.js +0 -1
- ksadk/server/static/assets/pie-WAS4IAKB-BIT6qjr3.js +0 -1
- ksadk/server/static/assets/radar-RG4KPBEZ-l5noef9X.js +0 -1
- ksadk/server/static/assets/railroad-74A4TZTK-Baea6ZvM.js +0 -1
- ksadk/server/static/assets/railroad-abnf-HS5TGJTU-OKn8zZnU.js +0 -1
- ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-DdKAKC4l.js +0 -1
- ksadk/server/static/assets/railroad-peg-WCYAUIDC-Bds8udlG.js +0 -1
- ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-5b-8o2iS.js +0 -1
- ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-uf6WPRA4.js +0 -8
- ksadk/server/static/assets/treeView-Q6P3EWNA-CK5CSrSO.js +0 -1
- ksadk/server/static/assets/treemap-WGGIJYW6-Ch2BKgAM.js +0 -1
- ksadk/server/static/assets/wardley-WFR3VGLG-YW3Q0ml_.js +0 -1
- ksadk/studio/static/assets/PrismRenderer-IYN-ffww.js +0 -3
- ksadk/studio/static/assets/index-DXs1Eq4M.css +0 -1
- ksadk/studio/static/assets/index-DeDqwTsD.js +0 -283
- {agentengine_sdk_python-0.8.3.dist-info → agentengine_sdk_python-0.8.4.dist-info}/WHEEL +0 -0
- {agentengine_sdk_python-0.8.3.dist-info → agentengine_sdk_python-0.8.4.dist-info}/entry_points.txt +0 -0
- {agentengine_sdk_python-0.8.3.dist-info → agentengine_sdk_python-0.8.4.dist-info}/licenses/LICENSE +0 -0
- {agentengine_sdk_python-0.8.3.dist-info → agentengine_sdk_python-0.8.4.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"""Async owner of one resource worker subprocess and its private pipes."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import os
|
|
7
|
+
import struct
|
|
8
|
+
import sys
|
|
9
|
+
import time
|
|
10
|
+
|
|
11
|
+
from ksadk.resource_runtime.ipc import MAX_FRAME_BYTES, ResourceRequest, decode_body, encode_frame
|
|
12
|
+
from ksadk.resource_runtime.leases import ResourceScope
|
|
13
|
+
from ksadk.resource_runtime.worker import WorkerInitialization
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ResourceWorkerError(RuntimeError):
|
|
17
|
+
def __init__(self):
|
|
18
|
+
super().__init__("RESOURCE_WORKER_UNAVAILABLE")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class ResourceWorkerProcess:
|
|
22
|
+
def __init__(self, process: asyncio.subprocess.Process):
|
|
23
|
+
self._process = process
|
|
24
|
+
self._lock = asyncio.Lock()
|
|
25
|
+
|
|
26
|
+
@classmethod
|
|
27
|
+
async def start(cls, initialization: WorkerInitialization) -> ResourceWorkerProcess:
|
|
28
|
+
if os.name != "posix":
|
|
29
|
+
raise RuntimeError("RESOURCE_IPC_UNSUPPORTED")
|
|
30
|
+
# No inherited credential, proxy, Python path or runtime selection vars.
|
|
31
|
+
env = {
|
|
32
|
+
key: os.environ[key]
|
|
33
|
+
for key in ("PATH", "LANG", "LC_ALL", "SYSTEMROOT")
|
|
34
|
+
if key in os.environ
|
|
35
|
+
}
|
|
36
|
+
process = await asyncio.create_subprocess_exec(
|
|
37
|
+
sys.executable,
|
|
38
|
+
"-I",
|
|
39
|
+
"-m",
|
|
40
|
+
"ksadk.resource_runtime.worker",
|
|
41
|
+
stdin=asyncio.subprocess.PIPE,
|
|
42
|
+
stdout=asyncio.subprocess.PIPE,
|
|
43
|
+
stderr=asyncio.subprocess.DEVNULL,
|
|
44
|
+
env=env,
|
|
45
|
+
)
|
|
46
|
+
worker = cls(process)
|
|
47
|
+
try:
|
|
48
|
+
response = await asyncio.wait_for(worker._exchange(initialization.pipe_payload()), 30)
|
|
49
|
+
if response != {"status": "ready"}:
|
|
50
|
+
raise ResourceWorkerError()
|
|
51
|
+
return worker
|
|
52
|
+
except BaseException:
|
|
53
|
+
await worker.aclose()
|
|
54
|
+
raise
|
|
55
|
+
|
|
56
|
+
async def invoke(self, request: ResourceRequest, scope: ResourceScope) -> dict:
|
|
57
|
+
async with self._lock:
|
|
58
|
+
remaining = request.deadline / 1000 - time.time()
|
|
59
|
+
if remaining <= 0:
|
|
60
|
+
raise ResourceWorkerError()
|
|
61
|
+
try:
|
|
62
|
+
response = await asyncio.wait_for(
|
|
63
|
+
self._exchange(
|
|
64
|
+
{
|
|
65
|
+
"request": request.model_dump(by_alias=True, mode="json"),
|
|
66
|
+
"scope": scope.model_dump(by_alias=True, mode="json"),
|
|
67
|
+
}
|
|
68
|
+
),
|
|
69
|
+
remaining,
|
|
70
|
+
)
|
|
71
|
+
if response.get("requestId") != request.request_id or "result" not in response:
|
|
72
|
+
raise ResourceWorkerError()
|
|
73
|
+
return response["result"]
|
|
74
|
+
except BaseException:
|
|
75
|
+
# A lost response cannot be correlated with a subsequent request.
|
|
76
|
+
# Terminate instead of reusing or silently restarting the worker.
|
|
77
|
+
await self.aclose()
|
|
78
|
+
raise
|
|
79
|
+
|
|
80
|
+
async def _exchange(self, payload: dict) -> dict:
|
|
81
|
+
if self._process.returncode is not None:
|
|
82
|
+
raise ResourceWorkerError()
|
|
83
|
+
source, target = self._process.stdout, self._process.stdin
|
|
84
|
+
assert source is not None and target is not None
|
|
85
|
+
target.write(encode_frame(payload))
|
|
86
|
+
await target.drain()
|
|
87
|
+
prefix = await source.readexactly(4)
|
|
88
|
+
(size,) = struct.unpack("!I", prefix)
|
|
89
|
+
if not 0 < size <= MAX_FRAME_BYTES:
|
|
90
|
+
raise ResourceWorkerError()
|
|
91
|
+
return decode_body(await source.readexactly(size))
|
|
92
|
+
|
|
93
|
+
async def aclose(self) -> None:
|
|
94
|
+
if self._process.returncode is None:
|
|
95
|
+
try:
|
|
96
|
+
self._process.kill()
|
|
97
|
+
except ProcessLookupError:
|
|
98
|
+
pass
|
|
99
|
+
await self._process.wait()
|
|
100
|
+
|
|
101
|
+
@property
|
|
102
|
+
def pid(self) -> int:
|
|
103
|
+
return self._process.pid
|
|
104
|
+
|
|
105
|
+
@property
|
|
106
|
+
def is_running(self) -> bool:
|
|
107
|
+
return self._process.returncode is None
|
|
108
|
+
|
|
109
|
+
async def wait_stopped(self) -> int:
|
|
110
|
+
return await self._process.wait()
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"""Host-owned Skill result publication in the existing durable operation ledger.
|
|
2
|
+
|
|
3
|
+
This is local runtime storage, not a new upload service. Callers must admit the
|
|
4
|
+
current resource lease before every read; opaque IDs do not confer authority.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import base64
|
|
10
|
+
import hashlib
|
|
11
|
+
import json
|
|
12
|
+
import tempfile
|
|
13
|
+
import zipfile
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
|
|
16
|
+
from pydantic import Field
|
|
17
|
+
|
|
18
|
+
from ksadk.plugins.contracts import PluginContractModel
|
|
19
|
+
from ksadk.resource_runtime.operation_ledger import OperationConflict, OperationLedger
|
|
20
|
+
from ksadk.skills.runtime.artifact_delivery import export_artifacts
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class SkillArtifactQuery(PluginContractModel):
|
|
24
|
+
operation_id: str = Field(strict=True, pattern=r"^[0-9a-f]{64}$")
|
|
25
|
+
artifact_id: str = Field(strict=True, pattern=r"^[0-9a-f]{64}$")
|
|
26
|
+
offset: int = Field(default=0, strict=True, ge=0, le=20 * 1024 * 1024)
|
|
27
|
+
max_bytes: int = Field(default=32768, strict=True, ge=1, le=32768)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class SkillArtifactReceipts:
|
|
31
|
+
def __init__(self, ledger: OperationLedger):
|
|
32
|
+
self.ledger = ledger
|
|
33
|
+
with ledger._connect() as connection:
|
|
34
|
+
connection.execute(
|
|
35
|
+
"CREATE TABLE IF NOT EXISTS skill_results ("
|
|
36
|
+
"operation_id TEXT PRIMARY KEY, payload TEXT NOT NULL)"
|
|
37
|
+
)
|
|
38
|
+
connection.execute(
|
|
39
|
+
"CREATE TABLE IF NOT EXISTS skill_artifacts ("
|
|
40
|
+
"operation_id TEXT NOT NULL, id TEXT NOT NULL, data BLOB NOT NULL, "
|
|
41
|
+
"PRIMARY KEY(operation_id, id))"
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
def _owned(self, operation_id: str, authority_digest: str):
|
|
45
|
+
receipt = self.ledger.lookup(
|
|
46
|
+
operation_id, authority_digest=authority_digest, operation="execute_skills"
|
|
47
|
+
)
|
|
48
|
+
if receipt is None:
|
|
49
|
+
raise OperationConflict("RESOURCE_OPERATION_NOT_FOUND")
|
|
50
|
+
return receipt
|
|
51
|
+
|
|
52
|
+
def result(self, operation_id: str, *, authority_digest: str) -> dict | None:
|
|
53
|
+
self._owned(operation_id, authority_digest)
|
|
54
|
+
with self.ledger._connect() as connection:
|
|
55
|
+
row = connection.execute(
|
|
56
|
+
"SELECT payload FROM skill_results WHERE operation_id=?", (operation_id,)
|
|
57
|
+
).fetchone()
|
|
58
|
+
return None if row is None else json.loads(row[0])
|
|
59
|
+
|
|
60
|
+
def publish(
|
|
61
|
+
self,
|
|
62
|
+
operation_id: str,
|
|
63
|
+
*,
|
|
64
|
+
authority_digest: str,
|
|
65
|
+
root: Path,
|
|
66
|
+
paths: list[str],
|
|
67
|
+
status: str,
|
|
68
|
+
) -> dict:
|
|
69
|
+
"""Atomically retain validated bytes and a terminal receipt; never execute.
|
|
70
|
+
|
|
71
|
+
root is supplied by the trusted activation owner, not by the Worker result.
|
|
72
|
+
A repeated publication returns the original receipt and does not read paths.
|
|
73
|
+
"""
|
|
74
|
+
self._owned(operation_id, authority_digest)
|
|
75
|
+
if status not in {"succeeded", "failed"}:
|
|
76
|
+
raise ValueError("Only confirmed execution outcomes may be published")
|
|
77
|
+
existing = self.result(operation_id, authority_digest=authority_digest)
|
|
78
|
+
if existing is not None:
|
|
79
|
+
return existing
|
|
80
|
+
with tempfile.TemporaryDirectory(prefix="ksadk-artifact-publication-") as temporary:
|
|
81
|
+
archive_path = Path(temporary) / "artifacts.zip"
|
|
82
|
+
export_artifacts(paths, root, archive_path)
|
|
83
|
+
with zipfile.ZipFile(archive_path) as archive, self.ledger._connect() as connection:
|
|
84
|
+
connection.execute("BEGIN IMMEDIATE")
|
|
85
|
+
# Another host publisher may have committed while files were validated.
|
|
86
|
+
previous = connection.execute(
|
|
87
|
+
"SELECT payload FROM skill_results WHERE operation_id=?", (operation_id,)
|
|
88
|
+
).fetchone()
|
|
89
|
+
if previous is not None:
|
|
90
|
+
return json.loads(previous[0])
|
|
91
|
+
state = connection.execute(
|
|
92
|
+
"SELECT state FROM operations WHERE id=?", (operation_id,)
|
|
93
|
+
).fetchone()
|
|
94
|
+
if state is None or state[0] not in {"unknown", "accepted_pending"}:
|
|
95
|
+
raise OperationConflict("RESOURCE_OPERATION_STATE_CONFLICT")
|
|
96
|
+
artifacts = []
|
|
97
|
+
for entry in archive.infolist():
|
|
98
|
+
data = archive.read(entry)
|
|
99
|
+
digest = hashlib.sha256(data).hexdigest()
|
|
100
|
+
artifact_id = hashlib.sha256(
|
|
101
|
+
(operation_id + "\0" + entry.filename + "\0" + digest).encode()
|
|
102
|
+
).hexdigest()
|
|
103
|
+
artifacts.append(
|
|
104
|
+
{
|
|
105
|
+
"artifactId": artifact_id,
|
|
106
|
+
"name": entry.filename,
|
|
107
|
+
"size": len(data),
|
|
108
|
+
"sha256": digest,
|
|
109
|
+
}
|
|
110
|
+
)
|
|
111
|
+
connection.execute(
|
|
112
|
+
"INSERT INTO skill_artifacts VALUES (?, ?, ?)",
|
|
113
|
+
(operation_id, artifact_id, data),
|
|
114
|
+
)
|
|
115
|
+
result = {"status": status, "operationId": operation_id, "artifacts": artifacts}
|
|
116
|
+
connection.execute(
|
|
117
|
+
"INSERT INTO skill_results VALUES (?, ?)",
|
|
118
|
+
(operation_id, json.dumps(result, separators=(",", ":"))),
|
|
119
|
+
)
|
|
120
|
+
connection.execute(
|
|
121
|
+
"UPDATE operations SET state=? WHERE id=?", (status, operation_id)
|
|
122
|
+
)
|
|
123
|
+
return result
|
|
124
|
+
|
|
125
|
+
def read(self, arguments: dict, *, authority_digest: str) -> dict:
|
|
126
|
+
query = SkillArtifactQuery.model_validate(arguments)
|
|
127
|
+
result = self.result(query.operation_id, authority_digest=authority_digest)
|
|
128
|
+
artifact = next(
|
|
129
|
+
(
|
|
130
|
+
item
|
|
131
|
+
for item in (result or {}).get("artifacts", [])
|
|
132
|
+
if item["artifactId"] == query.artifact_id
|
|
133
|
+
),
|
|
134
|
+
None,
|
|
135
|
+
)
|
|
136
|
+
if artifact is None or query.offset > artifact["size"]:
|
|
137
|
+
raise OperationConflict("RESOURCE_ARTIFACT_NOT_FOUND")
|
|
138
|
+
with self.ledger._connect() as connection:
|
|
139
|
+
row = connection.execute(
|
|
140
|
+
"SELECT substr(data, ?, ?) FROM skill_artifacts WHERE operation_id=? AND id=?",
|
|
141
|
+
(query.offset + 1, query.max_bytes, query.operation_id, query.artifact_id),
|
|
142
|
+
).fetchone()
|
|
143
|
+
if row is None:
|
|
144
|
+
raise OperationConflict("RESOURCE_ARTIFACT_NOT_FOUND")
|
|
145
|
+
following = query.offset + len(row[0])
|
|
146
|
+
return {
|
|
147
|
+
**artifact,
|
|
148
|
+
"operationId": query.operation_id,
|
|
149
|
+
"encoding": "base64",
|
|
150
|
+
"content": base64.b64encode(row[0]).decode("ascii"),
|
|
151
|
+
"offset": query.offset,
|
|
152
|
+
"nextOffset": following if following < artifact["size"] else None,
|
|
153
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Instantiate the sandbox target frozen in a resource Build after host admission."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from pydantic import SecretStr
|
|
6
|
+
|
|
7
|
+
from ksadk.resource_runtime.snapshots import ConnectionTarget, ResourceSnapshot
|
|
8
|
+
from ksadk.sandbox.e2b_connection import ExplicitE2BConnection
|
|
9
|
+
from ksadk.skills.runtime.backends.e2b import E2BSkillRuntimeBackend
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def create_bound_skill_runtime(
|
|
13
|
+
snapshot: ResourceSnapshot,
|
|
14
|
+
binding_id: str,
|
|
15
|
+
*,
|
|
16
|
+
current_connection: ConnectionTarget,
|
|
17
|
+
api_key: SecretStr,
|
|
18
|
+
artifact_directory: Path | None = None,
|
|
19
|
+
) -> E2BSkillRuntimeBackend:
|
|
20
|
+
"""Host revalidates account/grant first; only secret values may rotate here.
|
|
21
|
+
|
|
22
|
+
This factory does not read process env, create a sandbox, or authorize tool
|
|
23
|
+
execution. The target and network policy are immutable Build inputs.
|
|
24
|
+
"""
|
|
25
|
+
snapshot = ResourceSnapshot.model_validate(snapshot.model_dump())
|
|
26
|
+
target = snapshot.binding(binding_id).skill_execution
|
|
27
|
+
if target is None:
|
|
28
|
+
raise ValueError("SKILL_EXECUTION_TARGET_REQUIRED")
|
|
29
|
+
if target.connection != current_connection:
|
|
30
|
+
raise ValueError("RESOURCE_CONNECTION_CHANGED")
|
|
31
|
+
connection = ExplicitE2BConnection(
|
|
32
|
+
api_url=target.connection.endpoint,
|
|
33
|
+
domain=target.domain,
|
|
34
|
+
api_key=api_key,
|
|
35
|
+
)
|
|
36
|
+
return E2BSkillRuntimeBackend(
|
|
37
|
+
template_id=target.template_id,
|
|
38
|
+
timeout=target.timeout,
|
|
39
|
+
allow_internet_access=target.allow_internet_access,
|
|
40
|
+
connection=connection,
|
|
41
|
+
artifact_directory=artifact_directory,
|
|
42
|
+
)
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"""Owned, activation-visible pinned Skill files for an outer-agent consumer.
|
|
2
|
+
|
|
3
|
+
This prepares files, not native discovery or sandbox isolation. The executor must
|
|
4
|
+
own the workspace lifetime and verify its runtime's discovery and context rules.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import re
|
|
10
|
+
import shutil
|
|
11
|
+
import tempfile
|
|
12
|
+
from contextlib import contextmanager
|
|
13
|
+
from dataclasses import dataclass
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from typing import Iterator
|
|
16
|
+
|
|
17
|
+
from ksadk.resource_runtime.build_artifacts import ResourceBuildReference, restore_resource_build
|
|
18
|
+
from ksadk.skills.package_store import SkillPackageError
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass(frozen=True)
|
|
22
|
+
class PreparedSkill:
|
|
23
|
+
skill_id: str
|
|
24
|
+
version_id: str
|
|
25
|
+
content_hash: str
|
|
26
|
+
relative_directory: str
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass(frozen=True)
|
|
30
|
+
class SkillWorkspace:
|
|
31
|
+
directory: Path
|
|
32
|
+
skills: tuple[PreparedSkill, ...]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _identity(path: Path) -> tuple[int, int]:
|
|
36
|
+
info = path.lstat()
|
|
37
|
+
if path.is_symlink() or not path.is_dir():
|
|
38
|
+
raise SkillPackageError("Skill workspace must remain an owned directory")
|
|
39
|
+
return info.st_dev, info.st_ino
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@contextmanager
|
|
43
|
+
def prepare_pinned_skill_workspace(
|
|
44
|
+
build_directory: Path,
|
|
45
|
+
reference: ResourceBuildReference,
|
|
46
|
+
*,
|
|
47
|
+
binding_id: str,
|
|
48
|
+
workspace_directory: Path,
|
|
49
|
+
) -> Iterator[SkillWorkspace]:
|
|
50
|
+
"""Restore a Build into a new private workspace; clean only that owned root.
|
|
51
|
+
|
|
52
|
+
The trusted executor must admit the current activation and binding first;
|
|
53
|
+
possession of Build bytes is not a grant to consume a platform resource.
|
|
54
|
+
Never merges into an existing project or a global Skill directory. Existing
|
|
55
|
+
user files require an executor-owned workspace composition step. The returned
|
|
56
|
+
paths are relative to the actual consumer cwd, not Worker cache locations.
|
|
57
|
+
"""
|
|
58
|
+
requested = Path(workspace_directory)
|
|
59
|
+
if not requested.is_absolute():
|
|
60
|
+
raise ValueError("Skill consumer workspace must be absolute")
|
|
61
|
+
# Normalize platform aliases such as macOS /var while retaining exclusive
|
|
62
|
+
# creation of the final path. A pre-existing symlink or directory is rejected.
|
|
63
|
+
directory = requested.parent.resolve(strict=True) / requested.name
|
|
64
|
+
with tempfile.TemporaryDirectory(prefix=".skill-consumer-", dir=directory.parent) as temporary:
|
|
65
|
+
manifest, packages = restore_resource_build(
|
|
66
|
+
build_directory,
|
|
67
|
+
reference,
|
|
68
|
+
cache_directory=Path(temporary),
|
|
69
|
+
)
|
|
70
|
+
config = manifest.snapshot.binding(binding_id).config
|
|
71
|
+
if (
|
|
72
|
+
config.binding.resource.kind != "skill-space"
|
|
73
|
+
or config.selection_mode == "discovery"
|
|
74
|
+
or config.execution_mode == "isolated"
|
|
75
|
+
):
|
|
76
|
+
raise SkillPackageError(
|
|
77
|
+
"Native file preparation requires an outer-agent pinned binding"
|
|
78
|
+
)
|
|
79
|
+
selected = packages.get(binding_id, [])
|
|
80
|
+
names = [package.ref.name for package in selected]
|
|
81
|
+
for package in selected:
|
|
82
|
+
for path in package.extract_dir.rglob("*"):
|
|
83
|
+
if path.is_file() and not path.is_relative_to(package.root_dir):
|
|
84
|
+
raise SkillPackageError(
|
|
85
|
+
"Archive contains files outside its selected Skill root"
|
|
86
|
+
)
|
|
87
|
+
if len(set(name.casefold() for name in names)) != len(names) or any(
|
|
88
|
+
not re.fullmatch(r"[A-Za-z0-9][A-Za-z0-9._-]{0,127}", name) for name in names
|
|
89
|
+
):
|
|
90
|
+
raise SkillPackageError(
|
|
91
|
+
"Pinned Skill names cannot form unique safe consumer directories"
|
|
92
|
+
)
|
|
93
|
+
directory.mkdir(mode=0o700)
|
|
94
|
+
owned_identity = _identity(directory)
|
|
95
|
+
try:
|
|
96
|
+
skills_root = directory / ".agents" / "skills"
|
|
97
|
+
skills_root.mkdir(parents=True, mode=0o700)
|
|
98
|
+
prepared = []
|
|
99
|
+
for package in selected:
|
|
100
|
+
destination = skills_root / package.ref.name
|
|
101
|
+
# The verified extraction belongs exclusively to this preparation.
|
|
102
|
+
# Moving it retains complete resources and executable bits without
|
|
103
|
+
# copying from any mutable profile or user Skill directory.
|
|
104
|
+
package.root_dir.rename(destination)
|
|
105
|
+
prepared.append(
|
|
106
|
+
PreparedSkill(
|
|
107
|
+
package.ref.skill_id,
|
|
108
|
+
package.ref.version_id,
|
|
109
|
+
package.ref.content_hash.render(),
|
|
110
|
+
destination.relative_to(directory).as_posix(),
|
|
111
|
+
)
|
|
112
|
+
)
|
|
113
|
+
yield SkillWorkspace(directory, tuple(prepared))
|
|
114
|
+
finally:
|
|
115
|
+
if directory.exists() or directory.is_symlink():
|
|
116
|
+
if _identity(directory) != owned_identity:
|
|
117
|
+
raise SkillPackageError("Skill workspace ownership changed; cleanup refused")
|
|
118
|
+
shutil.rmtree(directory)
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
"""Offline, Build-bound Skill directory and text resources for plugin consumers."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import stat
|
|
7
|
+
from dataclasses import replace
|
|
8
|
+
from pathlib import Path, PurePosixPath
|
|
9
|
+
|
|
10
|
+
from pydantic import Field, field_validator
|
|
11
|
+
|
|
12
|
+
from ksadk.plugins.contracts import PluginContractModel
|
|
13
|
+
from ksadk.resource_runtime.build_artifacts import ResourceBuildReference, restore_resource_build
|
|
14
|
+
from ksadk.skills.loader import load_local_skill
|
|
15
|
+
from ksadk.skills.package_store import SkillPackageError
|
|
16
|
+
from ksadk.skills.runtime.base import SkillRuntimeBackend, SkillRuntimeResult
|
|
17
|
+
from ksadk.skills.runtime.registry import match_skill_refs
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class SkillSelector(PluginContractModel):
|
|
21
|
+
skill_id: str = Field(strict=True, min_length=1, max_length=256)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class SkillSearchQuery(PluginContractModel):
|
|
25
|
+
query: str = Field(strict=True, min_length=1, max_length=16000)
|
|
26
|
+
max_results: int = Field(default=10, strict=True, ge=1, le=32)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class SkillExecutionQuery(PluginContractModel):
|
|
30
|
+
workflow_prompt: str = Field(strict=True, min_length=1, max_length=16000)
|
|
31
|
+
skill_ids: tuple[str, ...] = Field(min_length=1, max_length=32)
|
|
32
|
+
|
|
33
|
+
@field_validator("skill_ids")
|
|
34
|
+
@classmethod
|
|
35
|
+
def unique_ids(cls, values):
|
|
36
|
+
if len(set(values)) != len(values) or any(not item or len(item) > 256 for item in values):
|
|
37
|
+
raise ValueError("Execution requires unique Skill IDs")
|
|
38
|
+
return values
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class SkillResourceQuery(SkillSelector):
|
|
42
|
+
path: str = Field(strict=True, min_length=1, max_length=1024)
|
|
43
|
+
offset: int = Field(default=0, strict=True, ge=0, le=1024 * 1024)
|
|
44
|
+
max_chars: int = Field(default=16000, strict=True, ge=1, le=64000)
|
|
45
|
+
|
|
46
|
+
@field_validator("path")
|
|
47
|
+
@classmethod
|
|
48
|
+
def relative_path(cls, value: str) -> str:
|
|
49
|
+
path = PurePosixPath(value)
|
|
50
|
+
if (
|
|
51
|
+
path.is_absolute()
|
|
52
|
+
or "\\" in value
|
|
53
|
+
or "\x00" in value
|
|
54
|
+
or any(part in {"", ".", ".."} for part in value.split("/"))
|
|
55
|
+
):
|
|
56
|
+
raise ValueError("Skill resource must use a canonical relative path")
|
|
57
|
+
return value
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class PinnedSkillService:
|
|
61
|
+
"""The host supplies an admitted Build and binding; no remote catalog fallback.
|
|
62
|
+
|
|
63
|
+
Every operation revalidates saved Build bytes and the extraction cache. This
|
|
64
|
+
protects reproducibility, not hostile same-user processes during a read.
|
|
65
|
+
Paths returned in tool results are package-relative, never host locations.
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
def __init__(
|
|
69
|
+
self,
|
|
70
|
+
directory: Path,
|
|
71
|
+
reference: ResourceBuildReference,
|
|
72
|
+
*,
|
|
73
|
+
binding_id: str,
|
|
74
|
+
cache_directory: Path,
|
|
75
|
+
):
|
|
76
|
+
self.directory = directory
|
|
77
|
+
self.reference = ResourceBuildReference.model_validate(reference.model_dump())
|
|
78
|
+
self.binding_id = binding_id
|
|
79
|
+
self.cache_directory = cache_directory
|
|
80
|
+
self._packages()
|
|
81
|
+
|
|
82
|
+
def _restore(self):
|
|
83
|
+
manifest, packages = restore_resource_build(
|
|
84
|
+
self.directory,
|
|
85
|
+
self.reference,
|
|
86
|
+
cache_directory=self.cache_directory,
|
|
87
|
+
)
|
|
88
|
+
binding = manifest.snapshot.binding(self.binding_id)
|
|
89
|
+
config = binding.config
|
|
90
|
+
if config.binding.resource.kind != "skill-space" or config.selection_mode == "discovery":
|
|
91
|
+
raise SkillPackageError("Pinned Skill service requires a pinned Skill binding")
|
|
92
|
+
return (
|
|
93
|
+
config,
|
|
94
|
+
{package.ref.skill_id: package for package in packages.get(self.binding_id, [])},
|
|
95
|
+
binding.skill_execution,
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
def _packages(self):
|
|
99
|
+
return self._restore()[1]
|
|
100
|
+
|
|
101
|
+
def execute(
|
|
102
|
+
self,
|
|
103
|
+
arguments: dict,
|
|
104
|
+
*,
|
|
105
|
+
backend: SkillRuntimeBackend,
|
|
106
|
+
operation_id: str,
|
|
107
|
+
timeout: int,
|
|
108
|
+
) -> SkillRuntimeResult:
|
|
109
|
+
"""Host-only post-approval adapter to an explicitly admitted Runtime.
|
|
110
|
+
|
|
111
|
+
The host selects the backend and owns artifact publication. The internal
|
|
112
|
+
result may contain host paths; it must not be sent directly as tool text.
|
|
113
|
+
This adapter grants no approval and does not select a backend from env.
|
|
114
|
+
"""
|
|
115
|
+
query = SkillExecutionQuery.model_validate(arguments)
|
|
116
|
+
if not query.workflow_prompt.strip() or type(timeout) is not int or not 1 <= timeout <= 900:
|
|
117
|
+
raise ValueError("Invalid Skill execution budget or prompt")
|
|
118
|
+
if len(operation_id) != 64 or any(char not in "0123456789abcdef" for char in operation_id):
|
|
119
|
+
raise ValueError("Execution requires a durable operation ID")
|
|
120
|
+
config, packages, target = self._restore()
|
|
121
|
+
if config.execution_mode != "isolated":
|
|
122
|
+
raise ValueError("SKILL_EXECUTION_MODE_UNSUPPORTED")
|
|
123
|
+
if any(skill_id not in packages for skill_id in query.skill_ids):
|
|
124
|
+
raise ValueError("SKILL_NOT_BOUND")
|
|
125
|
+
selected = [packages[skill_id] for skill_id in query.skill_ids]
|
|
126
|
+
return backend.run_workflow(
|
|
127
|
+
query.workflow_prompt,
|
|
128
|
+
skill_space_ids=[],
|
|
129
|
+
session_id=operation_id,
|
|
130
|
+
skill_names=[package.ref.name for package in selected],
|
|
131
|
+
pinned_packages=selected,
|
|
132
|
+
timeout=min(timeout, target.timeout) if target is not None else timeout,
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
def list_skills(self, arguments: dict) -> dict:
|
|
136
|
+
if arguments:
|
|
137
|
+
raise ValueError("Pinned directory accepts no resource or space parameters")
|
|
138
|
+
packages = self._packages()
|
|
139
|
+
return {
|
|
140
|
+
"status": "ok",
|
|
141
|
+
"items": [
|
|
142
|
+
{
|
|
143
|
+
"skillId": package.ref.skill_id,
|
|
144
|
+
"versionId": package.ref.version_id,
|
|
145
|
+
"name": package.ref.name,
|
|
146
|
+
"contentHash": package.ref.content_hash.render(),
|
|
147
|
+
}
|
|
148
|
+
for package in sorted(packages.values(), key=lambda item: item.ref.skill_id)
|
|
149
|
+
],
|
|
150
|
+
"truncated": False,
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
def read_resource(self, arguments: dict) -> dict:
|
|
154
|
+
query = SkillResourceQuery.model_validate(arguments)
|
|
155
|
+
package = self._packages().get(query.skill_id)
|
|
156
|
+
if package is None:
|
|
157
|
+
raise ValueError("SKILL_NOT_BOUND")
|
|
158
|
+
path = package.root_dir
|
|
159
|
+
for part in PurePosixPath(query.path).parts:
|
|
160
|
+
path = path / part
|
|
161
|
+
if path.is_symlink():
|
|
162
|
+
raise SkillPackageError("Skill resource cannot be a symbolic link")
|
|
163
|
+
descriptor = os.open(path, os.O_RDONLY | os.O_NOFOLLOW | os.O_NONBLOCK)
|
|
164
|
+
with os.fdopen(descriptor, "rb") as stream:
|
|
165
|
+
info = os.fstat(stream.fileno())
|
|
166
|
+
if not stat.S_ISREG(info.st_mode) or info.st_size > 1024 * 1024:
|
|
167
|
+
raise SkillPackageError("Skill text resource exceeds limit or is not a file")
|
|
168
|
+
raw = stream.read(1024 * 1024 + 1)
|
|
169
|
+
if len(raw) > 1024 * 1024:
|
|
170
|
+
raise SkillPackageError("Skill text resource exceeds limit")
|
|
171
|
+
content = raw.decode("utf-8")
|
|
172
|
+
end = min(len(content), query.offset + query.max_chars)
|
|
173
|
+
truncated = end < len(content)
|
|
174
|
+
return {
|
|
175
|
+
"status": "ok",
|
|
176
|
+
"skillId": query.skill_id,
|
|
177
|
+
"versionId": package.ref.version_id,
|
|
178
|
+
"contentHash": package.ref.content_hash.render(),
|
|
179
|
+
"path": query.path,
|
|
180
|
+
"content": content[query.offset : end],
|
|
181
|
+
"truncated": truncated,
|
|
182
|
+
"nextOffset": end if truncated else None,
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
def search_skills(self, arguments: dict) -> dict:
|
|
186
|
+
query = SkillSearchQuery.model_validate(arguments)
|
|
187
|
+
if not query.query.strip():
|
|
188
|
+
raise ValueError("Skill query cannot be blank")
|
|
189
|
+
refs = []
|
|
190
|
+
for package in self._packages().values():
|
|
191
|
+
if (package.root_dir / "SKILL.md").stat().st_size > 1024 * 1024:
|
|
192
|
+
raise SkillPackageError("Skill document exceeds text limit")
|
|
193
|
+
document = load_local_skill(package.root_dir)
|
|
194
|
+
refs.append(replace(package.ref, description=document.description[:8192]))
|
|
195
|
+
matches = match_skill_refs(refs, query.query)
|
|
196
|
+
return {
|
|
197
|
+
"status": "ok",
|
|
198
|
+
"truncated": len(matches) > query.max_results,
|
|
199
|
+
"items": [
|
|
200
|
+
{
|
|
201
|
+
"skillId": match.skill.skill_id,
|
|
202
|
+
"name": match.skill.name,
|
|
203
|
+
"versionId": match.skill.version_id,
|
|
204
|
+
"contentHash": match.skill.content_hash.render(),
|
|
205
|
+
"description": match.skill.description,
|
|
206
|
+
"score": match.score,
|
|
207
|
+
"reason": match.reason,
|
|
208
|
+
}
|
|
209
|
+
for match in matches[: query.max_results]
|
|
210
|
+
],
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
def load_skill(self, arguments: dict) -> dict:
|
|
214
|
+
selector = SkillSelector.model_validate(arguments)
|
|
215
|
+
return self.read_resource({"skillId": selector.skill_id, "path": "SKILL.md"})
|