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,616 @@
|
|
|
1
|
+
"""One identity-aware RuntimeEvent -> ConversationItem projection."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Mapping
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from ksadk.conversations.contracts import ConversationItem
|
|
9
|
+
from ksadk.events.canonical import (
|
|
10
|
+
ContextCompactionCompleted,
|
|
11
|
+
ContextCompactionStarted,
|
|
12
|
+
ContinuationCreated,
|
|
13
|
+
ContinuationResumed,
|
|
14
|
+
InteractionRequested,
|
|
15
|
+
InteractionResolved,
|
|
16
|
+
ItemCompleted,
|
|
17
|
+
ItemFailed,
|
|
18
|
+
ItemSnapshotReplaced,
|
|
19
|
+
ItemStarted,
|
|
20
|
+
ItemUpdated,
|
|
21
|
+
RunCanceled,
|
|
22
|
+
RunCompleted,
|
|
23
|
+
RunFailed,
|
|
24
|
+
RunInterrupted,
|
|
25
|
+
RunProgress,
|
|
26
|
+
RunStarted,
|
|
27
|
+
RuntimeEvent,
|
|
28
|
+
UsageReported,
|
|
29
|
+
)
|
|
30
|
+
from ksadk.events.content import (
|
|
31
|
+
ArtifactContent,
|
|
32
|
+
ContentSnapshot,
|
|
33
|
+
DataContent,
|
|
34
|
+
TextContent,
|
|
35
|
+
ToolCallContent,
|
|
36
|
+
ToolResultContent,
|
|
37
|
+
)
|
|
38
|
+
from ksadk.kernel.contracts import SessionEventEnvelope
|
|
39
|
+
|
|
40
|
+
_INTERACTION_EVENT_TYPES = frozenset(
|
|
41
|
+
{
|
|
42
|
+
"interaction.requested",
|
|
43
|
+
"interaction.resolved",
|
|
44
|
+
"interaction.cancelled",
|
|
45
|
+
"interaction.expired",
|
|
46
|
+
}
|
|
47
|
+
)
|
|
48
|
+
_INTERACTION_KINDS = frozenset({"approval", "structured_input", "plan_review", "custom"})
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def project_conversation_item(
|
|
52
|
+
event: RuntimeEvent,
|
|
53
|
+
*,
|
|
54
|
+
session_id: str | None = None,
|
|
55
|
+
run_id: str | None = None,
|
|
56
|
+
) -> ConversationItem:
|
|
57
|
+
"""Create a stable item projection without changing RuntimeEvent truth."""
|
|
58
|
+
|
|
59
|
+
item_id = _item_id(event)
|
|
60
|
+
kind = "unknown"
|
|
61
|
+
operation = "append"
|
|
62
|
+
lifecycle = "streaming"
|
|
63
|
+
# Known conversation kinds render in the UI. Only truly unhandled
|
|
64
|
+
# events (kind stays "unknown" after the branch chain) are hidden so
|
|
65
|
+
# they stay observable via the raw event log without spamming cards.
|
|
66
|
+
visibility = "public"
|
|
67
|
+
schema = "conversation.item.unknown/v1"
|
|
68
|
+
payload: dict[str, Any] = {}
|
|
69
|
+
capability_ref: str | None = None
|
|
70
|
+
if isinstance(event, ItemStarted) and event.item_kind in {"message", "reasoning"}:
|
|
71
|
+
kind = "reasoning" if event.item_kind == "reasoning" else "assistant_text"
|
|
72
|
+
lifecycle = "pending"
|
|
73
|
+
schema = f"conversation.item.{kind}/v1"
|
|
74
|
+
payload = {"text": _text_from_snapshot(event.initial)}
|
|
75
|
+
elif isinstance(event, ItemUpdated) and event.item_kind in {"message", "reasoning"}:
|
|
76
|
+
kind = "reasoning" if event.item_kind == "reasoning" else "assistant_text"
|
|
77
|
+
operation = event.op
|
|
78
|
+
schema = f"conversation.item.{kind}/v1"
|
|
79
|
+
payload = {"text": _text_from_update(event)}
|
|
80
|
+
elif isinstance(event, ItemSnapshotReplaced) and event.item_kind in {"message", "reasoning"}:
|
|
81
|
+
kind = "reasoning" if event.item_kind == "reasoning" else "assistant_text"
|
|
82
|
+
operation = "replace"
|
|
83
|
+
schema = f"conversation.item.{kind}/v1"
|
|
84
|
+
payload = {"text": _text_from_snapshot(event.snapshot)}
|
|
85
|
+
elif isinstance(event, ItemCompleted) and event.item_kind in {"message", "reasoning"}:
|
|
86
|
+
kind = "reasoning" if event.item_kind == "reasoning" else "assistant_text"
|
|
87
|
+
operation = "completed"
|
|
88
|
+
lifecycle = "completed"
|
|
89
|
+
schema = f"conversation.item.{kind}/v1"
|
|
90
|
+
payload = {"text": _text_from_snapshot(event.snapshot)}
|
|
91
|
+
elif isinstance(event, ItemStarted) and event.item_kind == "tool_call":
|
|
92
|
+
kind = "tool_call"
|
|
93
|
+
schema = "conversation.item.tool-call/v1"
|
|
94
|
+
payload = _tool_payload(event.initial)
|
|
95
|
+
capability_ref = "tool.inspect"
|
|
96
|
+
elif isinstance(event, ItemCompleted) and event.item_kind == "tool_call":
|
|
97
|
+
kind = "tool_call"
|
|
98
|
+
operation = "completed"
|
|
99
|
+
lifecycle = "completed"
|
|
100
|
+
schema = "conversation.item.tool-call/v1"
|
|
101
|
+
payload = _tool_payload(event.snapshot)
|
|
102
|
+
capability_ref = "tool.inspect"
|
|
103
|
+
elif (
|
|
104
|
+
isinstance(event, (ItemStarted, ItemUpdated, ItemSnapshotReplaced, ItemCompleted))
|
|
105
|
+
and event.item_kind == "tool_result"
|
|
106
|
+
):
|
|
107
|
+
# Codex emits a separate tool_result item carrying the ToolResultContent.
|
|
108
|
+
# Project it as a completed tool_call so the UI renders the output instead
|
|
109
|
+
# of degrading it to an unknown fallback card.
|
|
110
|
+
kind = "tool_call"
|
|
111
|
+
schema = "conversation.item.tool-call/v1"
|
|
112
|
+
capability_ref = "tool.inspect"
|
|
113
|
+
if isinstance(event, ItemStarted):
|
|
114
|
+
payload = _tool_payload(event.initial)
|
|
115
|
+
else:
|
|
116
|
+
payload = _tool_payload(_item_snapshot(event))
|
|
117
|
+
if isinstance(event, ItemCompleted):
|
|
118
|
+
operation = "completed"
|
|
119
|
+
lifecycle = "completed"
|
|
120
|
+
elif isinstance(event, ItemSnapshotReplaced):
|
|
121
|
+
operation = "replace"
|
|
122
|
+
elif _is_codex_plan_item(event):
|
|
123
|
+
kind = "plan"
|
|
124
|
+
schema = "conversation.item.plan/v1"
|
|
125
|
+
payload = {"text": _text_from_item_event(event)}
|
|
126
|
+
capability_ref = "plan"
|
|
127
|
+
if isinstance(event, ItemSnapshotReplaced):
|
|
128
|
+
operation = "replace"
|
|
129
|
+
if isinstance(event, ItemCompleted):
|
|
130
|
+
operation = "completed"
|
|
131
|
+
lifecycle = "completed"
|
|
132
|
+
elif _is_codex_goal_item(event):
|
|
133
|
+
kind = "goal"
|
|
134
|
+
schema = "conversation.item.goal/v1"
|
|
135
|
+
payload = _goal_payload(_item_snapshot(event))
|
|
136
|
+
capability_ref = "goal"
|
|
137
|
+
if isinstance(event, ItemSnapshotReplaced):
|
|
138
|
+
operation = "replace"
|
|
139
|
+
if isinstance(event, ItemCompleted):
|
|
140
|
+
operation = "completed"
|
|
141
|
+
lifecycle = "completed"
|
|
142
|
+
elif _is_codex_user_message(event):
|
|
143
|
+
# ``userMessage`` is a transcript item. Its item completion must not
|
|
144
|
+
# be mistaken for completion of the containing Codex turn.
|
|
145
|
+
kind = "user_message"
|
|
146
|
+
schema = "conversation.item.user_message/v1"
|
|
147
|
+
payload = {"text": _codex_user_message_text(_item_snapshot(event))}
|
|
148
|
+
if isinstance(event, ItemSnapshotReplaced):
|
|
149
|
+
operation = "replace"
|
|
150
|
+
if isinstance(event, ItemCompleted):
|
|
151
|
+
operation = "completed"
|
|
152
|
+
lifecycle = "completed"
|
|
153
|
+
elif (
|
|
154
|
+
isinstance(event, (ItemStarted, ItemUpdated, ItemSnapshotReplaced, ItemCompleted))
|
|
155
|
+
and event.item_kind == "artifact"
|
|
156
|
+
):
|
|
157
|
+
kind = "artifact"
|
|
158
|
+
schema = "conversation.item.artifact/v1"
|
|
159
|
+
payload = _artifact_payload(_item_snapshot(event))
|
|
160
|
+
if isinstance(event, ItemSnapshotReplaced):
|
|
161
|
+
operation = "replace"
|
|
162
|
+
if isinstance(event, ItemCompleted):
|
|
163
|
+
operation = "completed"
|
|
164
|
+
lifecycle = "completed"
|
|
165
|
+
elif (
|
|
166
|
+
isinstance(event, (ItemStarted, ItemUpdated, ItemSnapshotReplaced, ItemCompleted))
|
|
167
|
+
and event.item_kind == "data"
|
|
168
|
+
and event.source.protocol == "a2ui"
|
|
169
|
+
):
|
|
170
|
+
kind = "a2ui"
|
|
171
|
+
schema = "conversation.item.a2ui/v1"
|
|
172
|
+
payload = _data_payload(_item_snapshot(event))
|
|
173
|
+
if isinstance(event, ItemSnapshotReplaced):
|
|
174
|
+
operation = "replace"
|
|
175
|
+
if isinstance(event, ItemCompleted):
|
|
176
|
+
operation = "completed"
|
|
177
|
+
lifecycle = "completed"
|
|
178
|
+
elif (
|
|
179
|
+
isinstance(event, (ItemStarted, ItemUpdated, ItemSnapshotReplaced, ItemCompleted))
|
|
180
|
+
and event.item_kind == "status"
|
|
181
|
+
):
|
|
182
|
+
# LangGraph subgraph lifecycle and similar status items. Project as
|
|
183
|
+
# progress so the UI shows a subtle indicator instead of an unknown card.
|
|
184
|
+
kind = "progress"
|
|
185
|
+
schema = "conversation.item.progress/v1"
|
|
186
|
+
payload = _data_payload(_item_snapshot(event))
|
|
187
|
+
if isinstance(event, ItemCompleted):
|
|
188
|
+
operation = "completed"
|
|
189
|
+
lifecycle = "completed"
|
|
190
|
+
elif isinstance(event, ItemFailed):
|
|
191
|
+
kind = "error"
|
|
192
|
+
operation = "completed"
|
|
193
|
+
lifecycle = "failed"
|
|
194
|
+
schema = "conversation.item.error/v1"
|
|
195
|
+
payload = {"error": event.error.message or event.error.code}
|
|
196
|
+
elif isinstance(event, InteractionRequested):
|
|
197
|
+
kind = "approval" if event.interaction_kind == "approval" else "progress"
|
|
198
|
+
lifecycle = "pending"
|
|
199
|
+
schema = (
|
|
200
|
+
"conversation.item.approval/v1"
|
|
201
|
+
if kind == "approval"
|
|
202
|
+
else "conversation.item.structured-input/v1"
|
|
203
|
+
)
|
|
204
|
+
payload = {
|
|
205
|
+
"interactionId": event.interaction_id,
|
|
206
|
+
"kind": getattr(event.request, "kind", event.interaction_kind),
|
|
207
|
+
"detail": getattr(event.request, "detail", None),
|
|
208
|
+
"prompt": getattr(event.request, "prompt", None),
|
|
209
|
+
"inputSchema": getattr(event.request, "schema_", None),
|
|
210
|
+
"surfaceId": event.source.metadata.get("surface_id"),
|
|
211
|
+
}
|
|
212
|
+
capability_ref = "approval" if kind == "approval" else "structured_input"
|
|
213
|
+
elif isinstance(event, InteractionResolved):
|
|
214
|
+
kind = "approval" if event.interaction_kind == "approval" else "progress"
|
|
215
|
+
operation = "completed"
|
|
216
|
+
lifecycle = "completed"
|
|
217
|
+
schema = (
|
|
218
|
+
"conversation.item.approval/v1"
|
|
219
|
+
if kind == "approval"
|
|
220
|
+
else "conversation.item.structured-input/v1"
|
|
221
|
+
)
|
|
222
|
+
payload = {
|
|
223
|
+
"interactionId": event.interaction_id,
|
|
224
|
+
"surfaceId": event.source.metadata.get("surface_id"),
|
|
225
|
+
}
|
|
226
|
+
capability_ref = "approval" if kind == "approval" else "structured_input"
|
|
227
|
+
elif isinstance(event, (RunStarted, RunProgress, RunCompleted, RunInterrupted)):
|
|
228
|
+
kind = "progress"
|
|
229
|
+
schema = "conversation.item.progress/v1"
|
|
230
|
+
if isinstance(event, RunProgress):
|
|
231
|
+
payload = {
|
|
232
|
+
"status": "running",
|
|
233
|
+
"progress": event.progress,
|
|
234
|
+
"message": event.message,
|
|
235
|
+
}
|
|
236
|
+
elif isinstance(event, RunInterrupted):
|
|
237
|
+
payload = {"status": "interrupted", "reason": event.reason or ""}
|
|
238
|
+
operation = "completed"
|
|
239
|
+
lifecycle = "completed"
|
|
240
|
+
elif isinstance(event, RunCompleted):
|
|
241
|
+
payload = {"status": "completed"}
|
|
242
|
+
operation = "completed"
|
|
243
|
+
lifecycle = "completed"
|
|
244
|
+
else:
|
|
245
|
+
payload = {"status": "running"}
|
|
246
|
+
elif isinstance(event, (RunFailed, RunCanceled)):
|
|
247
|
+
kind = "error"
|
|
248
|
+
operation = "completed"
|
|
249
|
+
lifecycle = "failed"
|
|
250
|
+
schema = "conversation.item.error/v1"
|
|
251
|
+
payload = {
|
|
252
|
+
"status": "failed" if isinstance(event, RunFailed) else "canceled",
|
|
253
|
+
"error": event.error.message if isinstance(event, RunFailed) else event.reason or ""
|
|
254
|
+
}
|
|
255
|
+
elif isinstance(event, (ContinuationCreated, ContinuationResumed)):
|
|
256
|
+
kind = "progress"
|
|
257
|
+
schema = "conversation.item.checkpoint/v1"
|
|
258
|
+
payload = {"continuationId": event.continuation_id}
|
|
259
|
+
elif isinstance(event, UsageReported):
|
|
260
|
+
# Token usage is carried in the top-level SSE envelope; no need to
|
|
261
|
+
# render a conversation card for it. Project as hidden progress.
|
|
262
|
+
kind = "progress"
|
|
263
|
+
schema = "conversation.item.progress/v1"
|
|
264
|
+
visibility = "hidden"
|
|
265
|
+
payload = {
|
|
266
|
+
"message": "usage",
|
|
267
|
+
"inputTokens": event.input_tokens,
|
|
268
|
+
"outputTokens": event.output_tokens,
|
|
269
|
+
"totalTokens": event.total_tokens,
|
|
270
|
+
"cachedTokens": event.cached_tokens,
|
|
271
|
+
"reasoningTokens": event.reasoning_tokens,
|
|
272
|
+
}
|
|
273
|
+
operation = "completed"
|
|
274
|
+
lifecycle = "completed"
|
|
275
|
+
elif isinstance(event, (ContextCompactionStarted, ContextCompactionCompleted)):
|
|
276
|
+
kind = "progress"
|
|
277
|
+
schema = "conversation.item.progress/v1"
|
|
278
|
+
payload = {"message": "context_compaction"}
|
|
279
|
+
if isinstance(event, ContextCompactionCompleted):
|
|
280
|
+
operation = "completed"
|
|
281
|
+
lifecycle = "completed"
|
|
282
|
+
elif (
|
|
283
|
+
isinstance(event, (ItemStarted, ItemUpdated, ItemSnapshotReplaced, ItemCompleted))
|
|
284
|
+
and event.item_kind == "data"
|
|
285
|
+
):
|
|
286
|
+
# Catch-all for Codex data items that are not plan/goal/a2ui
|
|
287
|
+
# (fileChange, userMessage, hookPrompt, contextCompaction, etc.).
|
|
288
|
+
# Project as progress so the UI shows a subtle indicator instead of
|
|
289
|
+
# rendering an ugly "unsupported content" card for every turn.
|
|
290
|
+
kind = "progress"
|
|
291
|
+
schema = "conversation.item.progress/v1"
|
|
292
|
+
native_kind = event.source.metadata.get("native_item_kind", "")
|
|
293
|
+
payload = {"message": native_kind or "data", **_data_payload(_item_snapshot(event))}
|
|
294
|
+
if isinstance(event, ItemCompleted):
|
|
295
|
+
operation = "completed"
|
|
296
|
+
lifecycle = "completed"
|
|
297
|
+
# Unhandled event types fall through with kind == "unknown". They are
|
|
298
|
+
# hidden unless a trusted projector explicitly marks the event as a public
|
|
299
|
+
# conversation surface. Public future kinds receive the fixed safe
|
|
300
|
+
# fallback card; internal provider chatter remains trace/replay-only.
|
|
301
|
+
if kind == "unknown":
|
|
302
|
+
visibility = (
|
|
303
|
+
"public"
|
|
304
|
+
if event.source.metadata.get("conversation_visibility") == "public"
|
|
305
|
+
else "hidden"
|
|
306
|
+
)
|
|
307
|
+
if visibility == "public":
|
|
308
|
+
payload = {
|
|
309
|
+
"eventType": event.event_type,
|
|
310
|
+
"summary": "This content requires a newer renderer.",
|
|
311
|
+
}
|
|
312
|
+
return ConversationItem(
|
|
313
|
+
item_id=item_id,
|
|
314
|
+
source_event_ids=(event.event_id,),
|
|
315
|
+
session_id=session_id or event.scope_id,
|
|
316
|
+
# A host may own a public/durable Run identity that differs from the
|
|
317
|
+
# provider-native handle. Conversation clients need the public id for
|
|
318
|
+
# replay and control; the untouched RuntimeEvent remains the native
|
|
319
|
+
# source of truth and is carried separately by the host projection.
|
|
320
|
+
run_id=run_id or event.run_id,
|
|
321
|
+
kind=kind,
|
|
322
|
+
operation=operation,
|
|
323
|
+
lifecycle=lifecycle,
|
|
324
|
+
visibility=visibility,
|
|
325
|
+
payload_schema_ref=schema,
|
|
326
|
+
payload=payload,
|
|
327
|
+
capability_ref=capability_ref,
|
|
328
|
+
native_ref=_native_ref(event),
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
def project_interaction_conversation_item(
|
|
333
|
+
envelope: SessionEventEnvelope,
|
|
334
|
+
) -> ConversationItem | None:
|
|
335
|
+
"""Project one authoritative Interaction/v1 fact for a conversation surface.
|
|
336
|
+
|
|
337
|
+
Interaction revision is the CAS token for ``SubmitInteraction``. It is
|
|
338
|
+
therefore read only from the durable Interaction/v1 payload and never
|
|
339
|
+
synthesized from cursor order, lifecycle, or a provider-native event.
|
|
340
|
+
Malformed legacy rows remain observable through their existing Studio
|
|
341
|
+
projection, but cannot become a writable ConversationItem.
|
|
342
|
+
"""
|
|
343
|
+
|
|
344
|
+
if envelope.family != "interaction" or envelope.family_version != 1:
|
|
345
|
+
return None
|
|
346
|
+
payload = envelope.payload
|
|
347
|
+
event_type = envelope.event_type
|
|
348
|
+
if event_type not in _INTERACTION_EVENT_TYPES:
|
|
349
|
+
return None
|
|
350
|
+
if payload.get("event_type") != event_type:
|
|
351
|
+
return None
|
|
352
|
+
|
|
353
|
+
interaction_id = _nonempty_string(payload.get("interaction_id"))
|
|
354
|
+
session_id = _nonempty_string(payload.get("session_id"))
|
|
355
|
+
run_id = _nonempty_string(payload.get("run_id"))
|
|
356
|
+
interaction_kind = _nonempty_string(payload.get("kind"))
|
|
357
|
+
revision = _positive_revision(payload.get("revision"))
|
|
358
|
+
if (
|
|
359
|
+
interaction_id is None
|
|
360
|
+
or session_id != envelope.session_id
|
|
361
|
+
or run_id is None
|
|
362
|
+
or interaction_kind not in _INTERACTION_KINDS
|
|
363
|
+
or revision is None
|
|
364
|
+
):
|
|
365
|
+
return None
|
|
366
|
+
if envelope.run_id is not None and run_id != envelope.run_id:
|
|
367
|
+
return None
|
|
368
|
+
|
|
369
|
+
is_requested = event_type == "interaction.requested"
|
|
370
|
+
request = payload.get("request")
|
|
371
|
+
if is_requested and not isinstance(request, Mapping):
|
|
372
|
+
return None
|
|
373
|
+
request_payload = request if isinstance(request, Mapping) else {}
|
|
374
|
+
presentation = request_payload.get("presentation")
|
|
375
|
+
presentation_payload = presentation if isinstance(presentation, Mapping) else {}
|
|
376
|
+
|
|
377
|
+
item_payload: dict[str, Any] = {
|
|
378
|
+
"interactionId": interaction_id,
|
|
379
|
+
"interactionKind": interaction_kind,
|
|
380
|
+
"kind": interaction_kind,
|
|
381
|
+
"revision": revision,
|
|
382
|
+
}
|
|
383
|
+
if is_requested:
|
|
384
|
+
item_payload.update(
|
|
385
|
+
{
|
|
386
|
+
"kind": _nonempty_string(presentation_payload.get("title")) or interaction_kind,
|
|
387
|
+
"inputSchema": (
|
|
388
|
+
dict(request_payload.get("request_schema"))
|
|
389
|
+
if isinstance(request_payload.get("request_schema"), Mapping)
|
|
390
|
+
else {}
|
|
391
|
+
),
|
|
392
|
+
"createdAt": str(payload.get("timestamp") or envelope.timestamp),
|
|
393
|
+
}
|
|
394
|
+
)
|
|
395
|
+
title = _nonempty_string(presentation_payload.get("title"))
|
|
396
|
+
detail = _nonempty_string(presentation_payload.get("description"))
|
|
397
|
+
expires_at = _nonempty_string(request_payload.get("expires_at"))
|
|
398
|
+
if title is not None:
|
|
399
|
+
item_payload["title"] = title
|
|
400
|
+
if detail is not None:
|
|
401
|
+
item_payload["detail"] = detail
|
|
402
|
+
item_payload["prompt"] = detail
|
|
403
|
+
if expires_at is not None:
|
|
404
|
+
item_payload["expiresAt"] = expires_at
|
|
405
|
+
if presentation_payload:
|
|
406
|
+
item_payload["presentation"] = dict(presentation_payload)
|
|
407
|
+
else:
|
|
408
|
+
item_payload["resolvedAt"] = str(payload.get("timestamp") or envelope.timestamp)
|
|
409
|
+
outcome = _nonempty_string(payload.get("outcome"))
|
|
410
|
+
actor_ref = _nonempty_string(payload.get("actor_ref"))
|
|
411
|
+
reason = _nonempty_string(payload.get("reason"))
|
|
412
|
+
if outcome is not None:
|
|
413
|
+
item_payload["outcome"] = outcome
|
|
414
|
+
if "response" in payload:
|
|
415
|
+
item_payload["response"] = payload["response"]
|
|
416
|
+
if actor_ref is not None:
|
|
417
|
+
item_payload["actor"] = actor_ref
|
|
418
|
+
if reason is not None:
|
|
419
|
+
item_payload["reason"] = reason
|
|
420
|
+
|
|
421
|
+
is_approval = interaction_kind == "approval"
|
|
422
|
+
return ConversationItem(
|
|
423
|
+
item_id=interaction_id,
|
|
424
|
+
source_event_ids=(str(envelope.event_id),),
|
|
425
|
+
session_id=session_id,
|
|
426
|
+
run_id=run_id,
|
|
427
|
+
kind="approval" if is_approval else "progress",
|
|
428
|
+
operation="append" if is_requested else "completed",
|
|
429
|
+
lifecycle="pending" if is_requested else "completed",
|
|
430
|
+
payload_schema_ref=(
|
|
431
|
+
"conversation.item.approval/v1"
|
|
432
|
+
if is_approval
|
|
433
|
+
else "conversation.item.structured-input/v1"
|
|
434
|
+
),
|
|
435
|
+
payload=item_payload,
|
|
436
|
+
capability_ref="approval" if is_approval else "structured_input",
|
|
437
|
+
native_ref={
|
|
438
|
+
"protocol": "agent-kernel/interaction-v1",
|
|
439
|
+
"eventId": str(envelope.event_id),
|
|
440
|
+
"cursor": envelope.seq,
|
|
441
|
+
},
|
|
442
|
+
)
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
def _positive_revision(value: Any) -> int | None:
|
|
446
|
+
if isinstance(value, bool) or not isinstance(value, int) or value < 1:
|
|
447
|
+
return None
|
|
448
|
+
return value
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
def _nonempty_string(value: Any) -> str | None:
|
|
452
|
+
if not isinstance(value, str) or not value.strip():
|
|
453
|
+
return None
|
|
454
|
+
return value
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
def _item_id(event: RuntimeEvent) -> str:
|
|
458
|
+
if isinstance(
|
|
459
|
+
event,
|
|
460
|
+
(ItemStarted, ItemUpdated, ItemSnapshotReplaced, ItemCompleted, ItemFailed),
|
|
461
|
+
):
|
|
462
|
+
return event.item_id
|
|
463
|
+
if isinstance(event, (InteractionRequested, InteractionResolved)):
|
|
464
|
+
return event.interaction_id
|
|
465
|
+
if isinstance(event, (ContinuationCreated, ContinuationResumed)):
|
|
466
|
+
return event.continuation_id
|
|
467
|
+
return event.event_id
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
def _text_from_update(event: ItemUpdated) -> str:
|
|
471
|
+
return event.update.text if isinstance(event.update, TextContent) else ""
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
def _text_from_item_event(
|
|
475
|
+
event: ItemStarted | ItemUpdated | ItemSnapshotReplaced | ItemCompleted,
|
|
476
|
+
) -> str:
|
|
477
|
+
if isinstance(event, ItemUpdated):
|
|
478
|
+
return _text_from_update(event)
|
|
479
|
+
return _text_from_snapshot(_item_snapshot(event))
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
def _text_from_snapshot(snapshot: ContentSnapshot | None) -> str:
|
|
483
|
+
if snapshot is None:
|
|
484
|
+
return ""
|
|
485
|
+
for part in snapshot.parts:
|
|
486
|
+
if isinstance(part, TextContent):
|
|
487
|
+
return part.text
|
|
488
|
+
return ""
|
|
489
|
+
|
|
490
|
+
|
|
491
|
+
def _tool_payload(snapshot: ContentSnapshot | None) -> dict[str, Any]:
|
|
492
|
+
if snapshot is None:
|
|
493
|
+
return {}
|
|
494
|
+
call = next((item for item in snapshot.parts if isinstance(item, ToolCallContent)), None)
|
|
495
|
+
result = next((item for item in snapshot.parts if isinstance(item, ToolResultContent)), None)
|
|
496
|
+
payload: dict[str, Any] = {}
|
|
497
|
+
if call is not None:
|
|
498
|
+
payload.update({"callId": call.call_id, "tool": call.name, "args": call.arguments})
|
|
499
|
+
if result is not None:
|
|
500
|
+
# A Codex tool_result can arrive as a separate native item from the
|
|
501
|
+
# corresponding tool_call. Keep the provider call identity in both
|
|
502
|
+
# projections so a renderer can enrich the original card in place
|
|
503
|
+
# rather than appending a duplicate result card.
|
|
504
|
+
payload.update(
|
|
505
|
+
{
|
|
506
|
+
"callId": result.call_id,
|
|
507
|
+
"output": result.result,
|
|
508
|
+
"isError": result.is_error,
|
|
509
|
+
}
|
|
510
|
+
)
|
|
511
|
+
return payload
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
def _item_snapshot(
|
|
515
|
+
event: ItemStarted | ItemUpdated | ItemSnapshotReplaced | ItemCompleted,
|
|
516
|
+
) -> ContentSnapshot | None:
|
|
517
|
+
if isinstance(event, ItemStarted):
|
|
518
|
+
return event.initial
|
|
519
|
+
if isinstance(event, ItemUpdated):
|
|
520
|
+
return ContentSnapshot(parts=(event.update,))
|
|
521
|
+
return event.snapshot
|
|
522
|
+
|
|
523
|
+
|
|
524
|
+
def _artifact_payload(snapshot: ContentSnapshot | None) -> dict[str, Any]:
|
|
525
|
+
if snapshot is None:
|
|
526
|
+
return {}
|
|
527
|
+
artifact = next(
|
|
528
|
+
(part for part in snapshot.parts if isinstance(part, ArtifactContent)), None
|
|
529
|
+
)
|
|
530
|
+
if artifact is None:
|
|
531
|
+
return {}
|
|
532
|
+
return {
|
|
533
|
+
"artifactId": artifact.artifact_id,
|
|
534
|
+
"name": artifact.name,
|
|
535
|
+
"mimeType": artifact.mime_type,
|
|
536
|
+
"uri": artifact.uri,
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
|
|
540
|
+
def _data_payload(snapshot: ContentSnapshot | None) -> dict[str, Any]:
|
|
541
|
+
if snapshot is None:
|
|
542
|
+
return {}
|
|
543
|
+
data = next((part for part in snapshot.parts if isinstance(part, DataContent)), None)
|
|
544
|
+
return {"data": data.data} if data is not None else {}
|
|
545
|
+
|
|
546
|
+
|
|
547
|
+
def _goal_payload(snapshot: ContentSnapshot | None) -> dict[str, Any]:
|
|
548
|
+
wrapped = _data_payload(snapshot)
|
|
549
|
+
value = wrapped.get("data")
|
|
550
|
+
return dict(value) if isinstance(value, Mapping) else wrapped
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
def _codex_user_message_text(snapshot: ContentSnapshot | None) -> str:
|
|
554
|
+
value = _data_payload(snapshot).get("data")
|
|
555
|
+
if not isinstance(value, Mapping):
|
|
556
|
+
return ""
|
|
557
|
+
content = value.get("content")
|
|
558
|
+
if isinstance(content, str):
|
|
559
|
+
return content
|
|
560
|
+
if not isinstance(content, (list, tuple)):
|
|
561
|
+
return ""
|
|
562
|
+
return "".join(
|
|
563
|
+
str(part["text"])
|
|
564
|
+
for part in content
|
|
565
|
+
if isinstance(part, Mapping) and isinstance(part.get("text"), str)
|
|
566
|
+
)
|
|
567
|
+
|
|
568
|
+
|
|
569
|
+
def _is_codex_plan_item(event: RuntimeEvent) -> bool:
|
|
570
|
+
return (
|
|
571
|
+
isinstance(event, (ItemStarted, ItemUpdated, ItemSnapshotReplaced, ItemCompleted))
|
|
572
|
+
and event.item_kind == "data"
|
|
573
|
+
and event.source.framework == "codex"
|
|
574
|
+
and (
|
|
575
|
+
event.source.metadata.get("native_item_kind") == "plan"
|
|
576
|
+
or event.source.metadata.get("method") == "turn/plan/updated"
|
|
577
|
+
)
|
|
578
|
+
)
|
|
579
|
+
|
|
580
|
+
|
|
581
|
+
def _is_codex_goal_item(event: RuntimeEvent) -> bool:
|
|
582
|
+
return (
|
|
583
|
+
isinstance(event, (ItemStarted, ItemUpdated, ItemSnapshotReplaced, ItemCompleted))
|
|
584
|
+
and event.item_kind == "data"
|
|
585
|
+
and event.source.framework == "codex"
|
|
586
|
+
and event.source.metadata.get("method")
|
|
587
|
+
in {"thread/goal/updated", "thread/goal/cleared"}
|
|
588
|
+
)
|
|
589
|
+
|
|
590
|
+
|
|
591
|
+
def _is_codex_user_message(event: RuntimeEvent) -> bool:
|
|
592
|
+
return (
|
|
593
|
+
isinstance(event, (ItemStarted, ItemUpdated, ItemSnapshotReplaced, ItemCompleted))
|
|
594
|
+
and event.item_kind == "data"
|
|
595
|
+
and event.source.framework == "codex"
|
|
596
|
+
and event.source.metadata.get("native_item_kind") == "userMessage"
|
|
597
|
+
)
|
|
598
|
+
|
|
599
|
+
|
|
600
|
+
def _native_ref(event: RuntimeEvent) -> dict[str, Any]:
|
|
601
|
+
source = event.source
|
|
602
|
+
return {
|
|
603
|
+
key: value
|
|
604
|
+
for key, value in {
|
|
605
|
+
"framework": source.framework,
|
|
606
|
+
"protocol": source.protocol,
|
|
607
|
+
"eventId": source.native_event_id,
|
|
608
|
+
"cursor": source.native_cursor,
|
|
609
|
+
"runId": source.native_run_id,
|
|
610
|
+
"itemId": source.native_item_id,
|
|
611
|
+
}.items()
|
|
612
|
+
if value is not None
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
|
|
616
|
+
__all__ = ["project_conversation_item", "project_interaction_conversation_item"]
|