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,368 @@
|
|
|
1
|
+
"""Official Codex provider's native assembly; no PluginHost or default-registry recursion.
|
|
2
|
+
|
|
3
|
+
Both the legacy runtime registration and the admitted AgentProvider use this
|
|
4
|
+
factory. Policy and input projection belong here; native lifecycle and events
|
|
5
|
+
remain in CodexRuntimeAdapter.
|
|
6
|
+
"""
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import dataclasses
|
|
10
|
+
import hashlib
|
|
11
|
+
import json
|
|
12
|
+
import os
|
|
13
|
+
import re
|
|
14
|
+
import shutil
|
|
15
|
+
import tempfile
|
|
16
|
+
from collections.abc import Mapping
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
from typing import Any
|
|
19
|
+
|
|
20
|
+
from ksadk.codex.client import AsyncCodexClient, CodexPluginBootstrap
|
|
21
|
+
from ksadk.plugins.providers.codex_turn import CodexTurnProjector
|
|
22
|
+
from ksadk.resource_runtime.managed_projection import native_codex_plugin_bindings
|
|
23
|
+
from ksadk.runtime.adapter import RuntimeAdapter, RuntimeRegistry
|
|
24
|
+
from ksadk.runtime.launch import RuntimeLaunchContext
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def codex_request_config(context: RuntimeLaunchContext) -> dict[str, Any]:
|
|
28
|
+
"""Project admitted Codex policy into native turn defaults."""
|
|
29
|
+
config = dict(context.config)
|
|
30
|
+
prompt = str(config.get("prompt") or "").strip()
|
|
31
|
+
task_prompt = str(config.get("task_prompt") or "").strip()
|
|
32
|
+
base_instructions = prompt
|
|
33
|
+
if task_prompt:
|
|
34
|
+
base_instructions = f"{prompt}\n\n{task_prompt}" if prompt else task_prompt
|
|
35
|
+
|
|
36
|
+
raw_sandbox = str(config.get("sandbox") or "read_only").strip().lower()
|
|
37
|
+
raw_approval = str(config.get("approval_mode") or "").strip().lower()
|
|
38
|
+
approval_profiles = {
|
|
39
|
+
"ask": ("workspace-write", "manual"),
|
|
40
|
+
"risk": ("workspace-write", "auto_review"),
|
|
41
|
+
"full": ("full-access", "deny_all"),
|
|
42
|
+
}
|
|
43
|
+
sandbox_profiles = {
|
|
44
|
+
"read_only": ("read-only", "deny_all"),
|
|
45
|
+
"read-only": ("read-only", "deny_all"),
|
|
46
|
+
"workspace_write": ("workspace-write", "deny_all"),
|
|
47
|
+
"workspace-write": ("workspace-write", "deny_all"),
|
|
48
|
+
"workspace_write_auto": ("workspace-write", "auto_review"),
|
|
49
|
+
"workspace-write-auto": ("workspace-write", "auto_review"),
|
|
50
|
+
"full_access": ("full-access", "deny_all"),
|
|
51
|
+
"full-access": ("full-access", "deny_all"),
|
|
52
|
+
}
|
|
53
|
+
if raw_approval in approval_profiles:
|
|
54
|
+
sandbox, approval = approval_profiles[raw_approval]
|
|
55
|
+
else:
|
|
56
|
+
sandbox, default_approval = sandbox_profiles.get(raw_sandbox, ("read-only", "deny_all"))
|
|
57
|
+
approval = raw_approval or default_approval
|
|
58
|
+
|
|
59
|
+
request_config: dict[str, Any] = {
|
|
60
|
+
"sandbox_read_only": sandbox == "read-only",
|
|
61
|
+
"sandbox": sandbox,
|
|
62
|
+
"approval_mode": approval,
|
|
63
|
+
"cwd": str(context.project_dir),
|
|
64
|
+
"summary": "auto",
|
|
65
|
+
"ephemeral": False,
|
|
66
|
+
}
|
|
67
|
+
if base_instructions:
|
|
68
|
+
request_config["base_instructions"] = base_instructions
|
|
69
|
+
collaboration_mode = str(config.get("collaboration_mode") or "").strip().lower()
|
|
70
|
+
if collaboration_mode:
|
|
71
|
+
if collaboration_mode not in {"default", "plan"}:
|
|
72
|
+
raise ValueError("Codex collaboration_mode must be default or plan")
|
|
73
|
+
request_config["collaboration_mode"] = collaboration_mode
|
|
74
|
+
goal_objective = str(config.get("goal_objective") or "").strip()
|
|
75
|
+
if goal_objective:
|
|
76
|
+
request_config["goal_objective"] = goal_objective
|
|
77
|
+
raw_skills = config.get("skills")
|
|
78
|
+
if isinstance(raw_skills, (list, tuple)):
|
|
79
|
+
request_config["skills"] = [dict(item) for item in raw_skills if isinstance(item, dict)]
|
|
80
|
+
return request_config
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _manifest_mcp_overrides(config: dict[str, Any]) -> list[str]:
|
|
84
|
+
"""Translate declarative MCP bindings into native Codex config keys."""
|
|
85
|
+
|
|
86
|
+
overrides: list[str] = []
|
|
87
|
+
servers = config.get("mcp_servers") or []
|
|
88
|
+
if not isinstance(servers, (list, tuple)):
|
|
89
|
+
return overrides
|
|
90
|
+
for server in servers:
|
|
91
|
+
if not isinstance(server, dict):
|
|
92
|
+
continue
|
|
93
|
+
name = str(server.get("name") or "").strip()
|
|
94
|
+
transport = str(server.get("transport") or ("http" if server.get("url") else "")).lower()
|
|
95
|
+
url = str(server.get("url") or "").strip()
|
|
96
|
+
if not name:
|
|
97
|
+
continue
|
|
98
|
+
if transport == "stdio":
|
|
99
|
+
command = str(server.get("command") or "").strip()
|
|
100
|
+
if not command:
|
|
101
|
+
continue
|
|
102
|
+
args = [str(argument) for argument in (server.get("args") or [])]
|
|
103
|
+
overrides.append(f"mcp_servers.{name}.command={json.dumps(command)}")
|
|
104
|
+
overrides.append(f"mcp_servers.{name}.args={json.dumps(args)}")
|
|
105
|
+
env_refs = server.get("env_refs") or {}
|
|
106
|
+
if isinstance(env_refs, dict) and env_refs:
|
|
107
|
+
overrides.append(
|
|
108
|
+
f"mcp_servers.{name}.env_vars="
|
|
109
|
+
f"{json.dumps(sorted(str(key) for key in env_refs))}"
|
|
110
|
+
)
|
|
111
|
+
elif transport in {"http", "sse"} and url:
|
|
112
|
+
overrides.append(f"mcp_servers.{name}.url={url}")
|
|
113
|
+
env_key = str(server.get("env_key") or "").strip()
|
|
114
|
+
if env_key:
|
|
115
|
+
overrides.append(f"mcp_servers.{name}.bearer_token_env_var={env_key}")
|
|
116
|
+
return overrides
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _manifest_has_network_mcp(config: Mapping[str, Any]) -> bool:
|
|
120
|
+
"""Whether a projected Codex MCP binding genuinely needs network access."""
|
|
121
|
+
|
|
122
|
+
servers = config.get("mcp_servers") or []
|
|
123
|
+
if not isinstance(servers, (list, tuple)):
|
|
124
|
+
return False
|
|
125
|
+
for server in servers:
|
|
126
|
+
if not isinstance(server, dict):
|
|
127
|
+
continue
|
|
128
|
+
name = str(server.get("name") or "").strip()
|
|
129
|
+
url = str(server.get("url") or "").strip()
|
|
130
|
+
transport = str(server.get("transport") or ("http" if url else "")).lower()
|
|
131
|
+
if name and url and transport in {"http", "sse"}:
|
|
132
|
+
return True
|
|
133
|
+
return False
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def _codex_plugin_bootstrap(config: Mapping[str, Any]) -> CodexPluginBootstrap | None:
|
|
137
|
+
"""Read the closed, digest-pinned plugin bootstrap launch contract."""
|
|
138
|
+
|
|
139
|
+
raw = config.get("codex_plugin_bootstrap")
|
|
140
|
+
if raw is None:
|
|
141
|
+
if native_codex_plugin_bindings(config):
|
|
142
|
+
raise ValueError(
|
|
143
|
+
"原生插件绑定缺少可验证的交付快照;当前启动只收到 plugins 声明,"
|
|
144
|
+
"无法恢复插件。请提供完整插件交付配置后再启动。"
|
|
145
|
+
)
|
|
146
|
+
return None
|
|
147
|
+
if not isinstance(raw, Mapping):
|
|
148
|
+
raise ValueError("codex_plugin_bootstrap must be an object")
|
|
149
|
+
return CodexPluginBootstrap.from_mapping(raw)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
_CODEX_HOME_KEY = re.compile(r"^build_[0-9a-f]{8,64}$")
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def _codex_home_key(
|
|
156
|
+
config: Mapping[str, Any],
|
|
157
|
+
plugin_bootstrap: CodexPluginBootstrap | None,
|
|
158
|
+
) -> str:
|
|
159
|
+
raw = config.get("codex_home_key")
|
|
160
|
+
if raw is None:
|
|
161
|
+
if plugin_bootstrap is not None:
|
|
162
|
+
raise ValueError("plugin-bearing Codex launches require codex_home_key")
|
|
163
|
+
return "unscoped"
|
|
164
|
+
value = str(raw).strip()
|
|
165
|
+
if _CODEX_HOME_KEY.fullmatch(value) is None:
|
|
166
|
+
raise ValueError("codex_home_key must match build_[0-9a-f]{8,64}")
|
|
167
|
+
return value
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def create_codex_adapter(context: RuntimeLaunchContext) -> RuntimeAdapter:
|
|
171
|
+
from ksadk.codex.runtime import CodexRuntimeAdapter
|
|
172
|
+
|
|
173
|
+
client_factory = context.services.codex_client_factory or AsyncCodexClient
|
|
174
|
+
config = dict(context.config)
|
|
175
|
+
plugin_bootstrap = _codex_plugin_bootstrap(config)
|
|
176
|
+
codex_home_key = _codex_home_key(config, plugin_bootstrap)
|
|
177
|
+
bound_skill_paths: dict[str, str] = {}
|
|
178
|
+
overrides = list(config.get("codex_overrides") or [])
|
|
179
|
+
manifest_mcp_overrides = _manifest_mcp_overrides(config)
|
|
180
|
+
overrides.extend(item for item in manifest_mcp_overrides if item not in overrides)
|
|
181
|
+
projected_config = codex_request_config(context)
|
|
182
|
+
if _manifest_has_network_mcp(config) and projected_config.get("sandbox") == "workspace-write":
|
|
183
|
+
network_override = "sandbox_workspace_write.network_access=true"
|
|
184
|
+
if network_override not in overrides:
|
|
185
|
+
overrides.append(network_override)
|
|
186
|
+
# Studio's default collaboration mode must expose Codex's structured
|
|
187
|
+
# request_user_input tool; the upstream feature is intentionally off by
|
|
188
|
+
# default outside Plan mode. This stays process-local to the isolated
|
|
189
|
+
# runtime and does not mutate the user's global Codex configuration.
|
|
190
|
+
interaction_override = "features.default_mode_request_user_input=true"
|
|
191
|
+
if interaction_override not in overrides:
|
|
192
|
+
overrides.append(interaction_override)
|
|
193
|
+
try:
|
|
194
|
+
from openai_codex import CodexConfig
|
|
195
|
+
|
|
196
|
+
base_cfg = CodexConfig()
|
|
197
|
+
if overrides:
|
|
198
|
+
base_cfg = dataclasses.replace(
|
|
199
|
+
base_cfg,
|
|
200
|
+
config_overrides=tuple(getattr(base_cfg, "config_overrides", ()) or ())
|
|
201
|
+
+ tuple(str(o) for o in overrides),
|
|
202
|
+
)
|
|
203
|
+
env = dict(getattr(base_cfg, "env", None) or {})
|
|
204
|
+
isolated_home = _isolated_codex_home(context.project_dir, codex_home_key)
|
|
205
|
+
bound_skill_paths = _materialize_bound_codex_skills(isolated_home, config.get("skills"))
|
|
206
|
+
env.setdefault("CODEX_HOME", str(isolated_home))
|
|
207
|
+
# HOME 级隔离:codex app-server 还会按约定扫 ~/.agents/skills、
|
|
208
|
+
# ~/.claude/skills 等宿主目录,仅设 CODEX_HOME 挡不住。隔离 HOME 后这些
|
|
209
|
+
# 路径全部落在工作区内,宿主 skills/MCP/凭证不再进入 Agent 上下文。
|
|
210
|
+
# 设 KSADK_CODEX_ISOLATE_HOME=0 可关闭(调试用)。
|
|
211
|
+
if os.environ.get("KSADK_CODEX_ISOLATE_HOME", "1") != "0":
|
|
212
|
+
env.setdefault("HOME", str(isolated_home))
|
|
213
|
+
# 运行期解析出的凭证值(如 MCP bearer_token_env_var 所需)注入子进程环境
|
|
214
|
+
env.update({str(k): str(v) for k, v in (context.config.get("env") or {}).items()})
|
|
215
|
+
base_cfg = dataclasses.replace(base_cfg, env=env)
|
|
216
|
+
try:
|
|
217
|
+
client: Any = client_factory(config=base_cfg)
|
|
218
|
+
except TypeError:
|
|
219
|
+
# 自定义/测试工厂可能不接受 config 参数:退化为无参构造,
|
|
220
|
+
# config_overrides 事后注入(自定义工厂自行承担 env 隔离)。
|
|
221
|
+
client = client_factory()
|
|
222
|
+
if overrides:
|
|
223
|
+
_apply_codex_overrides(client, overrides)
|
|
224
|
+
except ImportError:
|
|
225
|
+
client: Any = client_factory()
|
|
226
|
+
if overrides:
|
|
227
|
+
_apply_codex_overrides(client, overrides)
|
|
228
|
+
timeout = context.config.get("turn_timeout_seconds")
|
|
229
|
+
request_config = codex_request_config(context)
|
|
230
|
+
sandbox_read_only = (
|
|
231
|
+
bool(context.config["sandbox_read_only"])
|
|
232
|
+
if "sandbox_read_only" in context.config
|
|
233
|
+
else bool(request_config.get("sandbox_read_only", True))
|
|
234
|
+
)
|
|
235
|
+
return CodexRuntimeAdapter(
|
|
236
|
+
client,
|
|
237
|
+
sandbox_read_only=sandbox_read_only,
|
|
238
|
+
turn_timeout_seconds=float(timeout) if timeout is not None else None,
|
|
239
|
+
turn_projector=CodexTurnProjector(
|
|
240
|
+
bound_skill_paths=bound_skill_paths,
|
|
241
|
+
enforce_bound_skills=bool(config.get("enforce_bound_skills")),
|
|
242
|
+
),
|
|
243
|
+
plugin_bootstrap=plugin_bootstrap,
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def _isolated_codex_home(project_dir: Any, codex_home_key: str = "unscoped") -> Path:
|
|
248
|
+
"""Use one CODEX_HOME partition per immutable Codex build.
|
|
249
|
+
|
|
250
|
+
``KSADK_CODEX_HOME`` is a base directory, not the final home: every build
|
|
251
|
+
is placed under ``builds/<key>``. Workspace and managed-runtime fallbacks
|
|
252
|
+
use the same separation, so two build digests cannot observe each other's
|
|
253
|
+
App Server plugin cache.
|
|
254
|
+
"""
|
|
255
|
+
|
|
256
|
+
if codex_home_key != "unscoped" and _CODEX_HOME_KEY.fullmatch(codex_home_key) is None:
|
|
257
|
+
raise ValueError("codex_home_key must match build_[0-9a-f]{8,64}")
|
|
258
|
+
override = os.environ.get("KSADK_CODEX_HOME")
|
|
259
|
+
if override:
|
|
260
|
+
home = Path(override).expanduser() / "builds" / codex_home_key
|
|
261
|
+
home.mkdir(parents=True, exist_ok=True)
|
|
262
|
+
return home
|
|
263
|
+
|
|
264
|
+
# Source bundles are deliberately mounted read-only in managed runtimes.
|
|
265
|
+
# Keep the preferred workspace-local isolation for local development, but
|
|
266
|
+
# never make a Codex turn depend on being able to mutate that bundle.
|
|
267
|
+
workspace_home = Path(str(project_dir)) / ".agentkit" / "codex-homes" / codex_home_key
|
|
268
|
+
try:
|
|
269
|
+
workspace_home.mkdir(parents=True, exist_ok=True)
|
|
270
|
+
return workspace_home
|
|
271
|
+
except OSError:
|
|
272
|
+
pass
|
|
273
|
+
|
|
274
|
+
# The managed runtime already provides a per-workload writable state
|
|
275
|
+
# volume. Derive from its explicit directory first, then from the
|
|
276
|
+
# session-store path for backward-compatible images. /tmp is a final
|
|
277
|
+
# process-local fallback for custom read-only launchers.
|
|
278
|
+
state_dir = os.environ.get("KSADK_RUNTIME_STATE_DIR")
|
|
279
|
+
session_path = os.environ.get("KSADK_SESSION_PATH")
|
|
280
|
+
fallback_root = (
|
|
281
|
+
Path(state_dir)
|
|
282
|
+
if state_dir
|
|
283
|
+
else Path(session_path).expanduser().parent
|
|
284
|
+
if session_path
|
|
285
|
+
else Path(tempfile.gettempdir()) / "ksadk-runtime-state"
|
|
286
|
+
)
|
|
287
|
+
fallback_home = fallback_root / "codex-homes" / codex_home_key
|
|
288
|
+
fallback_home.mkdir(parents=True, exist_ok=True)
|
|
289
|
+
return fallback_home
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def _materialize_bound_codex_skills(codex_home: Path, value: Any) -> dict[str, str]:
|
|
293
|
+
"""Expose immutable Bundle Skills through Codex's native skill catalog.
|
|
294
|
+
|
|
295
|
+
Passing an arbitrary ``SkillInput`` path is accepted by the Python SDK but
|
|
296
|
+
ignored by the real App Server unless the Skill is discoverable by the
|
|
297
|
+
native host. Copy each content-addressed Bundle Skill into the isolated
|
|
298
|
+
CODEX_HOME so the host owns discovery while the Bundle remains read-only.
|
|
299
|
+
Content-addressed directory names avoid overwriting user-managed Skills
|
|
300
|
+
when an explicit KSADK_CODEX_HOME is used.
|
|
301
|
+
"""
|
|
302
|
+
|
|
303
|
+
if not isinstance(value, (list, tuple)):
|
|
304
|
+
return {}
|
|
305
|
+
skills_root = codex_home / "skills"
|
|
306
|
+
skills_root.mkdir(parents=True, exist_ok=True)
|
|
307
|
+
installed: dict[str, str] = {}
|
|
308
|
+
for item in value:
|
|
309
|
+
if not isinstance(item, dict):
|
|
310
|
+
continue
|
|
311
|
+
name = str(item.get("name") or "").strip()
|
|
312
|
+
raw_path = str(item.get("path") or "").strip()
|
|
313
|
+
if not name or not raw_path:
|
|
314
|
+
continue
|
|
315
|
+
skill_file = Path(raw_path).resolve()
|
|
316
|
+
if skill_file.name != "SKILL.md" or not skill_file.is_file():
|
|
317
|
+
continue
|
|
318
|
+
source_dir = skill_file.parent
|
|
319
|
+
digest = hashlib.sha256()
|
|
320
|
+
for source in sorted(path for path in source_dir.rglob("*") if path.is_file()):
|
|
321
|
+
digest.update(source.relative_to(source_dir).as_posix().encode("utf-8"))
|
|
322
|
+
digest.update(b"\0")
|
|
323
|
+
digest.update(source.read_bytes())
|
|
324
|
+
digest.update(b"\0")
|
|
325
|
+
safe_name = re.sub(r"[^A-Za-z0-9._-]+", "-", name).strip(".-") or "skill"
|
|
326
|
+
target = skills_root / f"ksadk-{digest.hexdigest()[:16]}-{safe_name}"
|
|
327
|
+
if target.is_dir():
|
|
328
|
+
installed[name] = str(target / "SKILL.md")
|
|
329
|
+
continue
|
|
330
|
+
staging = Path(tempfile.mkdtemp(prefix=".ksadk-skill-", dir=skills_root))
|
|
331
|
+
try:
|
|
332
|
+
shutil.copytree(source_dir, staging, dirs_exist_ok=True)
|
|
333
|
+
try:
|
|
334
|
+
staging.replace(target)
|
|
335
|
+
except FileExistsError:
|
|
336
|
+
pass
|
|
337
|
+
finally:
|
|
338
|
+
if staging.exists():
|
|
339
|
+
shutil.rmtree(staging)
|
|
340
|
+
installed[name] = str(target / "SKILL.md")
|
|
341
|
+
return installed
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
def _apply_codex_overrides(client: Any, overrides: Any) -> None:
|
|
345
|
+
"""Append MCP server --config overrides to the client's CodexConfig."""
|
|
346
|
+
try:
|
|
347
|
+
from openai_codex import CodexConfig
|
|
348
|
+
except ImportError:
|
|
349
|
+
return
|
|
350
|
+
# ksadk AsyncCodexClient -> AsyncCodex -> inner AsyncCodexClient.config
|
|
351
|
+
inner_codex = getattr(client, "_codex", None)
|
|
352
|
+
inner_client = getattr(inner_codex, "_client", None) or inner_codex
|
|
353
|
+
cfg = getattr(inner_client, "config", None)
|
|
354
|
+
if cfg is None or not isinstance(cfg, CodexConfig):
|
|
355
|
+
return
|
|
356
|
+
base_overrides = tuple(getattr(cfg, "config_overrides", ()) or ())
|
|
357
|
+
new_overrides = tuple(str(o) for o in overrides if o not in base_overrides)
|
|
358
|
+
if not new_overrides:
|
|
359
|
+
return
|
|
360
|
+
new_cfg = dataclasses.replace(cfg, config_overrides=base_overrides + new_overrides)
|
|
361
|
+
setattr(inner_client, "config", new_cfg)
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
def codex_runtime_registry() -> RuntimeRegistry:
|
|
365
|
+
"""Private native registry for the provider, never a provider resolver."""
|
|
366
|
+
registry = RuntimeRegistry()
|
|
367
|
+
registry.register("codex", create_codex_adapter)
|
|
368
|
+
return registry
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
"""Provider-owned projection of bound capabilities and canonical input into Codex.
|
|
2
|
+
|
|
3
|
+
One projector belongs to one native adapter. Attachment persistence retains the
|
|
4
|
+
existing native-thread continuation contract; adapter close is not session close.
|
|
5
|
+
"""
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import base64
|
|
9
|
+
import binascii
|
|
10
|
+
import hashlib
|
|
11
|
+
import json
|
|
12
|
+
import re
|
|
13
|
+
from collections.abc import Mapping
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from typing import Any, Optional
|
|
16
|
+
|
|
17
|
+
from ksadk.codex.projection import ProjectedCodexTurn
|
|
18
|
+
from ksadk.runtime.adapter import ResumePayload, StartRequest
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class CodexTurnProjector:
|
|
22
|
+
def __init__(
|
|
23
|
+
self, *, bound_skill_paths: Mapping[str, str] | None = None,
|
|
24
|
+
enforce_bound_skills: bool = False,
|
|
25
|
+
) -> None:
|
|
26
|
+
self._skills = dict(bound_skill_paths or {})
|
|
27
|
+
self._enforce_bound_skills = enforce_bound_skills
|
|
28
|
+
self._closed = False
|
|
29
|
+
|
|
30
|
+
def prepare(self, request: StartRequest) -> StartRequest:
|
|
31
|
+
"""Project admitted native Skill paths without mutating a caller request."""
|
|
32
|
+
self._require_open()
|
|
33
|
+
skills = request.config.get("skills")
|
|
34
|
+
if self._enforce_bound_skills:
|
|
35
|
+
if skills is not None and (not isinstance(skills, list) or any(
|
|
36
|
+
not isinstance(item, dict)
|
|
37
|
+
or str(item.get("name") or "").strip() not in self._skills
|
|
38
|
+
for item in skills
|
|
39
|
+
)):
|
|
40
|
+
raise ValueError("Codex request contains a Skill absent from the immutable Bundle")
|
|
41
|
+
return request.model_copy(update={"config": {
|
|
42
|
+
**request.config,
|
|
43
|
+
"skills": [{"name": name, "path": path} for name, path in self._skills.items()],
|
|
44
|
+
}})
|
|
45
|
+
if not self._skills or not isinstance(skills, list):
|
|
46
|
+
return request
|
|
47
|
+
projected = [
|
|
48
|
+
{**item, "path": self._skills.get(
|
|
49
|
+
str(item.get("name") or "").strip(), str(item.get("path") or ""),
|
|
50
|
+
)}
|
|
51
|
+
for item in skills if isinstance(item, dict)
|
|
52
|
+
]
|
|
53
|
+
return request.model_copy(update={"config": {**request.config, "skills": projected}})
|
|
54
|
+
|
|
55
|
+
def project(
|
|
56
|
+
self, request: StartRequest | None, payload: ResumePayload | None,
|
|
57
|
+
) -> ProjectedCodexTurn:
|
|
58
|
+
self._require_open()
|
|
59
|
+
prompt = _request_prompt(request) if request is not None else _resume_prompt(payload)
|
|
60
|
+
return ProjectedCodexTurn(_build_run_input(request, prompt, self._materialize_file))
|
|
61
|
+
|
|
62
|
+
def close(self) -> None:
|
|
63
|
+
self._closed = True
|
|
64
|
+
|
|
65
|
+
def _require_open(self) -> None:
|
|
66
|
+
if self._closed:
|
|
67
|
+
raise RuntimeError("Codex turn projector is closed")
|
|
68
|
+
|
|
69
|
+
def _materialize_file(self, data_url: str, filename: str) -> Path | None:
|
|
70
|
+
"""Materialize a bounded Studio inline attachment for native Codex."""
|
|
71
|
+
|
|
72
|
+
match = re.fullmatch(r"data:([^;,]+)?;base64,([A-Za-z0-9+/=\s]+)", data_url)
|
|
73
|
+
encoded = match.group(2) if match is not None else data_url.strip()
|
|
74
|
+
try:
|
|
75
|
+
payload = base64.b64decode(encoded, validate=True)
|
|
76
|
+
except (ValueError, binascii.Error):
|
|
77
|
+
return None
|
|
78
|
+
if not payload or len(payload) > 10 * 1024 * 1024:
|
|
79
|
+
return None
|
|
80
|
+
safe_name = re.sub(r"[^A-Za-z0-9._-]+", "-", Path(filename).name).strip(".-")
|
|
81
|
+
safe_name = safe_name[:120] or "attachment"
|
|
82
|
+
digest = hashlib.sha256(payload).hexdigest()
|
|
83
|
+
# Native thread continuation can outlive this adapter. Keep the existing
|
|
84
|
+
# content-addressed storage until the session owner supplies retention.
|
|
85
|
+
path = Path("/tmp/ksadk-codex-attachments") / digest / safe_name
|
|
86
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
87
|
+
if not path.exists():
|
|
88
|
+
path.write_bytes(payload)
|
|
89
|
+
return path
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _resume_prompt(payload: Optional[ResumePayload]) -> Any:
|
|
93
|
+
if payload is None:
|
|
94
|
+
return ""
|
|
95
|
+
if isinstance(payload.data, str):
|
|
96
|
+
return payload.data
|
|
97
|
+
return json.dumps(payload.data, ensure_ascii=False, sort_keys=True)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _coerce_prompt_text(value: Any) -> Any:
|
|
101
|
+
"""把 canonical message 形态的 input 压成 SDK 可接受的文本。
|
|
102
|
+
|
|
103
|
+
``openai-codex`` 0.147 的 run input 只接受 TextInput/str;请求侧没有
|
|
104
|
+
conversation preprocessing 时 ``request.input`` 可能是
|
|
105
|
+
``[{role, content}]`` 历史列表,直接透传会 ``unsupported input item``。
|
|
106
|
+
"""
|
|
107
|
+
if isinstance(value, str) or value is None:
|
|
108
|
+
return value
|
|
109
|
+
if isinstance(value, dict):
|
|
110
|
+
content = value.get("content") if "role" in value else value.get("text")
|
|
111
|
+
if isinstance(content, str):
|
|
112
|
+
return content
|
|
113
|
+
if isinstance(content, dict):
|
|
114
|
+
text = content.get("text") or content.get("content")
|
|
115
|
+
if isinstance(text, str):
|
|
116
|
+
return text
|
|
117
|
+
return str(value)
|
|
118
|
+
if isinstance(value, list):
|
|
119
|
+
texts = [
|
|
120
|
+
text
|
|
121
|
+
for text in (_coerce_prompt_text(item) for item in value)
|
|
122
|
+
if isinstance(text, str) and text
|
|
123
|
+
]
|
|
124
|
+
return "\n".join(texts) if texts else str(value)
|
|
125
|
+
return str(value)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def _request_prompt(request: StartRequest) -> Any:
|
|
129
|
+
"""Render canonical conversation history for a native Codex turn.
|
|
130
|
+
|
|
131
|
+
只传 user 消息历史 + 当前 input,不传 assistant 的完整回复(避免 codex 复述历史)。
|
|
132
|
+
assistant 回复用简短摘要代替,仅维持对话结构。
|
|
133
|
+
"""
|
|
134
|
+
# A resumed Codex thread already owns its transcript. Re-sending Studio's
|
|
135
|
+
# transport-neutral history would duplicate every prior turn after refresh.
|
|
136
|
+
if str(request.metadata.get("thread_id") or "").strip():
|
|
137
|
+
return (
|
|
138
|
+
request.input
|
|
139
|
+
if _is_structured_turn_input(request.input)
|
|
140
|
+
else _coerce_prompt_text(request.input)
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
conversation = request.conversation_preprocessing()
|
|
144
|
+
if conversation is None or not conversation.messages:
|
|
145
|
+
# Keep native text/image/mention parts intact for _build_run_input().
|
|
146
|
+
# Flattening this list turns an image dict into user-visible text.
|
|
147
|
+
return (
|
|
148
|
+
request.input
|
|
149
|
+
if _is_structured_turn_input(request.input)
|
|
150
|
+
else _coerce_prompt_text(request.input)
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
lines: list[str] = []
|
|
154
|
+
for message in conversation.messages:
|
|
155
|
+
content = message.get("content")
|
|
156
|
+
if not isinstance(content, str):
|
|
157
|
+
continue
|
|
158
|
+
role = str(message.get("role") or "user").strip().lower()
|
|
159
|
+
if role == "assistant":
|
|
160
|
+
# 不传完整回复,只标注"已回复",避免 codex 复述
|
|
161
|
+
summary = content[:80] + ("..." if len(content) > 80 else "")
|
|
162
|
+
lines.append(f"[上一轮已回复: {summary}]")
|
|
163
|
+
elif role == "user":
|
|
164
|
+
lines.append(f"User: {content}")
|
|
165
|
+
return "\n".join(lines) or request.input
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def _is_structured_turn_input(value: Any) -> bool:
|
|
169
|
+
return isinstance(value, list) and any(
|
|
170
|
+
isinstance(item, dict) and isinstance(item.get("type"), str) for item in value
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def _build_run_input(
|
|
175
|
+
request: Optional[StartRequest], prompt: Any, materialize_file: Any
|
|
176
|
+
) -> Any:
|
|
177
|
+
"""Compose Codex skills and native text/image/mention turn input."""
|
|
178
|
+
try:
|
|
179
|
+
from openai_codex import ImageInput, LocalImageInput, MentionInput, SkillInput, TextInput
|
|
180
|
+
except ImportError:
|
|
181
|
+
return prompt
|
|
182
|
+
skills: list[SkillInput] = []
|
|
183
|
+
if request is not None:
|
|
184
|
+
raw = request.config.get("skills") if request.config else None
|
|
185
|
+
if isinstance(raw, list):
|
|
186
|
+
for item in raw:
|
|
187
|
+
if not isinstance(item, dict):
|
|
188
|
+
continue
|
|
189
|
+
name = str(item.get("name") or "").strip()
|
|
190
|
+
path = str(item.get("path") or "").strip()
|
|
191
|
+
if name and path:
|
|
192
|
+
skills.append(SkillInput(name=name, path=path))
|
|
193
|
+
native_items: list[Any] = []
|
|
194
|
+
raw_input = request.input if request is not None else prompt
|
|
195
|
+
if isinstance(raw_input, list):
|
|
196
|
+
text_replaced = False
|
|
197
|
+
for item in raw_input:
|
|
198
|
+
if not isinstance(item, dict):
|
|
199
|
+
continue
|
|
200
|
+
kind = str(item.get("type") or "")
|
|
201
|
+
if not kind and "role" in item:
|
|
202
|
+
# canonical conversation message({role, content});当前 input
|
|
203
|
+
# 已由 prompt(或 conversation preprocessing)承载,跳过历史项。
|
|
204
|
+
continue
|
|
205
|
+
if kind in {"text", "input_text"}:
|
|
206
|
+
text = str(
|
|
207
|
+
prompt
|
|
208
|
+
if not text_replaced and isinstance(prompt, str)
|
|
209
|
+
else item.get("text") or ""
|
|
210
|
+
)
|
|
211
|
+
text_replaced = True
|
|
212
|
+
if text:
|
|
213
|
+
native_items.append(TextInput(text=text))
|
|
214
|
+
elif kind in {"image", "input_image"} and (item.get("url") or item.get("image_url")):
|
|
215
|
+
native_items.append(ImageInput(url=str(item.get("url") or item.get("image_url"))))
|
|
216
|
+
elif kind == "localImage" and item.get("path"):
|
|
217
|
+
native_items.append(LocalImageInput(path=str(item["path"])))
|
|
218
|
+
elif kind == "input_file" and (
|
|
219
|
+
item.get("file_data") or str(item.get("file_url") or "").startswith("data:")
|
|
220
|
+
):
|
|
221
|
+
file_path = materialize_file(
|
|
222
|
+
str(item.get("file_data") or item.get("file_url")),
|
|
223
|
+
str(item.get("filename") or "attachment"),
|
|
224
|
+
)
|
|
225
|
+
if file_path is not None:
|
|
226
|
+
# App Server's ``mention`` input is presentation metadata:
|
|
227
|
+
# current Codex versions do not include it in the model's
|
|
228
|
+
# user message. Always add an explicit model-visible
|
|
229
|
+
# attachment context as well. Small textual files are
|
|
230
|
+
# inlined deterministically; binary/large files expose a
|
|
231
|
+
# sandbox-readable path that Codex can inspect with tools.
|
|
232
|
+
native_items.append(TextInput(text=_attachment_context_text(file_path, item)))
|
|
233
|
+
native_items.append(MentionInput(name=file_path.name, path=str(file_path)))
|
|
234
|
+
elif kind == "mention" and item.get("path"):
|
|
235
|
+
native_items.append(
|
|
236
|
+
MentionInput(
|
|
237
|
+
name=str(item.get("name") or item["path"]),
|
|
238
|
+
path=str(item["path"]),
|
|
239
|
+
)
|
|
240
|
+
)
|
|
241
|
+
else:
|
|
242
|
+
text = prompt if isinstance(prompt, str) else str(prompt or "")
|
|
243
|
+
if text:
|
|
244
|
+
native_items.append(TextInput(text=text))
|
|
245
|
+
combined = [*skills, *native_items]
|
|
246
|
+
if not combined:
|
|
247
|
+
return prompt
|
|
248
|
+
if len(combined) == 1 and isinstance(combined[0], TextInput) and not skills:
|
|
249
|
+
return combined[0].text
|
|
250
|
+
return combined
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
_MAX_INLINE_ATTACHMENT_TEXT_BYTES = 64 * 1024
|
|
256
|
+
_TEXT_ATTACHMENT_SUFFIXES = {
|
|
257
|
+
".csv",
|
|
258
|
+
".html",
|
|
259
|
+
".htm",
|
|
260
|
+
".ini",
|
|
261
|
+
".json",
|
|
262
|
+
".jsonl",
|
|
263
|
+
".log",
|
|
264
|
+
".md",
|
|
265
|
+
".py",
|
|
266
|
+
".rst",
|
|
267
|
+
".toml",
|
|
268
|
+
".tsv",
|
|
269
|
+
".txt",
|
|
270
|
+
".xml",
|
|
271
|
+
".yaml",
|
|
272
|
+
".yml",
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
def _attachment_context_text(path: Path, item: Mapping[str, Any]) -> str:
|
|
277
|
+
"""Build model-visible context for a materialized Responses input file."""
|
|
278
|
+
|
|
279
|
+
name = str(item.get("filename") or path.name).replace('"', "'")
|
|
280
|
+
inline_data = item.get("inlineData")
|
|
281
|
+
inline_mime = inline_data.get("mimeType") if isinstance(inline_data, Mapping) else None
|
|
282
|
+
mime_type = str(item.get("mime_type") or inline_mime or "").strip().lower()
|
|
283
|
+
source = str(item.get("file_data") or item.get("file_url") or "")
|
|
284
|
+
data_url_match = re.match(r"data:([^;,]+)", source)
|
|
285
|
+
if not mime_type and data_url_match is not None:
|
|
286
|
+
mime_type = data_url_match.group(1).strip().lower()
|
|
287
|
+
is_text = mime_type.startswith("text/") or path.suffix.lower() in _TEXT_ATTACHMENT_SUFFIXES
|
|
288
|
+
header = f'<uploaded_attachment name="{name}" path="{path}">'
|
|
289
|
+
if not is_text:
|
|
290
|
+
return (
|
|
291
|
+
f"{header}\n"
|
|
292
|
+
"The uploaded file is available at the path above. Read it with an appropriate "
|
|
293
|
+
"tool before answering questions about its contents.\n"
|
|
294
|
+
"</uploaded_attachment>"
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
raw = path.read_bytes()
|
|
298
|
+
truncated = len(raw) > _MAX_INLINE_ATTACHMENT_TEXT_BYTES
|
|
299
|
+
text = raw[:_MAX_INLINE_ATTACHMENT_TEXT_BYTES].decode("utf-8", errors="replace")
|
|
300
|
+
suffix = "\n[attachment content truncated]" if truncated else ""
|
|
301
|
+
return f"{header}\n{text}{suffix}\n</uploaded_attachment>"
|