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.
Files changed (250) hide show
  1. {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.3.dist-info}/METADATA +18 -25
  2. {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.3.dist-info}/RECORD +224 -169
  3. ksadk/_build_provenance.json +1 -0
  4. ksadk/agui/_agent_helpers.py +4 -0
  5. ksadk/api/client.py +3 -0
  6. ksadk/builders/managed_runtime_builder.py +3 -0
  7. ksadk/cli/__init__.py +6 -0
  8. ksadk/cli/cmd_plugin.py +657 -0
  9. ksadk/codex/runtime.py +50 -8
  10. ksadk/configs/env_registry.py +31 -3
  11. ksadk/configs/settings.py +9 -0
  12. ksadk/context_engine/contributors.py +73 -8
  13. ksadk/conversations/__init__.py +19 -0
  14. ksadk/conversations/context.py +104 -24
  15. ksadk/conversations/contracts.py +266 -0
  16. ksadk/conversations/message_projection.py +19 -1
  17. ksadk/conversations/projector.py +616 -0
  18. ksadk/conversations/reducer.py +98 -0
  19. ksadk/events/_v1_compat/projection.py +2 -0
  20. ksadk/events/adapters/codex.py +190 -0
  21. ksadk/harness/__init__.py +45 -35
  22. ksadk/harness/runtime.py +60 -1
  23. ksadk/kernel/contract_fingerprints.py +5 -4
  24. ksadk/kernel/contracts.py +8 -0
  25. ksadk/kernel/control.py +1 -0
  26. ksadk/kernel/ingress.py +21 -0
  27. ksadk/kernel/memory_store.py +1 -0
  28. ksadk/kernel/postgres_store.py +1 -0
  29. ksadk/kernel/sqlite_store.py +1 -0
  30. ksadk/kernel/worker.py +11 -0
  31. ksadk/memory/providers/local_sqlite.py +7 -0
  32. ksadk/plugins/__init__.py +167 -0
  33. ksadk/plugins/bridges/__init__.py +45 -0
  34. ksadk/plugins/bridges/codex.py +552 -0
  35. ksadk/plugins/bridges/dsh.py +1116 -0
  36. ksadk/plugins/builtins.py +747 -0
  37. ksadk/plugins/bundle.py +246 -0
  38. ksadk/plugins/bundle_security.py +167 -0
  39. ksadk/plugins/composition.py +529 -0
  40. ksadk/plugins/context_contributor.py +437 -0
  41. ksadk/plugins/contracts.py +451 -0
  42. ksadk/plugins/dsh_toolchain.py +935 -0
  43. ksadk/plugins/ecosystem_bridge.py +1105 -0
  44. ksadk/plugins/ecosystem_probe.py +191 -0
  45. ksadk/plugins/host.py +724 -0
  46. ksadk/plugins/providers/__init__.py +85 -0
  47. ksadk/plugins/providers/bundles/ksadk-codex/cordis.patch.yml +3 -0
  48. ksadk/plugins/providers/bundles/ksadk-codex/index.mjs +18 -0
  49. ksadk/plugins/providers/bundles/ksadk-codex/package.json +19 -0
  50. ksadk/plugins/providers/bundles/ksadk-harness/cordis.patch.yml +3 -0
  51. ksadk/plugins/providers/bundles/ksadk-harness/index.mjs +19 -0
  52. ksadk/plugins/providers/bundles/ksadk-harness/package.json +19 -0
  53. ksadk/plugins/providers/codex.py +722 -0
  54. ksadk/plugins/providers/codex_dsh.py +83 -0
  55. ksadk/plugins/providers/dsh.py +951 -0
  56. ksadk/plugins/providers/dsh_descriptor_host.py +226 -0
  57. ksadk/plugins/providers/harness.py +627 -0
  58. ksadk/plugins/providers/harness_dsh.py +91 -0
  59. ksadk/plugins/providers/legacy.py +215 -0
  60. ksadk/plugins/providers/legacy_catalog.py +100 -0
  61. ksadk/plugins/providers/shipped_dsh.py +370 -0
  62. ksadk/plugins/resolver.py +331 -0
  63. ksadk/plugins/subagent_providers/__init__.py +12 -0
  64. ksadk/plugins/subagent_providers/codex.py +443 -0
  65. ksadk/plugins/subagents.py +333 -0
  66. ksadk/runtime/_runner_adapter/stream_mapping.py +51 -42
  67. ksadk/runtime/adapter.py +1 -0
  68. ksadk/runtime/factory.py +76 -2
  69. ksadk/runtime/framework_adapters.py +18 -0
  70. ksadk/runtime/runner_adapter.py +5 -0
  71. ksadk/sandbox/__init__.py +2 -1
  72. ksadk/sandbox/factory.py +72 -0
  73. ksadk/scheduler/__init__.py +18 -0
  74. ksadk/scheduler/calendar.py +102 -0
  75. ksadk/scheduler/contracts.py +254 -0
  76. ksadk/scheduler/dispatcher.py +129 -0
  77. ksadk/scheduler/engine.py +416 -0
  78. ksadk/scheduler/sqlite_store.py +563 -0
  79. ksadk/server/static/assets/{ArtifactsPanel-DSU1sWD_.js → ArtifactsPanel-10GPXIJ6.js} +1 -1
  80. ksadk/server/static/assets/{CodeBlock-DOH6MVcn.js → CodeBlock-BXk1l-G1.js} +1 -1
  81. ksadk/server/static/assets/{MathMessageMarkdown-BL8my1R2.js → MathMessageMarkdown-D9uB55Oh.js} +1 -1
  82. ksadk/server/static/assets/{MermaidBlock-Dz4IP-Tx.js → MermaidBlock--OEYoXIJ.js} +6 -6
  83. ksadk/server/static/assets/{NativeTerminalPanel-DUrK0JpZ.js → NativeTerminalPanel-DrEe1syq.js} +1 -1
  84. ksadk/server/static/assets/{abnfDiagram-VCTEODGH-g20pFzNV.js → abnfDiagram-VCTEODGH-eeTFJLvo.js} +1 -1
  85. ksadk/server/static/assets/{arc-C4FzinUA.js → arc-S3ZNbIAd.js} +1 -1
  86. ksadk/server/static/assets/architecture-7GRP2DOG-Dk9nRQ6-.js +1 -0
  87. ksadk/server/static/assets/{architectureDiagram-5GKGNRK7-DpIqL5h4.js → architectureDiagram-5GKGNRK7-CRjgEJDX.js} +1 -1
  88. ksadk/server/static/assets/{blockDiagram-NRAW4CY4-BjkljTNz.js → blockDiagram-NRAW4CY4-C7bsBoNH.js} +1 -1
  89. ksadk/server/static/assets/{c4Diagram-UCG6FXSJ-Dk_ieq2X.js → c4Diagram-UCG6FXSJ-BX3c33Ob.js} +1 -1
  90. ksadk/server/static/assets/channel-s354Yo6o.js +1 -0
  91. ksadk/server/static/assets/chunk-2Q5K7J3B-CDpPpKR5.js +1 -0
  92. ksadk/server/static/assets/{chunk-5VM5RSS4-BVHAchFb.js → chunk-5VM5RSS4-bZ7ws-8m.js} +1 -1
  93. ksadk/server/static/assets/{chunk-F27PBJKO-C-ipQzuS.js → chunk-F27PBJKO-D2r0pvhY.js} +1 -1
  94. ksadk/server/static/assets/{chunk-G27WJ6UU-C2EyJbIK.js → chunk-G27WJ6UU-CZwF3oUP.js} +1 -1
  95. ksadk/server/static/assets/{chunk-JWPE2WC7-vYvVJb_M.js → chunk-JWPE2WC7-DigFYCML.js} +1 -1
  96. ksadk/server/static/assets/{chunk-LCL6LL3I-BcI6ysPT.js → chunk-LCL6LL3I-CnorGV5q.js} +1 -1
  97. ksadk/server/static/assets/{chunk-POPQ4Y6H-C030x_Z1.js → chunk-POPQ4Y6H-CexntQA-.js} +1 -1
  98. ksadk/server/static/assets/{chunk-RHFEMEQ7-yyGpsz4n.js → chunk-RHFEMEQ7-CHTC7UxA.js} +1 -1
  99. ksadk/server/static/assets/{chunk-SVP7TREG-BLTlmMU7.js → chunk-SVP7TREG-BC1EWt_-.js} +1 -1
  100. ksadk/server/static/assets/{chunk-XXDRQBXY-C_32ArgP.js → chunk-XXDRQBXY-BTG24xN0.js} +1 -1
  101. ksadk/server/static/assets/classDiagram-DTDB5LWJ-Dd0nucl9.js +1 -0
  102. ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-Dd0nucl9.js +1 -0
  103. ksadk/server/static/assets/{cose-bilkent-JH36ORCC-9YQYwdl0.js → cose-bilkent-JH36ORCC-CkonRdAS.js} +1 -1
  104. ksadk/server/static/assets/cynefin-OW5HDTMX-BBlT4uMf.js +1 -0
  105. ksadk/server/static/assets/{cynefinDiagram-5FMLGOSQ-ErLF5N13.js → cynefinDiagram-5FMLGOSQ-DEOCBe15.js} +1 -1
  106. ksadk/server/static/assets/{dagre-3AP2YEHR-DFiQF-6f.js → dagre-3AP2YEHR-DBThPuLa.js} +1 -1
  107. ksadk/server/static/assets/{dagre-BuhGnRI1.js → dagre-ClTPrTht.js} +1 -1
  108. ksadk/server/static/assets/{diagram-S7CK7UJ4-Bt1v8-GC.js → diagram-S7CK7UJ4-DsZHrnpJ.js} +1 -1
  109. ksadk/server/static/assets/{diagram-UQ7AKVKN-DSCxJdBK.js → diagram-UQ7AKVKN-BJR4nhVr.js} +1 -1
  110. ksadk/server/static/assets/{diagram-VSXAHHWV-DHfYwp_9.js → diagram-VSXAHHWV-xzcERX0a.js} +1 -1
  111. ksadk/server/static/assets/{diagram-VX7I27RA-DdzD-4Le.js → diagram-VX7I27RA-tn2xM1xu.js} +1 -1
  112. ksadk/server/static/assets/{diagram-Z3DM3KII-Du-nAJ9F.js → diagram-Z3DM3KII-BZPGBkw5.js} +1 -1
  113. ksadk/server/static/assets/{dist-ClxGviKw.js → dist-4zN1_tq5.js} +1 -1
  114. ksadk/server/static/assets/{dist-BE7bu-DL.js → dist-8VWI-2bZ.js} +1 -1
  115. ksadk/server/static/assets/{dist-BX8z72IC.js → dist-B-46q3Hk.js} +1 -1
  116. ksadk/server/static/assets/{dist-BjU6y-A2.js → dist-B0gdk4rl.js} +1 -1
  117. ksadk/server/static/assets/{dist-C_wsv-Qd.js → dist-B1oWRmrH.js} +1 -1
  118. ksadk/server/static/assets/{dist-ngtN0DJB.js → dist-BI1qQH4n.js} +1 -1
  119. ksadk/server/static/assets/{dist-dydu68Fl.js → dist-BJLUwH6W.js} +1 -1
  120. ksadk/server/static/assets/{dist-Dq9gLD7L.js → dist-Bbwqa8TG.js} +1 -1
  121. ksadk/server/static/assets/{dist-CttYUqzS.js → dist-Btyo4vX4.js} +1 -1
  122. ksadk/server/static/assets/{dist-CXYYBw3_.js → dist-C71CsujO.js} +1 -1
  123. ksadk/server/static/assets/{dist-dDdADKFA.js → dist-CXpH_Rdd.js} +1 -1
  124. ksadk/server/static/assets/{dist-CSh_DE14.js → dist-Cq4OL6nO.js} +1 -1
  125. ksadk/server/static/assets/{dist-8hqcx0sU.js → dist-D1V3f1B4.js} +1 -1
  126. ksadk/server/static/assets/{dist-BVDffZ0U.js → dist-DJmCPRVB.js} +1 -1
  127. ksadk/server/static/assets/{dist-DnfXs8Vn.js → dist-DQAB0qn_.js} +1 -1
  128. ksadk/server/static/assets/{dist-DNp6rLRA.js → dist-DUwKa_l6.js} +1 -1
  129. ksadk/server/static/assets/{dist-B7seoj3d.js → dist-DdRBIceA.js} +1 -1
  130. ksadk/server/static/assets/{dist-BytlxIDT.js → dist-DfGFrb0v.js} +1 -1
  131. ksadk/server/static/assets/{dist-Bf2M8m3N.js → dist-DjhwGUgZ.js} +1 -1
  132. ksadk/server/static/assets/{dist-W-TIVntx.js → dist-DyqV4fL4.js} +1 -1
  133. ksadk/server/static/assets/{dist-DUX-id_F.js → dist-M67Hwu0n.js} +1 -1
  134. ksadk/server/static/assets/{dist-DmldrHd_.js → dist-u8tVH5Ak.js} +1 -1
  135. ksadk/server/static/assets/{ebnfDiagram-PWID7BFC-Da9C9NO1.js → ebnfDiagram-PWID7BFC-DVfMsLge.js} +1 -1
  136. ksadk/server/static/assets/{erDiagram-SSCWMZ5O-EAGqqR79.js → erDiagram-SSCWMZ5O-CWEZSYaw.js} +1 -1
  137. ksadk/server/static/assets/eventmodeling-NTZA5JFV-Dr5okd8V.js +1 -0
  138. ksadk/server/static/assets/flowDiagram-A5DVABFB-VEO-cVcO.js +1 -0
  139. ksadk/server/static/assets/{ganttDiagram-EL5Y4UJY-DqJsKb59.js → ganttDiagram-EL5Y4UJY-TWIxoyYL.js} +1 -1
  140. ksadk/server/static/assets/gitGraph-4MIJSDKK-CKiKY9Cf.js +1 -0
  141. ksadk/server/static/assets/{gitGraphDiagram-WWUBYQGX-B6g4dtDi.js → gitGraphDiagram-WWUBYQGX-DDh2hd2S.js} +1 -1
  142. ksadk/server/static/assets/index-B2k_urY8.js +241 -0
  143. ksadk/server/static/assets/index-ILPt6IWF.css +2 -0
  144. ksadk/server/static/assets/info-A6RAGUB7-ubA4Nm_p.js +1 -0
  145. ksadk/server/static/assets/{infoDiagram-RXCK75RN-Djm_nbd5.js → infoDiagram-RXCK75RN-CgoyWiDR.js} +1 -1
  146. ksadk/server/static/assets/{ishikawaDiagram-5VMMS53U-DWya9SG2.js → ishikawaDiagram-5VMMS53U-CyRIu_om.js} +1 -1
  147. ksadk/server/static/assets/{journeyDiagram-EYS64GPL-DutxhSNI.js → journeyDiagram-EYS64GPL-DN5JXHzN.js} +1 -1
  148. ksadk/server/static/assets/{kanban-definition-3QL26DDD-DJdOF8Fm.js → kanban-definition-3QL26DDD-CNP3ui66.js} +1 -1
  149. ksadk/server/static/assets/{katex-vFWytM5c.js → katex-DWEzQy1d.js} +1 -1
  150. ksadk/server/static/assets/{linear-BHjG8b-J.js → linear-C-qHp7d2.js} +1 -1
  151. ksadk/server/static/assets/{mermaid-parser.core-KGSy4jWT.js → mermaid-parser.core-Cl-K943T.js} +2 -2
  152. ksadk/server/static/assets/{mindmap-definition-FBJOCRG2-9-HC88D4.js → mindmap-definition-FBJOCRG2-D5DB5mYm.js} +1 -1
  153. ksadk/server/static/assets/packet-AYTQ26CC-C7R3NUlK.js +1 -0
  154. ksadk/server/static/assets/{pegDiagram-XKGWAZYB-DrEZd4fD.js → pegDiagram-XKGWAZYB-BQVc9ia_.js} +1 -1
  155. ksadk/server/static/assets/pie-WAS4IAKB-BIT6qjr3.js +1 -0
  156. ksadk/server/static/assets/{pieDiagram-E7YTZNPT-DpjqOFFp.js → pieDiagram-E7YTZNPT-B6UCAvtY.js} +1 -1
  157. ksadk/server/static/assets/{quadrantDiagram-AXDQQJYC-BiNhgOXX.js → quadrantDiagram-AXDQQJYC-mIr2d3eb.js} +1 -1
  158. ksadk/server/static/assets/radar-RG4KPBEZ-l5noef9X.js +1 -0
  159. ksadk/server/static/assets/railroad-74A4TZTK-Baea6ZvM.js +1 -0
  160. ksadk/server/static/assets/railroad-abnf-HS5TGJTU-OKn8zZnU.js +1 -0
  161. ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-DdKAKC4l.js +1 -0
  162. ksadk/server/static/assets/railroad-peg-WCYAUIDC-Bds8udlG.js +1 -0
  163. ksadk/server/static/assets/{railroadDiagram-O6MQD6OU-_Y3Ojg6G.js → railroadDiagram-O6MQD6OU-Dt3FFDmK.js} +1 -1
  164. ksadk/server/static/assets/{requirementDiagram-EFPCY7ZU-DeCFdg9K.js → requirementDiagram-EFPCY7ZU-Cz_vQtgF.js} +1 -1
  165. ksadk/server/static/assets/{sankeyDiagram-P5KCCOFB-CPH75rhw.js → sankeyDiagram-P5KCCOFB-wlO1TsH5.js} +1 -1
  166. ksadk/server/static/assets/{sequenceDiagram-WJ2MYXX4-OEpQQdr4.js → sequenceDiagram-WJ2MYXX4-CHRbElYq.js} +1 -1
  167. ksadk/server/static/assets/{sizeCapture-X5ZJPWSS-heUErzhI.js → sizeCapture-X5ZJPWSS-DXX54iyO.js} +1 -1
  168. ksadk/server/static/assets/{stateDiagram-HBIQ2CUA-DvA3jSMB.js → stateDiagram-HBIQ2CUA-Dp_lw9II.js} +1 -1
  169. ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-5b-8o2iS.js +1 -0
  170. ksadk/server/static/assets/{swimlanes-XN3QIQJK-CR-dfN_t.js → swimlanes-XN3QIQJK-D8O5UlLG.js} +1 -1
  171. ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-uf6WPRA4.js +8 -0
  172. ksadk/server/static/assets/{timeline-definition-24CTP7MA-DAVJf1TX.js → timeline-definition-24CTP7MA-8mfKcxvG.js} +1 -1
  173. ksadk/server/static/assets/treeView-Q6P3EWNA-CK5CSrSO.js +1 -0
  174. ksadk/server/static/assets/treemap-WGGIJYW6-Ch2BKgAM.js +1 -0
  175. ksadk/server/static/assets/{vennDiagram-4TSXK5OY-DwM8eDkh.js → vennDiagram-4TSXK5OY-EnNl0DE7.js} +1 -1
  176. ksadk/server/static/assets/wardley-WFR3VGLG-YW3Q0ml_.js +1 -0
  177. ksadk/server/static/assets/{wardleyDiagram-VM6X3IG4-DZL-Zz2t.js → wardleyDiagram-VM6X3IG4-DBu5fbYr.js} +1 -1
  178. ksadk/server/static/assets/{xychartDiagram-S5SC5T6Z-Dy6Yh_hu.js → xychartDiagram-S5SC5T6Z-BSVXs4IY.js} +1 -1
  179. ksadk/server/static/index.html +2 -2
  180. ksadk/skills/service_client.py +48 -0
  181. ksadk/studio/agent_lifecycle.py +26 -20
  182. ksadk/studio/api.py +513 -71
  183. ksadk/studio/api_catalog_routes.py +5 -0
  184. ksadk/studio/api_contracts.py +34 -1
  185. ksadk/studio/api_plugin_routes.py +480 -0
  186. ksadk/studio/attachment_store.py +187 -0
  187. ksadk/studio/authoring.py +10 -4
  188. ksadk/studio/authoring_coordinator.py +12 -2
  189. ksadk/studio/builder.py +123 -43
  190. ksadk/studio/cloud.py +4 -0
  191. ksadk/studio/codex_agent_service.py +12 -1
  192. ksadk/studio/codex_builder.py +54 -15
  193. ksadk/studio/codex_manifest.py +21 -1
  194. ksadk/studio/codex_run.py +16 -4
  195. ksadk/studio/compatibility_report.py +445 -0
  196. ksadk/studio/compiler.py +6 -1
  197. ksadk/studio/contracts.py +123 -4
  198. ksadk/studio/dsh_provider_registration.py +768 -0
  199. ksadk/studio/event_store.py +54 -6
  200. ksadk/studio/framework_run.py +37 -4
  201. ksadk/studio/hosted_kernel.py +1 -1
  202. ksadk/studio/operations.py +12 -2
  203. ksadk/studio/plugin_composition.py +301 -0
  204. ksadk/studio/plugin_kernel_adapter.py +128 -0
  205. ksadk/studio/plugin_runtime.py +652 -0
  206. ksadk/studio/resource_catalog.py +6 -1
  207. ksadk/studio/run_service.py +713 -75
  208. ksadk/studio/runtime_source.py +9 -1
  209. ksadk/studio/scheduler_runtime.py +374 -0
  210. ksadk/studio/scheduler_service.py +211 -0
  211. ksadk/studio/service.py +672 -82
  212. ksadk/studio/shared_web.py +167 -28
  213. ksadk/studio/soul.py +52 -0
  214. ksadk/studio/static/assets/index-DXs1Eq4M.css +1 -0
  215. ksadk/studio/static/assets/index-DeDqwTsD.js +283 -0
  216. ksadk/studio/static/index.html +2 -2
  217. ksadk/studio/validator.py +1 -1
  218. ksadk/studio/workspace.py +1 -0
  219. ksadk/version.py +1 -1
  220. ksadk_runtime_common/workspace_files/path_utils.py +41 -0
  221. ksadk/server/static/assets/architecture-7GRP2DOG-DjKratdf.js +0 -1
  222. ksadk/server/static/assets/channel-4cQHKtx1.js +0 -1
  223. ksadk/server/static/assets/chunk-2Q5K7J3B-DmgWkESh.js +0 -1
  224. ksadk/server/static/assets/classDiagram-DTDB5LWJ-DLFd9Xi0.js +0 -1
  225. ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-DLFd9Xi0.js +0 -1
  226. ksadk/server/static/assets/cynefin-OW5HDTMX-DjEM48Qp.js +0 -1
  227. ksadk/server/static/assets/eventmodeling-NTZA5JFV-CMgMaJrC.js +0 -1
  228. ksadk/server/static/assets/flowDiagram-A5DVABFB-BBKL0x3P.js +0 -1
  229. ksadk/server/static/assets/gitGraph-4MIJSDKK-Dw63mrhw.js +0 -1
  230. ksadk/server/static/assets/index-8ipRcQ-M.js +0 -240
  231. ksadk/server/static/assets/index-ByFCqjlh.css +0 -2
  232. ksadk/server/static/assets/info-A6RAGUB7-B6iAblII.js +0 -1
  233. ksadk/server/static/assets/packet-AYTQ26CC-BOYAipuq.js +0 -1
  234. ksadk/server/static/assets/pie-WAS4IAKB-Ctq0Kbku.js +0 -1
  235. ksadk/server/static/assets/radar-RG4KPBEZ-DN0-ul_0.js +0 -1
  236. ksadk/server/static/assets/railroad-74A4TZTK-C6cC_to0.js +0 -1
  237. ksadk/server/static/assets/railroad-abnf-HS5TGJTU-BimjIuRc.js +0 -1
  238. ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-CvY65ABq.js +0 -1
  239. ksadk/server/static/assets/railroad-peg-WCYAUIDC-D72Iq_Tv.js +0 -1
  240. ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-BgQY03nz.js +0 -1
  241. ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-DLVw3q5Q.js +0 -8
  242. ksadk/server/static/assets/treeView-Q6P3EWNA-BMpO0wsB.js +0 -1
  243. ksadk/server/static/assets/treemap-WGGIJYW6-Et0aqzU3.js +0 -1
  244. ksadk/server/static/assets/wardley-WFR3VGLG-CbY0mhpl.js +0 -1
  245. ksadk/studio/static/assets/index-BLpcdrgW.css +0 -1
  246. ksadk/studio/static/assets/index-CYekR2Xv.js +0 -260
  247. {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.3.dist-info}/WHEEL +0 -0
  248. {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.3.dist-info}/entry_points.txt +0 -0
  249. {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.3.dist-info}/licenses/LICENSE +0 -0
  250. {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"]