agentengine-sdk-python 0.8.2__py3-none-any.whl → 0.8.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.3.dist-info}/METADATA +18 -25
- {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.3.dist-info}/RECORD +224 -169
- ksadk/_build_provenance.json +1 -0
- ksadk/agui/_agent_helpers.py +4 -0
- ksadk/api/client.py +3 -0
- ksadk/builders/managed_runtime_builder.py +3 -0
- ksadk/cli/__init__.py +6 -0
- ksadk/cli/cmd_plugin.py +657 -0
- ksadk/codex/runtime.py +50 -8
- ksadk/configs/env_registry.py +31 -3
- ksadk/configs/settings.py +9 -0
- ksadk/context_engine/contributors.py +73 -8
- ksadk/conversations/__init__.py +19 -0
- ksadk/conversations/context.py +104 -24
- ksadk/conversations/contracts.py +266 -0
- ksadk/conversations/message_projection.py +19 -1
- ksadk/conversations/projector.py +616 -0
- ksadk/conversations/reducer.py +98 -0
- ksadk/events/_v1_compat/projection.py +2 -0
- ksadk/events/adapters/codex.py +190 -0
- ksadk/harness/__init__.py +45 -35
- ksadk/harness/runtime.py +60 -1
- ksadk/kernel/contract_fingerprints.py +5 -4
- ksadk/kernel/contracts.py +8 -0
- ksadk/kernel/control.py +1 -0
- ksadk/kernel/ingress.py +21 -0
- ksadk/kernel/memory_store.py +1 -0
- ksadk/kernel/postgres_store.py +1 -0
- ksadk/kernel/sqlite_store.py +1 -0
- ksadk/kernel/worker.py +11 -0
- ksadk/memory/providers/local_sqlite.py +7 -0
- ksadk/plugins/__init__.py +167 -0
- ksadk/plugins/bridges/__init__.py +45 -0
- ksadk/plugins/bridges/codex.py +552 -0
- ksadk/plugins/bridges/dsh.py +1116 -0
- ksadk/plugins/builtins.py +747 -0
- ksadk/plugins/bundle.py +246 -0
- ksadk/plugins/bundle_security.py +167 -0
- ksadk/plugins/composition.py +529 -0
- ksadk/plugins/context_contributor.py +437 -0
- ksadk/plugins/contracts.py +451 -0
- ksadk/plugins/dsh_toolchain.py +935 -0
- ksadk/plugins/ecosystem_bridge.py +1105 -0
- ksadk/plugins/ecosystem_probe.py +191 -0
- ksadk/plugins/host.py +724 -0
- ksadk/plugins/providers/__init__.py +85 -0
- ksadk/plugins/providers/bundles/ksadk-codex/cordis.patch.yml +3 -0
- ksadk/plugins/providers/bundles/ksadk-codex/index.mjs +18 -0
- ksadk/plugins/providers/bundles/ksadk-codex/package.json +19 -0
- ksadk/plugins/providers/bundles/ksadk-harness/cordis.patch.yml +3 -0
- ksadk/plugins/providers/bundles/ksadk-harness/index.mjs +19 -0
- ksadk/plugins/providers/bundles/ksadk-harness/package.json +19 -0
- ksadk/plugins/providers/codex.py +722 -0
- ksadk/plugins/providers/codex_dsh.py +83 -0
- ksadk/plugins/providers/dsh.py +951 -0
- ksadk/plugins/providers/dsh_descriptor_host.py +226 -0
- ksadk/plugins/providers/harness.py +627 -0
- ksadk/plugins/providers/harness_dsh.py +91 -0
- ksadk/plugins/providers/legacy.py +215 -0
- ksadk/plugins/providers/legacy_catalog.py +100 -0
- ksadk/plugins/providers/shipped_dsh.py +370 -0
- ksadk/plugins/resolver.py +331 -0
- ksadk/plugins/subagent_providers/__init__.py +12 -0
- ksadk/plugins/subagent_providers/codex.py +443 -0
- ksadk/plugins/subagents.py +333 -0
- ksadk/runtime/_runner_adapter/stream_mapping.py +51 -42
- ksadk/runtime/adapter.py +1 -0
- ksadk/runtime/factory.py +76 -2
- ksadk/runtime/framework_adapters.py +18 -0
- ksadk/runtime/runner_adapter.py +5 -0
- ksadk/sandbox/__init__.py +2 -1
- ksadk/sandbox/factory.py +72 -0
- ksadk/scheduler/__init__.py +18 -0
- ksadk/scheduler/calendar.py +102 -0
- ksadk/scheduler/contracts.py +254 -0
- ksadk/scheduler/dispatcher.py +129 -0
- ksadk/scheduler/engine.py +416 -0
- ksadk/scheduler/sqlite_store.py +563 -0
- ksadk/server/static/assets/{ArtifactsPanel-DSU1sWD_.js → ArtifactsPanel-10GPXIJ6.js} +1 -1
- ksadk/server/static/assets/{CodeBlock-DOH6MVcn.js → CodeBlock-BXk1l-G1.js} +1 -1
- ksadk/server/static/assets/{MathMessageMarkdown-BL8my1R2.js → MathMessageMarkdown-D9uB55Oh.js} +1 -1
- ksadk/server/static/assets/{MermaidBlock-Dz4IP-Tx.js → MermaidBlock--OEYoXIJ.js} +6 -6
- ksadk/server/static/assets/{NativeTerminalPanel-DUrK0JpZ.js → NativeTerminalPanel-DrEe1syq.js} +1 -1
- ksadk/server/static/assets/{abnfDiagram-VCTEODGH-g20pFzNV.js → abnfDiagram-VCTEODGH-eeTFJLvo.js} +1 -1
- ksadk/server/static/assets/{arc-C4FzinUA.js → arc-S3ZNbIAd.js} +1 -1
- ksadk/server/static/assets/architecture-7GRP2DOG-Dk9nRQ6-.js +1 -0
- ksadk/server/static/assets/{architectureDiagram-5GKGNRK7-DpIqL5h4.js → architectureDiagram-5GKGNRK7-CRjgEJDX.js} +1 -1
- ksadk/server/static/assets/{blockDiagram-NRAW4CY4-BjkljTNz.js → blockDiagram-NRAW4CY4-C7bsBoNH.js} +1 -1
- ksadk/server/static/assets/{c4Diagram-UCG6FXSJ-Dk_ieq2X.js → c4Diagram-UCG6FXSJ-BX3c33Ob.js} +1 -1
- ksadk/server/static/assets/channel-s354Yo6o.js +1 -0
- ksadk/server/static/assets/chunk-2Q5K7J3B-CDpPpKR5.js +1 -0
- ksadk/server/static/assets/{chunk-5VM5RSS4-BVHAchFb.js → chunk-5VM5RSS4-bZ7ws-8m.js} +1 -1
- ksadk/server/static/assets/{chunk-F27PBJKO-C-ipQzuS.js → chunk-F27PBJKO-D2r0pvhY.js} +1 -1
- ksadk/server/static/assets/{chunk-G27WJ6UU-C2EyJbIK.js → chunk-G27WJ6UU-CZwF3oUP.js} +1 -1
- ksadk/server/static/assets/{chunk-JWPE2WC7-vYvVJb_M.js → chunk-JWPE2WC7-DigFYCML.js} +1 -1
- ksadk/server/static/assets/{chunk-LCL6LL3I-BcI6ysPT.js → chunk-LCL6LL3I-CnorGV5q.js} +1 -1
- ksadk/server/static/assets/{chunk-POPQ4Y6H-C030x_Z1.js → chunk-POPQ4Y6H-CexntQA-.js} +1 -1
- ksadk/server/static/assets/{chunk-RHFEMEQ7-yyGpsz4n.js → chunk-RHFEMEQ7-CHTC7UxA.js} +1 -1
- ksadk/server/static/assets/{chunk-SVP7TREG-BLTlmMU7.js → chunk-SVP7TREG-BC1EWt_-.js} +1 -1
- ksadk/server/static/assets/{chunk-XXDRQBXY-C_32ArgP.js → chunk-XXDRQBXY-BTG24xN0.js} +1 -1
- ksadk/server/static/assets/classDiagram-DTDB5LWJ-Dd0nucl9.js +1 -0
- ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-Dd0nucl9.js +1 -0
- ksadk/server/static/assets/{cose-bilkent-JH36ORCC-9YQYwdl0.js → cose-bilkent-JH36ORCC-CkonRdAS.js} +1 -1
- ksadk/server/static/assets/cynefin-OW5HDTMX-BBlT4uMf.js +1 -0
- ksadk/server/static/assets/{cynefinDiagram-5FMLGOSQ-ErLF5N13.js → cynefinDiagram-5FMLGOSQ-DEOCBe15.js} +1 -1
- ksadk/server/static/assets/{dagre-3AP2YEHR-DFiQF-6f.js → dagre-3AP2YEHR-DBThPuLa.js} +1 -1
- ksadk/server/static/assets/{dagre-BuhGnRI1.js → dagre-ClTPrTht.js} +1 -1
- ksadk/server/static/assets/{diagram-S7CK7UJ4-Bt1v8-GC.js → diagram-S7CK7UJ4-DsZHrnpJ.js} +1 -1
- ksadk/server/static/assets/{diagram-UQ7AKVKN-DSCxJdBK.js → diagram-UQ7AKVKN-BJR4nhVr.js} +1 -1
- ksadk/server/static/assets/{diagram-VSXAHHWV-DHfYwp_9.js → diagram-VSXAHHWV-xzcERX0a.js} +1 -1
- ksadk/server/static/assets/{diagram-VX7I27RA-DdzD-4Le.js → diagram-VX7I27RA-tn2xM1xu.js} +1 -1
- ksadk/server/static/assets/{diagram-Z3DM3KII-Du-nAJ9F.js → diagram-Z3DM3KII-BZPGBkw5.js} +1 -1
- ksadk/server/static/assets/{dist-ClxGviKw.js → dist-4zN1_tq5.js} +1 -1
- ksadk/server/static/assets/{dist-BE7bu-DL.js → dist-8VWI-2bZ.js} +1 -1
- ksadk/server/static/assets/{dist-BX8z72IC.js → dist-B-46q3Hk.js} +1 -1
- ksadk/server/static/assets/{dist-BjU6y-A2.js → dist-B0gdk4rl.js} +1 -1
- ksadk/server/static/assets/{dist-C_wsv-Qd.js → dist-B1oWRmrH.js} +1 -1
- ksadk/server/static/assets/{dist-ngtN0DJB.js → dist-BI1qQH4n.js} +1 -1
- ksadk/server/static/assets/{dist-dydu68Fl.js → dist-BJLUwH6W.js} +1 -1
- ksadk/server/static/assets/{dist-Dq9gLD7L.js → dist-Bbwqa8TG.js} +1 -1
- ksadk/server/static/assets/{dist-CttYUqzS.js → dist-Btyo4vX4.js} +1 -1
- ksadk/server/static/assets/{dist-CXYYBw3_.js → dist-C71CsujO.js} +1 -1
- ksadk/server/static/assets/{dist-dDdADKFA.js → dist-CXpH_Rdd.js} +1 -1
- ksadk/server/static/assets/{dist-CSh_DE14.js → dist-Cq4OL6nO.js} +1 -1
- ksadk/server/static/assets/{dist-8hqcx0sU.js → dist-D1V3f1B4.js} +1 -1
- ksadk/server/static/assets/{dist-BVDffZ0U.js → dist-DJmCPRVB.js} +1 -1
- ksadk/server/static/assets/{dist-DnfXs8Vn.js → dist-DQAB0qn_.js} +1 -1
- ksadk/server/static/assets/{dist-DNp6rLRA.js → dist-DUwKa_l6.js} +1 -1
- ksadk/server/static/assets/{dist-B7seoj3d.js → dist-DdRBIceA.js} +1 -1
- ksadk/server/static/assets/{dist-BytlxIDT.js → dist-DfGFrb0v.js} +1 -1
- ksadk/server/static/assets/{dist-Bf2M8m3N.js → dist-DjhwGUgZ.js} +1 -1
- ksadk/server/static/assets/{dist-W-TIVntx.js → dist-DyqV4fL4.js} +1 -1
- ksadk/server/static/assets/{dist-DUX-id_F.js → dist-M67Hwu0n.js} +1 -1
- ksadk/server/static/assets/{dist-DmldrHd_.js → dist-u8tVH5Ak.js} +1 -1
- ksadk/server/static/assets/{ebnfDiagram-PWID7BFC-Da9C9NO1.js → ebnfDiagram-PWID7BFC-DVfMsLge.js} +1 -1
- ksadk/server/static/assets/{erDiagram-SSCWMZ5O-EAGqqR79.js → erDiagram-SSCWMZ5O-CWEZSYaw.js} +1 -1
- ksadk/server/static/assets/eventmodeling-NTZA5JFV-Dr5okd8V.js +1 -0
- ksadk/server/static/assets/flowDiagram-A5DVABFB-VEO-cVcO.js +1 -0
- ksadk/server/static/assets/{ganttDiagram-EL5Y4UJY-DqJsKb59.js → ganttDiagram-EL5Y4UJY-TWIxoyYL.js} +1 -1
- ksadk/server/static/assets/gitGraph-4MIJSDKK-CKiKY9Cf.js +1 -0
- ksadk/server/static/assets/{gitGraphDiagram-WWUBYQGX-B6g4dtDi.js → gitGraphDiagram-WWUBYQGX-DDh2hd2S.js} +1 -1
- ksadk/server/static/assets/index-B2k_urY8.js +241 -0
- ksadk/server/static/assets/index-ILPt6IWF.css +2 -0
- ksadk/server/static/assets/info-A6RAGUB7-ubA4Nm_p.js +1 -0
- ksadk/server/static/assets/{infoDiagram-RXCK75RN-Djm_nbd5.js → infoDiagram-RXCK75RN-CgoyWiDR.js} +1 -1
- ksadk/server/static/assets/{ishikawaDiagram-5VMMS53U-DWya9SG2.js → ishikawaDiagram-5VMMS53U-CyRIu_om.js} +1 -1
- ksadk/server/static/assets/{journeyDiagram-EYS64GPL-DutxhSNI.js → journeyDiagram-EYS64GPL-DN5JXHzN.js} +1 -1
- ksadk/server/static/assets/{kanban-definition-3QL26DDD-DJdOF8Fm.js → kanban-definition-3QL26DDD-CNP3ui66.js} +1 -1
- ksadk/server/static/assets/{katex-vFWytM5c.js → katex-DWEzQy1d.js} +1 -1
- ksadk/server/static/assets/{linear-BHjG8b-J.js → linear-C-qHp7d2.js} +1 -1
- ksadk/server/static/assets/{mermaid-parser.core-KGSy4jWT.js → mermaid-parser.core-Cl-K943T.js} +2 -2
- ksadk/server/static/assets/{mindmap-definition-FBJOCRG2-9-HC88D4.js → mindmap-definition-FBJOCRG2-D5DB5mYm.js} +1 -1
- ksadk/server/static/assets/packet-AYTQ26CC-C7R3NUlK.js +1 -0
- ksadk/server/static/assets/{pegDiagram-XKGWAZYB-DrEZd4fD.js → pegDiagram-XKGWAZYB-BQVc9ia_.js} +1 -1
- ksadk/server/static/assets/pie-WAS4IAKB-BIT6qjr3.js +1 -0
- ksadk/server/static/assets/{pieDiagram-E7YTZNPT-DpjqOFFp.js → pieDiagram-E7YTZNPT-B6UCAvtY.js} +1 -1
- ksadk/server/static/assets/{quadrantDiagram-AXDQQJYC-BiNhgOXX.js → quadrantDiagram-AXDQQJYC-mIr2d3eb.js} +1 -1
- ksadk/server/static/assets/radar-RG4KPBEZ-l5noef9X.js +1 -0
- ksadk/server/static/assets/railroad-74A4TZTK-Baea6ZvM.js +1 -0
- ksadk/server/static/assets/railroad-abnf-HS5TGJTU-OKn8zZnU.js +1 -0
- ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-DdKAKC4l.js +1 -0
- ksadk/server/static/assets/railroad-peg-WCYAUIDC-Bds8udlG.js +1 -0
- ksadk/server/static/assets/{railroadDiagram-O6MQD6OU-_Y3Ojg6G.js → railroadDiagram-O6MQD6OU-Dt3FFDmK.js} +1 -1
- ksadk/server/static/assets/{requirementDiagram-EFPCY7ZU-DeCFdg9K.js → requirementDiagram-EFPCY7ZU-Cz_vQtgF.js} +1 -1
- ksadk/server/static/assets/{sankeyDiagram-P5KCCOFB-CPH75rhw.js → sankeyDiagram-P5KCCOFB-wlO1TsH5.js} +1 -1
- ksadk/server/static/assets/{sequenceDiagram-WJ2MYXX4-OEpQQdr4.js → sequenceDiagram-WJ2MYXX4-CHRbElYq.js} +1 -1
- ksadk/server/static/assets/{sizeCapture-X5ZJPWSS-heUErzhI.js → sizeCapture-X5ZJPWSS-DXX54iyO.js} +1 -1
- ksadk/server/static/assets/{stateDiagram-HBIQ2CUA-DvA3jSMB.js → stateDiagram-HBIQ2CUA-Dp_lw9II.js} +1 -1
- ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-5b-8o2iS.js +1 -0
- ksadk/server/static/assets/{swimlanes-XN3QIQJK-CR-dfN_t.js → swimlanes-XN3QIQJK-D8O5UlLG.js} +1 -1
- ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-uf6WPRA4.js +8 -0
- ksadk/server/static/assets/{timeline-definition-24CTP7MA-DAVJf1TX.js → timeline-definition-24CTP7MA-8mfKcxvG.js} +1 -1
- ksadk/server/static/assets/treeView-Q6P3EWNA-CK5CSrSO.js +1 -0
- ksadk/server/static/assets/treemap-WGGIJYW6-Ch2BKgAM.js +1 -0
- ksadk/server/static/assets/{vennDiagram-4TSXK5OY-DwM8eDkh.js → vennDiagram-4TSXK5OY-EnNl0DE7.js} +1 -1
- ksadk/server/static/assets/wardley-WFR3VGLG-YW3Q0ml_.js +1 -0
- ksadk/server/static/assets/{wardleyDiagram-VM6X3IG4-DZL-Zz2t.js → wardleyDiagram-VM6X3IG4-DBu5fbYr.js} +1 -1
- ksadk/server/static/assets/{xychartDiagram-S5SC5T6Z-Dy6Yh_hu.js → xychartDiagram-S5SC5T6Z-BSVXs4IY.js} +1 -1
- ksadk/server/static/index.html +2 -2
- ksadk/skills/service_client.py +48 -0
- ksadk/studio/agent_lifecycle.py +26 -20
- ksadk/studio/api.py +513 -71
- ksadk/studio/api_catalog_routes.py +5 -0
- ksadk/studio/api_contracts.py +34 -1
- ksadk/studio/api_plugin_routes.py +480 -0
- ksadk/studio/attachment_store.py +187 -0
- ksadk/studio/authoring.py +10 -4
- ksadk/studio/authoring_coordinator.py +12 -2
- ksadk/studio/builder.py +123 -43
- ksadk/studio/cloud.py +4 -0
- ksadk/studio/codex_agent_service.py +12 -1
- ksadk/studio/codex_builder.py +54 -15
- ksadk/studio/codex_manifest.py +21 -1
- ksadk/studio/codex_run.py +16 -4
- ksadk/studio/compatibility_report.py +445 -0
- ksadk/studio/compiler.py +6 -1
- ksadk/studio/contracts.py +123 -4
- ksadk/studio/dsh_provider_registration.py +768 -0
- ksadk/studio/event_store.py +54 -6
- ksadk/studio/framework_run.py +37 -4
- ksadk/studio/hosted_kernel.py +1 -1
- ksadk/studio/operations.py +12 -2
- ksadk/studio/plugin_composition.py +301 -0
- ksadk/studio/plugin_kernel_adapter.py +128 -0
- ksadk/studio/plugin_runtime.py +652 -0
- ksadk/studio/resource_catalog.py +6 -1
- ksadk/studio/run_service.py +713 -75
- ksadk/studio/runtime_source.py +9 -1
- ksadk/studio/scheduler_runtime.py +374 -0
- ksadk/studio/scheduler_service.py +211 -0
- ksadk/studio/service.py +672 -82
- ksadk/studio/shared_web.py +167 -28
- ksadk/studio/soul.py +52 -0
- ksadk/studio/static/assets/index-DXs1Eq4M.css +1 -0
- ksadk/studio/static/assets/index-DeDqwTsD.js +283 -0
- ksadk/studio/static/index.html +2 -2
- ksadk/studio/validator.py +1 -1
- ksadk/studio/workspace.py +1 -0
- ksadk/version.py +1 -1
- ksadk_runtime_common/workspace_files/path_utils.py +41 -0
- ksadk/server/static/assets/architecture-7GRP2DOG-DjKratdf.js +0 -1
- ksadk/server/static/assets/channel-4cQHKtx1.js +0 -1
- ksadk/server/static/assets/chunk-2Q5K7J3B-DmgWkESh.js +0 -1
- ksadk/server/static/assets/classDiagram-DTDB5LWJ-DLFd9Xi0.js +0 -1
- ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-DLFd9Xi0.js +0 -1
- ksadk/server/static/assets/cynefin-OW5HDTMX-DjEM48Qp.js +0 -1
- ksadk/server/static/assets/eventmodeling-NTZA5JFV-CMgMaJrC.js +0 -1
- ksadk/server/static/assets/flowDiagram-A5DVABFB-BBKL0x3P.js +0 -1
- ksadk/server/static/assets/gitGraph-4MIJSDKK-Dw63mrhw.js +0 -1
- ksadk/server/static/assets/index-8ipRcQ-M.js +0 -240
- ksadk/server/static/assets/index-ByFCqjlh.css +0 -2
- ksadk/server/static/assets/info-A6RAGUB7-B6iAblII.js +0 -1
- ksadk/server/static/assets/packet-AYTQ26CC-BOYAipuq.js +0 -1
- ksadk/server/static/assets/pie-WAS4IAKB-Ctq0Kbku.js +0 -1
- ksadk/server/static/assets/radar-RG4KPBEZ-DN0-ul_0.js +0 -1
- ksadk/server/static/assets/railroad-74A4TZTK-C6cC_to0.js +0 -1
- ksadk/server/static/assets/railroad-abnf-HS5TGJTU-BimjIuRc.js +0 -1
- ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-CvY65ABq.js +0 -1
- ksadk/server/static/assets/railroad-peg-WCYAUIDC-D72Iq_Tv.js +0 -1
- ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-BgQY03nz.js +0 -1
- ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-DLVw3q5Q.js +0 -8
- ksadk/server/static/assets/treeView-Q6P3EWNA-BMpO0wsB.js +0 -1
- ksadk/server/static/assets/treemap-WGGIJYW6-Et0aqzU3.js +0 -1
- ksadk/server/static/assets/wardley-WFR3VGLG-CbY0mhpl.js +0 -1
- ksadk/studio/static/assets/index-BLpcdrgW.css +0 -1
- ksadk/studio/static/assets/index-CYekR2Xv.js +0 -260
- {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.3.dist-info}/WHEEL +0 -0
- {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.3.dist-info}/entry_points.txt +0 -0
- {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.3.dist-info}/licenses/LICENSE +0 -0
- {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.3.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"""Identity-aware reducer for a ConversationItem surface.
|
|
2
|
+
|
|
3
|
+
This reducer deliberately does not deduplicate by author or text. Providers
|
|
4
|
+
may emit the same content in two different items, and both are user-visible
|
|
5
|
+
truth. Reconnect de-duplication is limited to a previously applied source
|
|
6
|
+
event for the same item.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from collections import OrderedDict
|
|
12
|
+
|
|
13
|
+
from ksadk.conversations.contracts import ConversationItem
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ConversationItemReducer:
|
|
17
|
+
"""Apply append/replace/completed operations while preserving item identity."""
|
|
18
|
+
|
|
19
|
+
def __init__(self) -> None:
|
|
20
|
+
self._items: OrderedDict[str, ConversationItem] = OrderedDict()
|
|
21
|
+
self._source_events: set[tuple[str, str]] = set()
|
|
22
|
+
|
|
23
|
+
def apply(self, item: ConversationItem) -> bool:
|
|
24
|
+
"""Apply one item operation and return whether this changed the view."""
|
|
25
|
+
|
|
26
|
+
keys = {(item.item_id, source_id) for source_id in item.source_event_ids}
|
|
27
|
+
if keys and keys.issubset(self._source_events):
|
|
28
|
+
return False
|
|
29
|
+
|
|
30
|
+
existing = self._items.get(item.item_id)
|
|
31
|
+
if existing is not None and _terminal(existing) and not _terminal(item):
|
|
32
|
+
# A reconnect may replay an older delta after the terminal snapshot
|
|
33
|
+
# has already arrived on the live connection. Remember its event
|
|
34
|
+
# identity, but never regress a completed item back to streaming or
|
|
35
|
+
# append the stale delta a second time.
|
|
36
|
+
self._source_events.update(keys)
|
|
37
|
+
return False
|
|
38
|
+
if existing is None:
|
|
39
|
+
merged = item
|
|
40
|
+
elif item.operation == "append":
|
|
41
|
+
merged = item.model_copy(
|
|
42
|
+
update={
|
|
43
|
+
"payload": _append_payload(existing.payload, item.payload),
|
|
44
|
+
"source_event_ids": _merge_sources(
|
|
45
|
+
existing.source_event_ids,
|
|
46
|
+
item.source_event_ids,
|
|
47
|
+
),
|
|
48
|
+
}
|
|
49
|
+
)
|
|
50
|
+
else:
|
|
51
|
+
merged = item.model_copy(
|
|
52
|
+
update={
|
|
53
|
+
"source_event_ids": _merge_sources(
|
|
54
|
+
existing.source_event_ids,
|
|
55
|
+
item.source_event_ids,
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
)
|
|
59
|
+
self._items[item.item_id] = merged
|
|
60
|
+
self._source_events.update(keys)
|
|
61
|
+
return True
|
|
62
|
+
|
|
63
|
+
def items(self) -> tuple[ConversationItem, ...]:
|
|
64
|
+
"""Return presentation items in first-seen order."""
|
|
65
|
+
|
|
66
|
+
return tuple(self._items.values())
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _append_payload(
|
|
70
|
+
existing: dict[str, object],
|
|
71
|
+
update: dict[str, object],
|
|
72
|
+
) -> dict[str, object]:
|
|
73
|
+
merged = dict(existing)
|
|
74
|
+
for key, value in update.items():
|
|
75
|
+
previous = merged.get(key)
|
|
76
|
+
if key == "text" and isinstance(previous, str) and isinstance(value, str):
|
|
77
|
+
merged[key] = previous + value
|
|
78
|
+
elif key in {"data", "operations"} and isinstance(previous, list) and isinstance(
|
|
79
|
+
value, list
|
|
80
|
+
):
|
|
81
|
+
merged[key] = [*previous, *value]
|
|
82
|
+
else:
|
|
83
|
+
merged[key] = value
|
|
84
|
+
return merged
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _merge_sources(
|
|
88
|
+
current: tuple[str, ...],
|
|
89
|
+
incoming: tuple[str, ...],
|
|
90
|
+
) -> tuple[str, ...]:
|
|
91
|
+
return tuple(dict.fromkeys((*current, *incoming)))
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _terminal(item: ConversationItem) -> bool:
|
|
95
|
+
return item.lifecycle in {"completed", "failed"}
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
__all__ = ["ConversationItemReducer"]
|
|
@@ -370,6 +370,8 @@ def _project_item_completed(
|
|
|
370
370
|
if text_projection or event.item_kind in {"message", "reasoning"}:
|
|
371
371
|
return text_projection
|
|
372
372
|
if event.item_kind == "data":
|
|
373
|
+
if event.source.metadata.get("operation_batch") is True:
|
|
374
|
+
return ()
|
|
373
375
|
ref = _a2ui_surface_ref(event, context)
|
|
374
376
|
if ref is None:
|
|
375
377
|
return ()
|
ksadk/events/adapters/codex.py
CHANGED
|
@@ -48,6 +48,7 @@ from ksadk.events.canonical import (
|
|
|
48
48
|
ContinuationCreated,
|
|
49
49
|
ContinuationResumed,
|
|
50
50
|
ErrorInfo,
|
|
51
|
+
InteractionRequested,
|
|
51
52
|
ItemCompleted,
|
|
52
53
|
ItemFailed,
|
|
53
54
|
ItemStarted,
|
|
@@ -56,10 +57,12 @@ from ksadk.events.canonical import (
|
|
|
56
57
|
RunCanceled,
|
|
57
58
|
RunCompleted,
|
|
58
59
|
RunFailed,
|
|
60
|
+
RunInterrupted,
|
|
59
61
|
RunProgress,
|
|
60
62
|
RunStarted,
|
|
61
63
|
RuntimeEvent,
|
|
62
64
|
SourceRef,
|
|
65
|
+
StructuredInputRequest,
|
|
63
66
|
UsageReported,
|
|
64
67
|
)
|
|
65
68
|
from ksadk.events.content import (
|
|
@@ -191,6 +194,20 @@ class CodexEventAdapter(_CodexInteractionMixin):
|
|
|
191
194
|
return self._map_server_request_resolved(
|
|
192
195
|
params=params, context=context, cursor=cursor, timestamp=timestamp
|
|
193
196
|
)
|
|
197
|
+
if method == "a2ui/surface":
|
|
198
|
+
return self._map_a2ui_surface(
|
|
199
|
+
params=params,
|
|
200
|
+
context=context,
|
|
201
|
+
cursor=cursor,
|
|
202
|
+
timestamp=timestamp,
|
|
203
|
+
)
|
|
204
|
+
if method == "a2ui/interaction":
|
|
205
|
+
return self._map_a2ui_interaction(
|
|
206
|
+
params=params,
|
|
207
|
+
context=context,
|
|
208
|
+
cursor=cursor,
|
|
209
|
+
timestamp=timestamp,
|
|
210
|
+
)
|
|
194
211
|
if method in _CONTROL_INTERACTION_METHODS:
|
|
195
212
|
return self._map_control_interaction_request(
|
|
196
213
|
message=message,
|
|
@@ -255,6 +272,179 @@ class CodexEventAdapter(_CodexInteractionMixin):
|
|
|
255
272
|
)
|
|
256
273
|
_fail("unsupported_method", "method", f"Unsupported Codex app-server method: {method}")
|
|
257
274
|
|
|
275
|
+
@staticmethod
|
|
276
|
+
def _a2ui_scope(
|
|
277
|
+
params: Mapping[str, Any],
|
|
278
|
+
context: CodexAdapterContext,
|
|
279
|
+
*,
|
|
280
|
+
surface_id: str,
|
|
281
|
+
) -> tuple[str, str, str]:
|
|
282
|
+
thread_value = params.get("threadId", params.get("thread_id"))
|
|
283
|
+
turn_value = params.get("turnId", params.get("turn_id"))
|
|
284
|
+
thread_id = (
|
|
285
|
+
_required_string(thread_value, "params.threadId")
|
|
286
|
+
if thread_value is not None
|
|
287
|
+
else f"runtime:{context.run_id}"
|
|
288
|
+
)
|
|
289
|
+
turn_id = (
|
|
290
|
+
_required_string(turn_value, "params.turnId")
|
|
291
|
+
if turn_value is not None
|
|
292
|
+
else "a2ui"
|
|
293
|
+
)
|
|
294
|
+
return thread_id, turn_id, stable_scope_id("codex", thread_id, turn_id, surface_id)
|
|
295
|
+
|
|
296
|
+
@staticmethod
|
|
297
|
+
def _a2ui_source(
|
|
298
|
+
*,
|
|
299
|
+
method: str,
|
|
300
|
+
cursor: str,
|
|
301
|
+
thread_id: str,
|
|
302
|
+
turn_id: str,
|
|
303
|
+
native_item_id: str,
|
|
304
|
+
surface_id: str,
|
|
305
|
+
metadata: Mapping[str, Any] | None = None,
|
|
306
|
+
) -> SourceRef:
|
|
307
|
+
source = _protocol_source(
|
|
308
|
+
method=method,
|
|
309
|
+
cursor=cursor,
|
|
310
|
+
thread_id=thread_id,
|
|
311
|
+
turn_id=turn_id,
|
|
312
|
+
native_item_id=native_item_id,
|
|
313
|
+
native_event_id=native_item_id,
|
|
314
|
+
)
|
|
315
|
+
return source.model_copy(
|
|
316
|
+
update={
|
|
317
|
+
"protocol": "a2ui",
|
|
318
|
+
"metadata": {
|
|
319
|
+
**source.metadata,
|
|
320
|
+
"surface_id": surface_id,
|
|
321
|
+
**dict(metadata or {}),
|
|
322
|
+
},
|
|
323
|
+
}
|
|
324
|
+
)
|
|
325
|
+
|
|
326
|
+
def _map_a2ui_surface(
|
|
327
|
+
self,
|
|
328
|
+
*,
|
|
329
|
+
params: Mapping[str, Any],
|
|
330
|
+
context: CodexAdapterContext,
|
|
331
|
+
cursor: str,
|
|
332
|
+
timestamp: float,
|
|
333
|
+
) -> tuple[RuntimeEvent, ...]:
|
|
334
|
+
"""Map one complete A2UI surface description as an immutable operation batch."""
|
|
335
|
+
|
|
336
|
+
surface_id = _required_string(params.get("surface_id"), "params.surface_id")
|
|
337
|
+
surface = _mapping(params.get("surface"), "params.surface")
|
|
338
|
+
thread_id, turn_id, scope_id = self._a2ui_scope(
|
|
339
|
+
params, context, surface_id=surface_id
|
|
340
|
+
)
|
|
341
|
+
item_id = stable_item_id("codex", scope_id, "a2ui-surface", surface_id)
|
|
342
|
+
source = self._a2ui_source(
|
|
343
|
+
method="a2ui/surface",
|
|
344
|
+
cursor=cursor,
|
|
345
|
+
thread_id=thread_id,
|
|
346
|
+
turn_id=turn_id,
|
|
347
|
+
native_item_id=surface_id,
|
|
348
|
+
surface_id=surface_id,
|
|
349
|
+
metadata={
|
|
350
|
+
"operation_batch": True,
|
|
351
|
+
"surface_lifecycle": "begin",
|
|
352
|
+
"catalog_id": str(surface.get("catalog_id") or surface.get("catalogId") or ""),
|
|
353
|
+
},
|
|
354
|
+
)
|
|
355
|
+
snapshot = ContentSnapshot(
|
|
356
|
+
parts=(
|
|
357
|
+
DataContent(
|
|
358
|
+
part_id="a2ui-surface",
|
|
359
|
+
data={"surface_id": surface_id, **_json_value(surface)},
|
|
360
|
+
),
|
|
361
|
+
)
|
|
362
|
+
)
|
|
363
|
+
env = _envelope(context, cursor, timestamp)
|
|
364
|
+
return (
|
|
365
|
+
ItemStarted(
|
|
366
|
+
**env(scope_id, item_id, "item.started", "a2ui-surface", source),
|
|
367
|
+
item_id=item_id,
|
|
368
|
+
item_kind="data",
|
|
369
|
+
initial=snapshot,
|
|
370
|
+
),
|
|
371
|
+
ItemCompleted(
|
|
372
|
+
**env(scope_id, item_id, "item.completed", "a2ui-surface", source),
|
|
373
|
+
item_id=item_id,
|
|
374
|
+
item_kind="data",
|
|
375
|
+
snapshot=snapshot,
|
|
376
|
+
),
|
|
377
|
+
)
|
|
378
|
+
|
|
379
|
+
def _map_a2ui_interaction(
|
|
380
|
+
self,
|
|
381
|
+
*,
|
|
382
|
+
params: Mapping[str, Any],
|
|
383
|
+
context: CodexAdapterContext,
|
|
384
|
+
cursor: str,
|
|
385
|
+
timestamp: float,
|
|
386
|
+
) -> tuple[RuntimeEvent, ...]:
|
|
387
|
+
"""Map the client-owned A2UI input request without changing its live call id."""
|
|
388
|
+
|
|
389
|
+
surface_id = _required_string(params.get("surface_id"), "params.surface_id")
|
|
390
|
+
interaction_id = _required_string(
|
|
391
|
+
params.get("interaction_id"), "params.interaction_id"
|
|
392
|
+
)
|
|
393
|
+
kind = _required_string(params.get("kind"), "params.kind")
|
|
394
|
+
schema = _mapping(params.get("input_schema"), "params.input_schema")
|
|
395
|
+
is_blocking = params.get("is_blocking", True)
|
|
396
|
+
if not isinstance(is_blocking, bool):
|
|
397
|
+
_fail(
|
|
398
|
+
"invalid_interaction_request",
|
|
399
|
+
"params.is_blocking",
|
|
400
|
+
"A2UI is_blocking must be a boolean",
|
|
401
|
+
)
|
|
402
|
+
thread_id, turn_id, scope_id = self._a2ui_scope(
|
|
403
|
+
params, context, surface_id=surface_id
|
|
404
|
+
)
|
|
405
|
+
source = self._a2ui_source(
|
|
406
|
+
method="a2ui/interaction",
|
|
407
|
+
cursor=cursor,
|
|
408
|
+
thread_id=thread_id,
|
|
409
|
+
turn_id=turn_id,
|
|
410
|
+
native_item_id=interaction_id,
|
|
411
|
+
surface_id=surface_id,
|
|
412
|
+
metadata={"kind": kind, "is_blocking": is_blocking},
|
|
413
|
+
)
|
|
414
|
+
env = _envelope(context, cursor, timestamp)
|
|
415
|
+
requested = InteractionRequested(
|
|
416
|
+
**env(
|
|
417
|
+
scope_id,
|
|
418
|
+
interaction_id,
|
|
419
|
+
"interaction.requested",
|
|
420
|
+
"structured_input",
|
|
421
|
+
source,
|
|
422
|
+
),
|
|
423
|
+
interaction_id=interaction_id,
|
|
424
|
+
interaction_kind="structured_input",
|
|
425
|
+
request=StructuredInputRequest(prompt=None, schema=_json_value(schema)),
|
|
426
|
+
)
|
|
427
|
+
if not is_blocking:
|
|
428
|
+
return (requested,)
|
|
429
|
+
return (
|
|
430
|
+
requested,
|
|
431
|
+
RunInterrupted(
|
|
432
|
+
**env(
|
|
433
|
+
scope_id,
|
|
434
|
+
turn_id,
|
|
435
|
+
"run.interrupted",
|
|
436
|
+
interaction_id,
|
|
437
|
+
source,
|
|
438
|
+
),
|
|
439
|
+
status="interrupted",
|
|
440
|
+
reason="Codex requires user interaction",
|
|
441
|
+
interaction_id=interaction_id,
|
|
442
|
+
continuation_id=self._thread_continuations.setdefault(
|
|
443
|
+
thread_id, _thread_continuation_identity(thread_id)[1]
|
|
444
|
+
),
|
|
445
|
+
),
|
|
446
|
+
)
|
|
447
|
+
|
|
258
448
|
def _map_token_usage(
|
|
259
449
|
self,
|
|
260
450
|
*,
|
ksadk/harness/__init__.py
CHANGED
|
@@ -1,35 +1,45 @@
|
|
|
1
|
-
"""
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
from
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
)
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
1
|
+
"""Public Harness surface without eagerly requiring an ADK runtime.
|
|
2
|
+
|
|
3
|
+
Studio must be usable for Codex and DSH Providers from a base ``ksadk``
|
|
4
|
+
installation. Harness keeps ADK as an optional execution dependency, so
|
|
5
|
+
importing its configuration types cannot import the full Harness runtime.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from importlib import import_module
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
_EXPORTS = {
|
|
14
|
+
"HarnessApp": ("ksadk.harness.app", "HarnessApp"),
|
|
15
|
+
"HarnessCapabilities": ("ksadk.harness.app", "HarnessCapabilities"),
|
|
16
|
+
"HarnessPlugin": ("ksadk.harness.app", "HarnessPlugin"),
|
|
17
|
+
"HarnessConfig": ("ksadk.harness.config", "HarnessConfig"),
|
|
18
|
+
"HarnessConfigError": ("ksadk.harness.config", "HarnessConfigError"),
|
|
19
|
+
"McpToolSpec": ("ksadk.harness.config", "McpToolSpec"),
|
|
20
|
+
"SandboxPolicy": ("ksadk.harness.config", "SandboxPolicy"),
|
|
21
|
+
"HarnessReasoner": ("ksadk.harness.reasoner", "HarnessReasoner"),
|
|
22
|
+
"HarnessReasoningTurn": ("ksadk.harness.reasoner", "HarnessReasoningTurn"),
|
|
23
|
+
"HarnessToolCall": ("ksadk.harness.reasoner", "HarnessToolCall"),
|
|
24
|
+
"LiteLLMHarnessReasoner": ("ksadk.harness.reasoner", "LiteLLMHarnessReasoner"),
|
|
25
|
+
"HarnessRuntime": ("ksadk.harness.runtime", "HarnessRuntime"),
|
|
26
|
+
"HarnessRuntimeAdapter": ("ksadk.harness.runtime", "HarnessRuntimeAdapter"),
|
|
27
|
+
"HarnessSandboxExecutor": ("ksadk.harness.sandbox", "HarnessSandboxExecutor"),
|
|
28
|
+
"SandboxPolicyDenied": ("ksadk.harness.sandbox", "SandboxPolicyDenied"),
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
__all__ = list(_EXPORTS)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def __getattr__(name: str) -> Any:
|
|
35
|
+
try:
|
|
36
|
+
module_name, attribute = _EXPORTS[name]
|
|
37
|
+
except KeyError:
|
|
38
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}") from None
|
|
39
|
+
value = getattr(import_module(module_name), attribute)
|
|
40
|
+
globals()[name] = value
|
|
41
|
+
return value
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def __dir__() -> list[str]:
|
|
45
|
+
return sorted({*globals(), *__all__})
|
ksadk/harness/runtime.py
CHANGED
|
@@ -72,6 +72,19 @@ class _HarnessRun:
|
|
|
72
72
|
done: bool = False
|
|
73
73
|
|
|
74
74
|
|
|
75
|
+
@dataclass
|
|
76
|
+
class _HarnessSession:
|
|
77
|
+
"""Process-local transcript and serialization boundary for one Session.
|
|
78
|
+
|
|
79
|
+
The public capability matrix deliberately advertises process-scoped,
|
|
80
|
+
non-durable continuity. Keeping this state on the adapter makes that
|
|
81
|
+
declaration true without pretending that a restart can recover it.
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
messages: list[dict[str, Any]]
|
|
85
|
+
lock: asyncio.Lock
|
|
86
|
+
|
|
87
|
+
|
|
75
88
|
class HarnessRuntimeAdapter(RuntimeAdapter):
|
|
76
89
|
"""Execute a YAML Harness config directly as RuntimeEvent streams."""
|
|
77
90
|
|
|
@@ -95,6 +108,7 @@ class HarnessRuntimeAdapter(RuntimeAdapter):
|
|
|
95
108
|
self._tools: tuple[HarnessTool, ...] | None = None
|
|
96
109
|
self._tool_lock = asyncio.Lock()
|
|
97
110
|
self._mcp_toolsets: list[Any] = []
|
|
111
|
+
self._sessions: dict[tuple[str, str, str], _HarnessSession] = {}
|
|
98
112
|
|
|
99
113
|
@property
|
|
100
114
|
def harness_config(self) -> HarnessConfig:
|
|
@@ -167,16 +181,43 @@ class HarnessRuntimeAdapter(RuntimeAdapter):
|
|
|
167
181
|
if not self._runs:
|
|
168
182
|
await self._close_tools()
|
|
169
183
|
|
|
184
|
+
async def close_all(self) -> None:
|
|
185
|
+
"""Dispose every process-local run owned by this adapter instance."""
|
|
186
|
+
|
|
187
|
+
for run_id, run in list(self._runs.items()):
|
|
188
|
+
await self.close(
|
|
189
|
+
RunHandle(
|
|
190
|
+
run_id=run_id,
|
|
191
|
+
session_id=run.request.session_id,
|
|
192
|
+
runtime_type="harness",
|
|
193
|
+
native_ref={
|
|
194
|
+
"user_id": run.request.user_id,
|
|
195
|
+
"agent_id": run.request.agent_id,
|
|
196
|
+
},
|
|
197
|
+
)
|
|
198
|
+
)
|
|
199
|
+
|
|
170
200
|
def is_handle_attached(self, handle: RunHandle) -> bool:
|
|
171
201
|
return handle.run_id in self._runs
|
|
172
202
|
|
|
173
203
|
async def execute_request(self, request: StartRequest) -> dict[str, Any]:
|
|
204
|
+
session = self._session_for(request)
|
|
205
|
+
async with session.lock:
|
|
206
|
+
return await self._execute_session_request(request, session)
|
|
207
|
+
|
|
208
|
+
async def _execute_session_request(
|
|
209
|
+
self,
|
|
210
|
+
request: StartRequest,
|
|
211
|
+
session: _HarnessSession,
|
|
212
|
+
) -> dict[str, Any]:
|
|
174
213
|
tools = await self._ensure_tools()
|
|
175
214
|
model, prompt = self._effective(request)
|
|
176
215
|
messages: list[dict[str, Any]] = [
|
|
177
216
|
{"role": "system", "content": prompt},
|
|
178
|
-
|
|
217
|
+
*[dict(message) for message in session.messages],
|
|
179
218
|
]
|
|
219
|
+
user_message = {"role": "user", "content": str(request.input or "")}
|
|
220
|
+
messages.append(user_message)
|
|
180
221
|
execution_log: list[dict[str, Any]] = []
|
|
181
222
|
|
|
182
223
|
for _turn_number in range(_MAX_REASONING_TURNS):
|
|
@@ -235,6 +276,12 @@ class HarnessRuntimeAdapter(RuntimeAdapter):
|
|
|
235
276
|
raise RuntimeError(
|
|
236
277
|
"Harness reasoner returned neither a final response nor a tool call"
|
|
237
278
|
)
|
|
279
|
+
final_message = {"role": "assistant", "content": turn.final_text}
|
|
280
|
+
messages.append(final_message)
|
|
281
|
+
# Failed or cancelled turns never commit a partial transcript.
|
|
282
|
+
# A successful turn atomically replaces the process-local history
|
|
283
|
+
# while the per-session lock is still held.
|
|
284
|
+
session.messages[:] = [dict(message) for message in messages[1:]]
|
|
238
285
|
return {
|
|
239
286
|
"output": turn.final_text,
|
|
240
287
|
"model": model,
|
|
@@ -244,6 +291,18 @@ class HarnessRuntimeAdapter(RuntimeAdapter):
|
|
|
244
291
|
}
|
|
245
292
|
raise RuntimeError(f"Harness reasoning exceeded {_MAX_REASONING_TURNS} turns")
|
|
246
293
|
|
|
294
|
+
def _session_for(self, request: StartRequest) -> _HarnessSession:
|
|
295
|
+
key = (
|
|
296
|
+
str(request.agent_id or self._agent_name),
|
|
297
|
+
str(request.user_id),
|
|
298
|
+
str(request.session_id),
|
|
299
|
+
)
|
|
300
|
+
session = self._sessions.get(key)
|
|
301
|
+
if session is None:
|
|
302
|
+
session = _HarnessSession(messages=[], lock=asyncio.Lock())
|
|
303
|
+
self._sessions[key] = session
|
|
304
|
+
return session
|
|
305
|
+
|
|
247
306
|
def _effective(self, request: StartRequest) -> tuple[str, str]:
|
|
248
307
|
metadata = request.metadata or {}
|
|
249
308
|
model = str(
|
|
@@ -15,7 +15,7 @@ from typing import Any
|
|
|
15
15
|
|
|
16
16
|
AGENT_KERNEL_V1_CONTRACT_SET = "agent-kernel/v1"
|
|
17
17
|
AGENT_KERNEL_V1_AGGREGATE_DIGEST = (
|
|
18
|
-
"
|
|
18
|
+
"b610a25aae957306b9f84a2cc2c948b30d1ce6218585cfd2a91f96736b92d102"
|
|
19
19
|
)
|
|
20
20
|
|
|
21
21
|
|
|
@@ -23,12 +23,13 @@ def runtime_capability_matrix_wire_value(matrix: Any) -> dict[str, Any]:
|
|
|
23
23
|
"""Serialize the additive matrix without materializing absent v2 modes.
|
|
24
24
|
|
|
25
25
|
Pydantic includes optional ``None`` defaults in ``model_dump``. Omitting
|
|
26
|
-
those
|
|
27
|
-
capability digest for runtimes that do not publish
|
|
26
|
+
those additive top-level keys preserves the exact pre-extension wire value
|
|
27
|
+
and capability digest for runtimes that do not publish execution controls
|
|
28
|
+
or an interaction delivery mode.
|
|
28
29
|
"""
|
|
29
30
|
|
|
30
31
|
dump = matrix.model_dump(mode="json")
|
|
31
|
-
for key in ("goal", "loop", "plan"):
|
|
32
|
+
for key in ("interaction_mode", "goal", "loop", "plan"):
|
|
32
33
|
if dump.get(key) is None:
|
|
33
34
|
dump.pop(key, None)
|
|
34
35
|
return dump
|
ksadk/kernel/contracts.py
CHANGED
|
@@ -309,6 +309,14 @@ class RuntimeCapabilityMatrix(WireModel):
|
|
|
309
309
|
inject: RuntimeCapability
|
|
310
310
|
checkpoint: RuntimeCapability
|
|
311
311
|
durable_restore: RuntimeCapability
|
|
312
|
+
# Interaction delivery is deliberately separate from the verb matrix:
|
|
313
|
+
# ``submit_interaction`` alone does not tell a caller whether the reply
|
|
314
|
+
# reaches a live process, resumes a checkpoint, or has no native route.
|
|
315
|
+
# It remains optional so a v1 consumer can read records emitted before
|
|
316
|
+
# this additive declaration without inventing support.
|
|
317
|
+
interaction_mode: Literal[
|
|
318
|
+
"live_submit", "durable_resume", "unavailable"
|
|
319
|
+
] | None = None
|
|
312
320
|
# Runtime v2 execution controls are additive optional capabilities. Older
|
|
313
321
|
# runtimes omit them; a runtime must never infer support from UI presence.
|
|
314
322
|
# ``loop`` specifically means an externally bounded, eval-driven
|
ksadk/kernel/control.py
CHANGED
ksadk/kernel/ingress.py
CHANGED
|
@@ -421,6 +421,26 @@ def map_studio_request(
|
|
|
421
421
|
)
|
|
422
422
|
|
|
423
423
|
|
|
424
|
+
def map_scheduler_request(
|
|
425
|
+
*,
|
|
426
|
+
session_id: str,
|
|
427
|
+
idempotency_key: str,
|
|
428
|
+
content: Any,
|
|
429
|
+
occurrence_id: str,
|
|
430
|
+
trusted: TrustedRuntimeContext,
|
|
431
|
+
) -> AgentControlCommand:
|
|
432
|
+
"""Scheduler occurrence -> enqueue with durable source and correlation IDs."""
|
|
433
|
+
|
|
434
|
+
return _command(
|
|
435
|
+
trusted=trusted,
|
|
436
|
+
command_type="enqueue",
|
|
437
|
+
session_id=session_id,
|
|
438
|
+
idempotency_key=idempotency_key,
|
|
439
|
+
payload={"content": content},
|
|
440
|
+
correlation_id=occurrence_id,
|
|
441
|
+
)
|
|
442
|
+
|
|
443
|
+
|
|
424
444
|
def map_control_request(
|
|
425
445
|
*,
|
|
426
446
|
command_type: str,
|
|
@@ -1091,6 +1111,7 @@ __all__ = [
|
|
|
1091
1111
|
"map_control_request",
|
|
1092
1112
|
"map_responses_request",
|
|
1093
1113
|
"map_run_request",
|
|
1114
|
+
"map_scheduler_request",
|
|
1094
1115
|
"map_studio_request",
|
|
1095
1116
|
"receipt_error_payload",
|
|
1096
1117
|
"receipt_http_status",
|
ksadk/kernel/memory_store.py
CHANGED
ksadk/kernel/postgres_store.py
CHANGED
ksadk/kernel/sqlite_store.py
CHANGED
ksadk/kernel/worker.py
CHANGED
|
@@ -356,6 +356,17 @@ class AgentKernelWorker:
|
|
|
356
356
|
agent_instance_id=command.agent_instance_id,
|
|
357
357
|
session_id=command.session_id,
|
|
358
358
|
state=RunState.PENDING,
|
|
359
|
+
# Keep the admitted control identity on the durable run. This is
|
|
360
|
+
# not user-supplied metadata: it is copied from the trusted
|
|
361
|
+
# command that the worker actually claimed. Consumers such as the
|
|
362
|
+
# local Scheduler can therefore reconcile a runtime terminal fact
|
|
363
|
+
# back to one occurrence without matching text or wall-clock time.
|
|
364
|
+
metadata={
|
|
365
|
+
"command_id": str(command.command_id),
|
|
366
|
+
"source_kind": command.source.kind,
|
|
367
|
+
"source_ref": command.source.ref,
|
|
368
|
+
"correlation_id": command.correlation_id,
|
|
369
|
+
},
|
|
359
370
|
)
|
|
360
371
|
created = await self._store.save_run_transition(pending, expected_fence=fence)
|
|
361
372
|
continuation_metadata = await self._session_continuation_metadata(command.session_id)
|
|
@@ -141,6 +141,13 @@ class SqliteMemoryProvider:
|
|
|
141
141
|
workspace_id: str = "local",
|
|
142
142
|
) -> None:
|
|
143
143
|
self._db_path = str(db_path)
|
|
144
|
+
if self._db_path != ":memory:":
|
|
145
|
+
# A fresh local Studio has not created its session directory yet.
|
|
146
|
+
# SQLite creates the database file, but not missing parents.
|
|
147
|
+
Path(self._db_path).expanduser().resolve().parent.mkdir(
|
|
148
|
+
parents=True,
|
|
149
|
+
exist_ok=True,
|
|
150
|
+
)
|
|
144
151
|
self._tenant_id = tenant_id
|
|
145
152
|
self._workspace_id = workspace_id
|
|
146
153
|
self._lock = threading.Lock()
|