agentengine-sdk-python 0.8.1__py3-none-any.whl → 0.8.2__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 (411) hide show
  1. {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.2.dist-info}/METADATA +22 -2
  2. {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.2.dist-info}/RECORD +356 -222
  3. ksadk/a2a/_space_client_events.py +381 -0
  4. ksadk/a2a/event_adapter.py +156 -64
  5. ksadk/a2a/executor.py +179 -63
  6. ksadk/a2a/space_client.py +6 -333
  7. ksadk/a2ui/core.py +222 -53
  8. ksadk/agui/_agent_helpers.py +243 -0
  9. ksadk/agui/a2ui_projection.py +12 -5
  10. ksadk/agui/agent.py +443 -259
  11. ksadk/api/client.py +525 -27
  12. ksadk/builders/code_builder.py +284 -8
  13. ksadk/builders/container_builder.py +8 -1
  14. ksadk/builders/managed_runtime_builder.py +39 -35
  15. ksadk/cli/__init__.py +17 -0
  16. ksadk/cli/cmd_dashboard.py +15 -1
  17. ksadk/cli/cmd_deploy.py +10 -2
  18. ksadk/cli/cmd_eval.py +66 -9
  19. ksadk/cli/cmd_evalset.py +284 -0
  20. ksadk/cli/cmd_files.py +5 -1
  21. ksadk/cli/cmd_hermes.py +1 -126
  22. ksadk/cli/cmd_invoke.py +28 -38
  23. ksadk/cli/cmd_managed_runtime.py +95 -0
  24. ksadk/cli/cmd_observe.py +85 -0
  25. ksadk/cli/cmd_openclaw.py +1 -435
  26. ksadk/cli/cmd_replay.py +28 -4
  27. ksadk/cli/cmd_studio.py +99 -8
  28. ksadk/cli/cmd_web.py +10 -2
  29. ksadk/cli/hermes_env.py +151 -0
  30. ksadk/cli/invoke_payload.py +49 -0
  31. ksadk/cli/openclaw_env.py +458 -0
  32. ksadk/codex/client.py +180 -30
  33. ksadk/codex/runtime.py +428 -326
  34. ksadk/configs/env_registry.py +66 -12
  35. ksadk/configs/env_registry_pcm.py +181 -0
  36. ksadk/configs/env_var_spec.py +18 -0
  37. ksadk/configs/global_config.py +5 -0
  38. ksadk/context_engine/__init__.py +98 -0
  39. ksadk/context_engine/assembler.py +176 -0
  40. ksadk/context_engine/baseline.py +419 -0
  41. ksadk/context_engine/cache_observability.py +228 -0
  42. ksadk/context_engine/capabilities.py +443 -0
  43. ksadk/context_engine/contributors.py +344 -0
  44. ksadk/context_engine/hosted_pipeline.py +417 -0
  45. ksadk/context_engine/models.py +117 -0
  46. ksadk/context_engine/planner.py +698 -0
  47. ksadk/context_engine/policies.py +319 -0
  48. ksadk/context_engine/projection.py +31 -0
  49. ksadk/context_engine/shadow_plan.py +266 -0
  50. ksadk/context_engine/tokenizer.py +164 -0
  51. ksadk/conversations/context.py +126 -6
  52. ksadk/conversations/message_projection.py +292 -28
  53. ksadk/conversations/model_context.py +49 -3
  54. ksadk/conversations/runtime_compaction.py +207 -5
  55. ksadk/conversations/runtime_input.py +184 -2
  56. ksadk/conversations/runtime_invocation.py +81 -3
  57. ksadk/conversations/runtime_observability.py +141 -0
  58. ksadk/conversations/runtime_payloads.py +42 -0
  59. ksadk/conversations/runtime_preparation.py +272 -2
  60. ksadk/conversations/runtime_resume.py +20 -1
  61. ksadk/conversations/runtime_stream_events.py +94 -9
  62. ksadk/conversations/semantic_summary.py +311 -1
  63. ksadk/conversations/session_lock.py +51 -0
  64. ksadk/deployment/env_forward.py +72 -0
  65. ksadk/deployment/managed_runtime.py +5 -0
  66. ksadk/deployment/providers/serverless.py +143 -69
  67. ksadk/evaluation/__init__.py +32 -0
  68. ksadk/evaluation/a2a_adapter.py +9 -1
  69. ksadk/evaluation/adapters.py +18 -5
  70. ksadk/evaluation/agent_eval_client.py +395 -0
  71. ksadk/evaluation/cloud_binding.py +80 -0
  72. ksadk/evaluation/cloud_converter.py +194 -0
  73. ksadk/evaluation/cloud_service.py +199 -0
  74. ksadk/evaluation/contracts.py +73 -4
  75. ksadk/evaluation/evaluators.py +183 -17
  76. ksadk/evaluation/evidence.py +258 -0
  77. ksadk/evaluation/executor.py +31 -6
  78. ksadk/evaluation/local_adapter.py +550 -0
  79. ksadk/evaluation/service_env.py +27 -0
  80. ksadk/evaluation/studio_build_adapter.py +253 -0
  81. ksadk/evaluation/target.py +15 -6
  82. ksadk/events/__init__.py +13 -13
  83. ksadk/events/_v1_compat/__init__.py +1 -0
  84. ksadk/events/_v1_compat/models.py +299 -0
  85. ksadk/events/_v1_compat/parser.py +247 -0
  86. ksadk/events/_v1_compat/projection.py +753 -0
  87. ksadk/events/adapters/__init__.py +34 -0
  88. ksadk/events/adapters/_a2a_snapshot.py +622 -0
  89. ksadk/events/adapters/_a2a_support.py +275 -0
  90. ksadk/events/adapters/_codex_interactions.py +375 -0
  91. ksadk/events/adapters/_codex_items.py +801 -0
  92. ksadk/events/adapters/_codex_validators.py +311 -0
  93. ksadk/events/adapters/_langgraph_support.py +785 -0
  94. ksadk/events/adapters/a2a.py +841 -0
  95. ksadk/events/adapters/adk.py +503 -0
  96. ksadk/events/adapters/codex.py +717 -0
  97. ksadk/events/adapters/langgraph.py +745 -0
  98. ksadk/events/canonical.py +440 -0
  99. ksadk/events/canonical_replay.py +497 -0
  100. ksadk/events/canonical_store.py +468 -0
  101. ksadk/events/cold_recovery.py +257 -0
  102. ksadk/events/content.py +89 -0
  103. ksadk/events/identity.py +86 -0
  104. ksadk/events/pipeline.py +455 -0
  105. ksadk/events/projections.py +66 -0
  106. ksadk/events/reducer.py +661 -0
  107. ksadk/events/replay.py +3 -36
  108. ksadk/events/runtime_event.py +20 -265
  109. ksadk/events/session_event.py +324 -0
  110. ksadk/events/store.py +3 -316
  111. ksadk/events/v1_compat.py +41 -0
  112. ksadk/harness/runtime.py +160 -57
  113. ksadk/identity/resolver.py +4 -3
  114. ksadk/interaction/__init__.py +28 -0
  115. ksadk/interaction/contracts.py +136 -0
  116. ksadk/interaction/ledger.py +189 -0
  117. ksadk/interaction/provider.py +122 -0
  118. ksadk/interaction/providers/__init__.py +52 -0
  119. ksadk/interaction/providers/adk.py +40 -0
  120. ksadk/interaction/providers/codex.py +94 -0
  121. ksadk/interaction/providers/langgraph.py +58 -0
  122. ksadk/kernel/__init__.py +117 -0
  123. ksadk/kernel/authorization.py +258 -0
  124. ksadk/kernel/bootstrap.py +1074 -0
  125. ksadk/kernel/contract_fingerprints.py +61 -0
  126. ksadk/kernel/contracts.py +362 -0
  127. ksadk/kernel/control.py +219 -0
  128. ksadk/kernel/errors.py +79 -0
  129. ksadk/kernel/ingress.py +1102 -0
  130. ksadk/kernel/mapping.py +111 -0
  131. ksadk/kernel/memory_store.py +1133 -0
  132. ksadk/kernel/postgres_store.py +1756 -0
  133. ksadk/kernel/recovery.py +452 -0
  134. ksadk/kernel/runtime_identity.py +103 -0
  135. ksadk/kernel/sql/001_agent_kernel.sql +120 -0
  136. ksadk/kernel/sqlite_store.py +1410 -0
  137. ksadk/kernel/state.py +145 -0
  138. ksadk/kernel/store.py +232 -0
  139. ksadk/kernel/worker.py +953 -0
  140. ksadk/knowledge_base/client.py +7 -0
  141. ksadk/knowledge_base/service.py +32 -5
  142. ksadk/memory/__init__.py +61 -0
  143. ksadk/memory/adk/backends/base_ltm_backend.py +96 -1
  144. ksadk/memory/adk/backends/http_ltm_backend.py +14 -5
  145. ksadk/memory/adk/backends/inmemory_ltm_backend.py +136 -3
  146. ksadk/memory/adk/backends/sdk_ltm_backend.py +384 -2
  147. ksadk/memory/adk/backends/sqlite_ltm_backend.py +95 -0
  148. ksadk/memory/coordinator.py +461 -0
  149. ksadk/memory/events.py +202 -0
  150. ksadk/memory/extraction.py +228 -0
  151. ksadk/memory/ltm_backend_factory.py +16 -3
  152. ksadk/memory/models.py +316 -0
  153. ksadk/memory/policy.py +215 -0
  154. ksadk/memory/provider.py +47 -0
  155. ksadk/memory/provider_adapter.py +159 -0
  156. ksadk/memory/provider_resolver.py +71 -0
  157. ksadk/memory/providers/__init__.py +5 -0
  158. ksadk/memory/providers/local_sqlite.py +490 -0
  159. ksadk/memory/resolved_policy.py +145 -0
  160. ksadk/memory/service.py +188 -6
  161. ksadk/model_proxy/bootstrap.py +16 -9
  162. ksadk/model_proxy/detect.py +202 -9
  163. ksadk/model_proxy/namespace.py +39 -15
  164. ksadk/model_proxy/server.py +24 -5
  165. ksadk/model_proxy/transform.py +60 -2
  166. ksadk/observability/__init__.py +25 -0
  167. ksadk/observability/session_log.py +420 -0
  168. ksadk/observability/trajectory.py +105 -0
  169. ksadk/prompts/__init__.py +71 -0
  170. ksadk/prompts/compiler.py +215 -0
  171. ksadk/prompts/models.py +82 -0
  172. ksadk/prompts/projection.py +89 -0
  173. ksadk/prompts/resolved.py +137 -0
  174. ksadk/prompts/sources.py +233 -0
  175. ksadk/runners/_langgraph_runner_streams.py +822 -0
  176. ksadk/runners/adk_runner.py +5 -5
  177. ksadk/runners/base_runner.py +16 -0
  178. ksadk/runners/factory.py +1 -2
  179. ksadk/runners/langgraph_runner.py +198 -437
  180. ksadk/runtime/_runner_adapter/__init__.py +1 -0
  181. ksadk/runtime/_runner_adapter/stream_mapping.py +788 -0
  182. ksadk/runtime/adapter.py +118 -2
  183. ksadk/runtime/conversation_execution.py +316 -182
  184. ksadk/runtime/executor.py +144 -3
  185. ksadk/runtime/factory.py +193 -7
  186. ksadk/runtime/hosted_finalizer.py +268 -0
  187. ksadk/runtime/launch.py +14 -1
  188. ksadk/runtime/preprocessing.py +25 -3
  189. ksadk/runtime/runner_adapter.py +288 -508
  190. ksadk/runtime/usage.py +33 -0
  191. ksadk/sandbox/backends/e2b.py +35 -2
  192. ksadk/server/composition.py +8 -0
  193. ksadk/server/factory.py +69 -6
  194. ksadk/server/routes/kernel_ingress.py +258 -0
  195. ksadk/server/routes/openai_compat.py +88 -8
  196. ksadk/server/routes/projection.py +35 -20
  197. ksadk/server/routes/run.py +94 -0
  198. ksadk/server/routes/sessions.py +2 -0
  199. ksadk/server/routes/streaming.py +5 -2
  200. ksadk/server/static/assets/{ArtifactsPanel-CakCqxEN.js → ArtifactsPanel-DSU1sWD_.js} +1 -1
  201. ksadk/server/static/assets/{CodeBlock-CynLknyO.js → CodeBlock-DOH6MVcn.js} +4 -4
  202. ksadk/server/static/assets/{MathMessageMarkdown-3sQdOysS.js → MathMessageMarkdown-BL8my1R2.js} +4 -4
  203. ksadk/server/static/assets/MathMessageMarkdown-BorAY7qD.css +1 -0
  204. ksadk/server/static/assets/MermaidBlock-Dz4IP-Tx.js +312 -0
  205. ksadk/server/static/assets/NativeTerminalPanel-DUrK0JpZ.js +1 -0
  206. ksadk/server/static/assets/abnfDiagram-VCTEODGH-g20pFzNV.js +1 -0
  207. ksadk/server/static/assets/arc-C4FzinUA.js +1 -0
  208. ksadk/server/static/assets/architecture-7GRP2DOG-DjKratdf.js +1 -0
  209. ksadk/server/static/assets/architectureDiagram-5GKGNRK7-DpIqL5h4.js +36 -0
  210. ksadk/server/static/assets/blockDiagram-NRAW4CY4-BjkljTNz.js +129 -0
  211. ksadk/server/static/assets/c4Diagram-UCG6FXSJ-Dk_ieq2X.js +38 -0
  212. ksadk/server/static/assets/channel-4cQHKtx1.js +1 -0
  213. ksadk/server/static/assets/chunk-2Q5K7J3B-DmgWkESh.js +1 -0
  214. ksadk/server/static/assets/{chunk-FMBD7UC4-B_fH2YuH.js → chunk-5VM5RSS4-BVHAchFb.js} +1 -1
  215. ksadk/server/static/assets/{chunk-ND2GUHAM-D6rFLaVV.js → chunk-F27PBJKO-C-ipQzuS.js} +1 -1
  216. ksadk/server/static/assets/chunk-G27WJ6UU-C2EyJbIK.js +231 -0
  217. ksadk/server/static/assets/{chunk-4BX2VUAB-B9drTgOW.js → chunk-JWPE2WC7-vYvVJb_M.js} +1 -1
  218. ksadk/server/static/assets/chunk-LCL6LL3I-BcI6ysPT.js +206 -0
  219. ksadk/server/static/assets/chunk-POPQ4Y6H-C030x_Z1.js +1 -0
  220. ksadk/server/static/assets/chunk-RHFEMEQ7-yyGpsz4n.js +168 -0
  221. ksadk/server/static/assets/chunk-SVP7TREG-BLTlmMU7.js +88 -0
  222. ksadk/server/static/assets/chunk-XXDRQBXY-C_32ArgP.js +1 -0
  223. ksadk/server/static/assets/classDiagram-DTDB5LWJ-DLFd9Xi0.js +1 -0
  224. ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-DLFd9Xi0.js +1 -0
  225. ksadk/server/static/assets/{cose-bilkent-S5V4N54A-ChNs_Mdk.js → cose-bilkent-JH36ORCC-9YQYwdl0.js} +1 -1
  226. ksadk/server/static/assets/cynefin-OW5HDTMX-DjEM48Qp.js +1 -0
  227. ksadk/server/static/assets/cynefinDiagram-5FMLGOSQ-ErLF5N13.js +62 -0
  228. ksadk/server/static/assets/cytoscape.esm-CyCl8rPi.js +321 -0
  229. ksadk/server/static/assets/dagre-3AP2YEHR-DFiQF-6f.js +4 -0
  230. ksadk/server/static/assets/dagre-BuhGnRI1.js +1 -0
  231. ksadk/server/static/assets/diagram-S7CK7UJ4-Bt1v8-GC.js +30 -0
  232. ksadk/server/static/assets/diagram-UQ7AKVKN-DSCxJdBK.js +41 -0
  233. ksadk/server/static/assets/diagram-VSXAHHWV-DHfYwp_9.js +3 -0
  234. ksadk/server/static/assets/diagram-VX7I27RA-DdzD-4Le.js +24 -0
  235. ksadk/server/static/assets/diagram-Z3DM3KII-Du-nAJ9F.js +24 -0
  236. ksadk/server/static/assets/{dist-Dli7qW-B.js → dist-8hqcx0sU.js} +1 -1
  237. ksadk/server/static/assets/dist-B7seoj3d.js +1 -0
  238. ksadk/server/static/assets/{dist-C1sz5Eo3.js → dist-BE7bu-DL.js} +1 -1
  239. ksadk/server/static/assets/{dist-fhOuWds5.js → dist-BVDffZ0U.js} +1 -1
  240. ksadk/server/static/assets/{dist-BjOdlDjj.js → dist-BX8z72IC.js} +1 -1
  241. ksadk/server/static/assets/{dist-DsHPdk3W.js → dist-Bf2M8m3N.js} +1 -1
  242. ksadk/server/static/assets/{dist-o2OVmKvt.js → dist-BjU6y-A2.js} +1 -1
  243. ksadk/server/static/assets/{dist-DWKByxWV.js → dist-BytlxIDT.js} +1 -1
  244. ksadk/server/static/assets/{dist-DJN_6Y39.js → dist-CSh_DE14.js} +1 -1
  245. ksadk/server/static/assets/{dist-DQU9EWw-.js → dist-CXYYBw3_.js} +1 -1
  246. ksadk/server/static/assets/{dist-4N2NMVYg.js → dist-C_wsv-Qd.js} +1 -1
  247. ksadk/server/static/assets/{dist-gLnrGsoU.js → dist-ClxGviKw.js} +1 -1
  248. ksadk/server/static/assets/{dist-j6Dxmf_j.js → dist-CttYUqzS.js} +1 -1
  249. ksadk/server/static/assets/{dist-D6MpCZtz.js → dist-DNp6rLRA.js} +1 -1
  250. ksadk/server/static/assets/{dist-BB3-OwTQ.js → dist-DUX-id_F.js} +1 -1
  251. ksadk/server/static/assets/{dist-_pHPTyZ-.js → dist-DmldrHd_.js} +1 -1
  252. ksadk/server/static/assets/{dist-CWV4lDr1.js → dist-DnfXs8Vn.js} +2 -2
  253. ksadk/server/static/assets/{dist-B5oS1zcj.js → dist-Dq9gLD7L.js} +1 -1
  254. ksadk/server/static/assets/{dist-B-jNR6Vn.js → dist-W-TIVntx.js} +1 -1
  255. ksadk/server/static/assets/{dist-BIlKoW0k.js → dist-dDdADKFA.js} +1 -1
  256. ksadk/server/static/assets/{dist-X4TnqwOK.js → dist-dydu68Fl.js} +1 -1
  257. ksadk/server/static/assets/{dist-CmZHzlwZ.js → dist-ngtN0DJB.js} +1 -1
  258. ksadk/server/static/assets/ebnfDiagram-PWID7BFC-Da9C9NO1.js +1 -0
  259. ksadk/server/static/assets/erDiagram-SSCWMZ5O-EAGqqR79.js +99 -0
  260. ksadk/server/static/assets/eventmodeling-NTZA5JFV-CMgMaJrC.js +1 -0
  261. ksadk/server/static/assets/flowDiagram-A5DVABFB-BBKL0x3P.js +1 -0
  262. ksadk/server/static/assets/ganttDiagram-EL5Y4UJY-DqJsKb59.js +292 -0
  263. ksadk/server/static/assets/gitGraph-4MIJSDKK-Dw63mrhw.js +1 -0
  264. ksadk/server/static/assets/gitGraphDiagram-WWUBYQGX-B6g4dtDi.js +106 -0
  265. ksadk/server/static/assets/index-8ipRcQ-M.js +240 -0
  266. ksadk/server/static/assets/index-ByFCqjlh.css +2 -0
  267. ksadk/server/static/assets/info-A6RAGUB7-B6iAblII.js +1 -0
  268. ksadk/server/static/assets/infoDiagram-RXCK75RN-Djm_nbd5.js +2 -0
  269. ksadk/server/static/assets/{ishikawaDiagram-YF4QCWOH-K0OOfVna.js → ishikawaDiagram-5VMMS53U-DWya9SG2.js} +6 -6
  270. ksadk/server/static/assets/{journeyDiagram-JHISSGLW-8LeOJaZp.js → journeyDiagram-EYS64GPL-DutxhSNI.js} +6 -6
  271. ksadk/server/static/assets/{kanban-definition-UN3LZRKU-C6uCgZrW.js → kanban-definition-3QL26DDD-DJdOF8Fm.js} +10 -10
  272. ksadk/server/static/assets/katex-vFWytM5c.js +257 -0
  273. ksadk/server/static/assets/{linear-hdBcYzM8.js → linear-BHjG8b-J.js} +1 -1
  274. ksadk/server/static/assets/mermaid-parser.core-KGSy4jWT.js +166 -0
  275. ksadk/server/static/assets/{mindmap-definition-RKZ34NQL-Bjy_2v4_.js → mindmap-definition-FBJOCRG2-9-HC88D4.js} +29 -29
  276. ksadk/server/static/assets/packet-AYTQ26CC-BOYAipuq.js +1 -0
  277. ksadk/server/static/assets/pegDiagram-XKGWAZYB-DrEZd4fD.js +1 -0
  278. ksadk/server/static/assets/pie-WAS4IAKB-Ctq0Kbku.js +1 -0
  279. ksadk/server/static/assets/pieDiagram-E7YTZNPT-DpjqOFFp.js +39 -0
  280. ksadk/server/static/assets/{quadrantDiagram-W4KKPZXB-BmkRbwCg.js → quadrantDiagram-AXDQQJYC-BiNhgOXX.js} +6 -6
  281. ksadk/server/static/assets/radar-RG4KPBEZ-DN0-ul_0.js +1 -0
  282. ksadk/server/static/assets/railroad-74A4TZTK-C6cC_to0.js +1 -0
  283. ksadk/server/static/assets/railroad-abnf-HS5TGJTU-BimjIuRc.js +1 -0
  284. ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-CvY65ABq.js +1 -0
  285. ksadk/server/static/assets/railroad-peg-WCYAUIDC-D72Iq_Tv.js +1 -0
  286. ksadk/server/static/assets/railroadDiagram-O6MQD6OU-_Y3Ojg6G.js +1 -0
  287. ksadk/server/static/assets/requirementDiagram-EFPCY7ZU-DeCFdg9K.js +84 -0
  288. ksadk/server/static/assets/{sankeyDiagram-5OEKKPKP-l6iXmU65.js → sankeyDiagram-P5KCCOFB-CPH75rhw.js} +7 -7
  289. ksadk/server/static/assets/{sequenceDiagram-3UESZ5HK-Cq6UBeQB.js → sequenceDiagram-WJ2MYXX4-OEpQQdr4.js} +10 -10
  290. ksadk/server/static/assets/sizeCapture-X5ZJPWSS-heUErzhI.js +1 -0
  291. ksadk/server/static/assets/stateDiagram-HBIQ2CUA-DvA3jSMB.js +1 -0
  292. ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-BgQY03nz.js +1 -0
  293. ksadk/server/static/assets/swimlanes-XN3QIQJK-CR-dfN_t.js +1 -0
  294. ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-DLVw3q5Q.js +8 -0
  295. ksadk/server/static/assets/{timeline-definition-PNZ67QCA-DEz24vV0.js → timeline-definition-24CTP7MA-DAVJf1TX.js} +7 -7
  296. ksadk/server/static/assets/treeView-Q6P3EWNA-BMpO0wsB.js +1 -0
  297. ksadk/server/static/assets/treemap-WGGIJYW6-Et0aqzU3.js +1 -0
  298. ksadk/server/static/assets/vennDiagram-4TSXK5OY-DwM8eDkh.js +34 -0
  299. ksadk/server/static/assets/wardley-WFR3VGLG-CbY0mhpl.js +1 -0
  300. ksadk/server/static/assets/wardleyDiagram-VM6X3IG4-DZL-Zz2t.js +78 -0
  301. ksadk/server/static/assets/xychartDiagram-S5SC5T6Z-Dy6Yh_hu.js +7 -0
  302. ksadk/server/static/index.html +2 -2
  303. ksadk/sessions/__init__.py +26 -9
  304. ksadk/sessions/_local_service_sync.py +688 -0
  305. ksadk/sessions/_local_tables.py +21 -0
  306. ksadk/sessions/_postgres_schema.py +305 -0
  307. ksadk/sessions/_postgres_tables.py +15 -0
  308. ksadk/sessions/base.py +80 -1
  309. ksadk/sessions/in_memory.py +53 -2
  310. ksadk/sessions/local_service.py +63 -604
  311. ksadk/sessions/postgres_service.py +58 -148
  312. ksadk/sessions/resilient.py +35 -1
  313. ksadk/studio/api.py +577 -25
  314. ksadk/studio/api_contracts.py +114 -5
  315. ksadk/studio/api_memory_routes.py +82 -0
  316. ksadk/studio/authoring.py +252 -27
  317. ksadk/studio/authoring_coordinator.py +799 -67
  318. ksadk/studio/builder.py +88 -11
  319. ksadk/studio/capabilities.py +17 -0
  320. ksadk/studio/cloud.py +1916 -95
  321. ksadk/studio/codex_agent_service.py +125 -14
  322. ksadk/studio/codex_authoring.py +469 -0
  323. ksadk/studio/codex_builder.py +138 -25
  324. ksadk/studio/codex_manifest.py +51 -22
  325. ksadk/studio/codex_run.py +46 -3
  326. ksadk/studio/compiler.py +1 -0
  327. ksadk/studio/contracts.py +114 -3
  328. ksadk/studio/event_store.py +25 -95
  329. ksadk/studio/framework_run.py +231 -3
  330. ksadk/studio/hosted_kernel.py +317 -0
  331. ksadk/studio/manifest_resolver.py +131 -0
  332. ksadk/studio/model_client.py +95 -9
  333. ksadk/studio/model_profile_service.py +1 -1
  334. ksadk/studio/operations.py +37 -5
  335. ksadk/studio/otel_trace.py +348 -42
  336. ksadk/studio/pcm_memory.py +85 -0
  337. ksadk/studio/repository.py +23 -2
  338. ksadk/studio/resource_catalog.py +43 -0
  339. ksadk/studio/run_service.py +563 -137
  340. ksadk/studio/runtime_source.py +42 -16
  341. ksadk/studio/service.py +1180 -72
  342. ksadk/studio/shared_web.py +32 -22
  343. ksadk/studio/static/assets/index-BLpcdrgW.css +1 -0
  344. ksadk/studio/static/assets/index-CYekR2Xv.js +260 -0
  345. ksadk/studio/static/index.html +2 -2
  346. ksadk/studio/templates.py +100 -8
  347. ksadk/studio/validator.py +19 -0
  348. ksadk/studio/workspace.py +30 -32
  349. ksadk/tracing/setup.py +304 -3
  350. ksadk/version.py +1 -1
  351. ksadk_runtime_common/schemas/runtime_event_v1.json +37 -0
  352. ksadk_runtime_common/schemas/runtime_event_v2.json +271 -0
  353. ksadk/events/parser.py +0 -191
  354. ksadk/server/static/assets/MathMessageMarkdown-DeYh8QPr.css +0 -1
  355. ksadk/server/static/assets/MermaidBlock-NERD_ef7.js +0 -303
  356. ksadk/server/static/assets/NativeTerminalPanel-CiHWf82q.js +0 -1
  357. ksadk/server/static/assets/arc-DrgjcKhl.js +0 -1
  358. ksadk/server/static/assets/architecture-7EHR7CIX-CpZLRCcY.js +0 -1
  359. ksadk/server/static/assets/architectureDiagram-3BPJPVTR-BXoVRbQ6.js +0 -36
  360. ksadk/server/static/assets/blockDiagram-GPEHLZMM-BnaB3Ywv.js +0 -132
  361. ksadk/server/static/assets/c4Diagram-AAUBKEIU-Dw4weZcp.js +0 -10
  362. ksadk/server/static/assets/channel-Dt3rQTFI.js +0 -1
  363. ksadk/server/static/assets/chunk-2J33WTMH-ChjpLK7j.js +0 -1
  364. ksadk/server/static/assets/chunk-55IACEB6-CK4ROATy.js +0 -1
  365. ksadk/server/static/assets/chunk-727SXJPM-B9KtTTgw.js +0 -206
  366. ksadk/server/static/assets/chunk-AQP2D5EJ-1O1mki3m.js +0 -231
  367. ksadk/server/static/assets/chunk-QZHKN3VN-iXEZtKQc.js +0 -1
  368. ksadk/server/static/assets/classDiagram-4FO5ZUOK-DIveV17Q.js +0 -1
  369. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-DIveV17Q.js +0 -1
  370. ksadk/server/static/assets/cytoscape.esm-DelgaX4f.js +0 -321
  371. ksadk/server/static/assets/dagre-BM42HDAG-D0QXg_MQ.js +0 -4
  372. ksadk/server/static/assets/dagre-Bx709z4p.js +0 -1
  373. ksadk/server/static/assets/diagram-2AECGRRQ-DBDDKwBQ.js +0 -43
  374. ksadk/server/static/assets/diagram-5GNKFQAL-BkwDOxmO.js +0 -10
  375. ksadk/server/static/assets/diagram-KO2AKTUF-Bv8waYvY.js +0 -3
  376. ksadk/server/static/assets/diagram-LMA3HP47-e1VECDdu.js +0 -24
  377. ksadk/server/static/assets/diagram-OG6HWLK6-Ds9adfRl.js +0 -24
  378. ksadk/server/static/assets/dist-B5J2uhNk.js +0 -1
  379. ksadk/server/static/assets/erDiagram-TEJ5UH35-BPItFKH6.js +0 -85
  380. ksadk/server/static/assets/eventmodeling-FCH6USID-DYFSxbqr.js +0 -1
  381. ksadk/server/static/assets/flowDiagram-I6XJVG4X-BbYB9w5Y.js +0 -162
  382. ksadk/server/static/assets/ganttDiagram-6RSMTGT7-TQXa0KXv.js +0 -292
  383. ksadk/server/static/assets/gitGraph-WXDBUCRP-DyNYp6BN.js +0 -1
  384. ksadk/server/static/assets/gitGraphDiagram-PVQCEYII-bKblCnpa.js +0 -106
  385. ksadk/server/static/assets/graphlib-B8gBHxth.js +0 -1
  386. ksadk/server/static/assets/index-R52pJJvg.js +0 -177
  387. ksadk/server/static/assets/index-jJr3_955.css +0 -2
  388. ksadk/server/static/assets/info-J43DQDTF-WUx7qTde.js +0 -1
  389. ksadk/server/static/assets/infoDiagram-5YYISTIA-BGVT7J_i.js +0 -2
  390. ksadk/server/static/assets/katex-CYWseY5E.js +0 -265
  391. ksadk/server/static/assets/mermaid-parser.core-BWrDjSZM.js +0 -161
  392. ksadk/server/static/assets/packet-YPE3B663-BN13y_xl.js +0 -1
  393. ksadk/server/static/assets/pie-LRSECV5Y-ftSLXhhc.js +0 -1
  394. ksadk/server/static/assets/pieDiagram-4H26LBE5-GmmqNiVH.js +0 -30
  395. ksadk/server/static/assets/radar-GUYGQ44K-jaICkIeO.js +0 -1
  396. ksadk/server/static/assets/requirementDiagram-4Y6WPE33-DSWFqL7c.js +0 -84
  397. ksadk/server/static/assets/stateDiagram-AJRCARHV-qzTQpg3Y.js +0 -1
  398. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-BYCoYGAN.js +0 -1
  399. ksadk/server/static/assets/treeView-BLDUP644-Cpib_vlz.js +0 -1
  400. ksadk/server/static/assets/treemap-LRROVOQU-DQxfmVHK.js +0 -1
  401. ksadk/server/static/assets/vennDiagram-CIIHVFJN-CMCixki2.js +0 -34
  402. ksadk/server/static/assets/wardley-L42UT6IY-BQYHnnkU.js +0 -1
  403. ksadk/server/static/assets/wardleyDiagram-YWT4CUSO-CVzB8F9K.js +0 -78
  404. ksadk/server/static/assets/xychartDiagram-2RQKCTM6-BFBqBLc1.js +0 -7
  405. ksadk/studio/evaluation.py +0 -192
  406. ksadk/studio/static/assets/index-CaEN0eTR.css +0 -1
  407. ksadk/studio/static/assets/index-DI2eY_NH.js +0 -252
  408. {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.2.dist-info}/WHEEL +0 -0
  409. {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.2.dist-info}/entry_points.txt +0 -0
  410. {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.2.dist-info}/licenses/LICENSE +0 -0
  411. {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.2.dist-info}/top_level.txt +0 -0
@@ -3,6 +3,7 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import asyncio
6
+ import time
6
7
  from collections.abc import AsyncIterator, Callable, Mapping, Sequence
7
8
  from dataclasses import asdict
8
9
  from typing import Any
@@ -14,7 +15,27 @@ from ksadk.conversations.runtime_metadata import (
14
15
  )
15
16
  from ksadk.conversations.runtime_persistence import append_run_status_event
16
17
  from ksadk.conversations.runtime_preparation import build_run_input
17
- from ksadk.events.runtime_event import EventType, RuntimeEvent
18
+ from ksadk.events.canonical import (
19
+ ContextCompactionCompleted,
20
+ ContextCompactionStarted,
21
+ ContinuationCreated,
22
+ ContinuationResumed,
23
+ InteractionRequested,
24
+ ItemCompleted,
25
+ ItemStarted,
26
+ ItemUpdated,
27
+ RunCanceled,
28
+ RunCompleted,
29
+ RunFailed,
30
+ RunInterrupted,
31
+ RunStarted,
32
+ RuntimeEvent,
33
+ SourceRef,
34
+ UsageReported,
35
+ )
36
+ from ksadk.events.content import TextContent, ToolCallContent, ToolResultContent
37
+ from ksadk.events.pipeline import CanonicalEventPipeline
38
+ from ksadk.events.reducer import RunProjection, StreamReducer
18
39
  from ksadk.events.store import RuntimeEventStore
19
40
  from ksadk.runtime.adapter import (
20
41
  CONVERSATION_PREPROCESSING_METADATA_KEY,
@@ -25,23 +46,24 @@ from ksadk.runtime.adapter import (
25
46
  StartRequest,
26
47
  )
27
48
  from ksadk.runtime.executor import RuntimeExecutor, RuntimeStartPreparation
49
+ from ksadk.runtime.factory import apply_runtime_start_request_defaults
28
50
  from ksadk.runtime.launch import RuntimeLaunchContext
29
51
  from ksadk.sessions import resolve_session_service
30
52
 
31
53
  _TERMINAL_EVENTS = frozenset(
32
54
  {
33
- EventType.RUN_COMPLETED,
34
- EventType.RUN_FAILED,
35
- EventType.RUN_CANCELED,
55
+ "run.completed",
56
+ "run.failed",
57
+ "run.canceled",
36
58
  }
37
59
  )
38
60
 
39
61
  _RUN_STATUS_BY_EVENT = {
40
- EventType.RUN_STARTED: "in_progress",
41
- EventType.RUN_INTERRUPTED: "interrupted",
42
- EventType.RUN_COMPLETED: "completed",
43
- EventType.RUN_FAILED: "failed",
44
- EventType.RUN_CANCELED: "cancelled",
62
+ "run.started": "in_progress",
63
+ "run.interrupted": "interrupted",
64
+ "run.completed": "completed",
65
+ "run.failed": "failed",
66
+ "run.canceled": "cancelled",
45
67
  }
46
68
 
47
69
 
@@ -67,9 +89,11 @@ async def iter_runtime_conversation_events(
67
89
  session_service_provider: Callable[[], Any] | None = None,
68
90
  run_mode: str = RUN_MODE_FOREGROUND,
69
91
  runtime_preparation: RuntimeStartPreparation | None = None,
92
+ _execution_context: dict[str, str] | None = None,
70
93
  ) -> AsyncIterator[RuntimeEvent]:
71
94
  """Prepare once, execute through RuntimeExecutor, and persist RuntimeEvents."""
72
95
 
96
+ turn_started_monotonic = time.monotonic()
73
97
  provider = session_service_provider or resolve_session_service
74
98
  compaction_preview = await preview_auto_compaction(
75
99
  agent_id=agent_id,
@@ -96,7 +120,10 @@ async def iter_runtime_conversation_events(
96
120
  invocation_id=invocation_id,
97
121
  session_service_provider=provider,
98
122
  run_mode=run_mode,
123
+ runtime_type=launch_context.runtime_type,
99
124
  )
125
+ if _execution_context is not None:
126
+ _execution_context["session_id"] = prepared.session_id
100
127
  canonical_messages = prepared.responses_history or [dict(item) for item in messages]
101
128
  conversation_request = {
102
129
  "messages": canonical_messages,
@@ -110,16 +137,25 @@ async def iter_runtime_conversation_events(
110
137
  "response_id": response_id,
111
138
  "prepared_turn": asdict(prepared),
112
139
  }
113
- request = StartRequest(
114
- input=prepared.user_input,
115
- user_id=user_id,
140
+ native_session_metadata = await _session_native_metadata(
141
+ runtime_type=launch_context.runtime_type,
116
142
  session_id=prepared.session_id,
117
- agent_id=agent_id,
118
- model=model,
119
- metadata={
120
- "invocation_id": prepared.invocation_id,
121
- CONVERSATION_PREPROCESSING_METADATA_KEY: conversation_request,
122
- },
143
+ session_service_provider=provider,
144
+ )
145
+ request = apply_runtime_start_request_defaults(
146
+ launch_context,
147
+ StartRequest(
148
+ input=prepared.user_input,
149
+ user_id=user_id,
150
+ session_id=prepared.session_id,
151
+ agent_id=agent_id,
152
+ model=model,
153
+ metadata={
154
+ "invocation_id": prepared.invocation_id,
155
+ CONVERSATION_PREPROCESSING_METADATA_KEY: conversation_request,
156
+ **native_session_metadata,
157
+ },
158
+ ),
123
159
  )
124
160
  checkpoint_resume = _checkpoint_resume_input(prepared.resume_input)
125
161
  if checkpoint_resume is None:
@@ -145,53 +181,66 @@ async def iter_runtime_conversation_events(
145
181
  }
146
182
  )
147
183
  store = RuntimeEventStore(provider())
184
+ pipeline = CanonicalEventPipeline(store, session_id=prepared.session_id)
148
185
  terminal = False
149
186
  interrupted = False
150
187
  completed_assistant_text = ""
188
+ usage: dict[str, int] | None = None
151
189
  try:
152
190
  for context_event in _compaction_runtime_events(
153
191
  prepared=prepared,
154
192
  preview=compaction_preview,
155
- agent_id=agent_id,
156
- user_id=user_id,
157
193
  ):
158
- yield await store.append_one(context_event)
194
+ for persisted in await pipeline.ingest(context_event):
195
+ yield persisted
159
196
  async for event in executor.stream(handle):
160
197
  _validate_event_scope(event, request)
161
- persisted = await store.append_one(event)
162
- await _project_runtime_run_status(
163
- persisted,
164
- run_mode=prepared.run_mode,
165
- run_trigger=prepared.run_trigger,
166
- session_service_provider=provider,
167
- )
168
- if (
169
- persisted.event_type == EventType.TEXT_COMPLETED
170
- and persisted.phase == "final_answer"
171
- ):
172
- completed_assistant_text = str(persisted.payload.get("text") or "")
173
- terminal = persisted.event_type in _TERMINAL_EVENTS
174
- interrupted = persisted.event_type == EventType.RUN_INTERRUPTED
175
- yield persisted
198
+ for persisted in await pipeline.ingest(event):
199
+ await _project_runtime_run_status(
200
+ persisted,
201
+ session_id=prepared.session_id,
202
+ author=agent_id,
203
+ run_mode=prepared.run_mode,
204
+ run_trigger=prepared.run_trigger,
205
+ session_service_provider=provider,
206
+ )
207
+ terminal = persisted.event_type in _TERMINAL_EVENTS
208
+ interrupted = persisted.event_type == "run.interrupted"
209
+ if isinstance(persisted, RunCompleted):
210
+ completed_assistant_text = _selected_output_text(
211
+ pipeline.reducer.snapshot(), persisted
212
+ )
213
+ elif isinstance(persisted, UsageReported):
214
+ usage = {
215
+ "input_tokens": persisted.input_tokens,
216
+ "output_tokens": persisted.output_tokens,
217
+ "total_tokens": persisted.total_tokens,
218
+ "cached_tokens": persisted.cached_tokens,
219
+ "reasoning_tokens": persisted.reasoning_tokens,
220
+ }
221
+ yield persisted
176
222
  if not terminal and not interrupted:
177
223
  raise RuntimeError("runtime stream ended without a terminal or interrupted event")
178
224
  except asyncio.CancelledError:
179
225
  cancel_result = await executor.cancel(handle)
180
- cancelled_event = RuntimeEvent.create(
181
- EventType.RUN_CANCELED,
182
- agent_id=str(request.agent_id or ""),
183
- user_id=request.user_id,
184
- session_id=request.session_id,
185
- invocation_id=str(request.metadata["invocation_id"]),
186
- seq_id=0,
187
- payload={
188
- "status": "cancelled",
189
- "cancel_result": cancel_result.value,
190
- },
226
+ cancelled_event = RunCanceled(
227
+ schema_version=2,
228
+ event_id=f"cancel:{handle.run_id}:{cancel_result.value}",
229
+ seq=0,
230
+ timestamp=time.time(),
231
+ run_id=handle.run_id,
232
+ scope_id=handle.run_id,
233
+ source=SourceRef(
234
+ framework="ksadk", metadata={"cancel_result": cancel_result.value}
235
+ ),
236
+ status="canceled",
237
+ reason=cancel_result.value,
191
238
  )
192
- persisted_cancelled = await store.append_one(cancelled_event)
239
+ persisted_cancelled = (await pipeline.ingest(cancelled_event))[-1]
193
240
  await _project_runtime_run_status(
194
241
  persisted_cancelled,
242
+ session_id=prepared.session_id,
243
+ author=agent_id,
195
244
  run_mode=prepared.run_mode,
196
245
  run_trigger=prepared.run_trigger,
197
246
  session_service_provider=provider,
@@ -210,58 +259,122 @@ async def iter_runtime_conversation_events(
210
259
  assistant_text=completed_assistant_text,
211
260
  model=model,
212
261
  )
262
+ if terminal:
263
+ _record_canonical_baseline_turn(
264
+ prepared=prepared,
265
+ model=model,
266
+ usage=usage,
267
+ turn_started_monotonic=turn_started_monotonic,
268
+ )
213
269
  if terminal:
214
270
  await executor.close(handle)
215
271
 
216
272
 
273
+ async def _session_native_metadata(
274
+ *,
275
+ runtime_type: str,
276
+ session_id: str,
277
+ session_service_provider: Callable[[], Any],
278
+ ) -> dict[str, str]:
279
+ """Resolve a provider-native continuation from the canonical Session log.
280
+
281
+ The HTTP conversation path creates a fresh adapter transport for every
282
+ terminal turn. Codex therefore needs the prior native thread id on the
283
+ next ``StartRequest``; otherwise one AgentEngine Session becomes unrelated
284
+ one-turn Codex threads.
285
+ """
286
+
287
+ if str(runtime_type or "").strip().lower() != "codex":
288
+ return {}
289
+ events = await RuntimeEventStore(session_service_provider()).list(
290
+ session_id,
291
+ limit=512,
292
+ )
293
+ for event in reversed(events):
294
+ if not isinstance(event, (ContinuationCreated, ContinuationResumed)):
295
+ continue
296
+ if event.continuation_kind != "thread_resume":
297
+ continue
298
+ ref = getattr(event, "ref", None)
299
+ thread_id = (
300
+ str(ref.get("thread_id") or "").strip()
301
+ if isinstance(ref, Mapping)
302
+ else ""
303
+ )
304
+ if not thread_id:
305
+ thread_id = str(event.source.metadata.get("thread_id") or "").strip()
306
+ if thread_id:
307
+ return {"thread_id": thread_id}
308
+ return {}
309
+
310
+
217
311
  def _compaction_runtime_events(
218
312
  *,
219
313
  prepared: Any,
220
314
  preview: Any,
221
- agent_id: str,
222
- user_id: str,
223
315
  ) -> list[RuntimeEvent]:
224
316
  if not prepared.compaction_triggered:
225
317
  return []
226
318
  trigger = str(prepared.compaction_trigger or "auto")
227
- scope = {
228
- "agent_id": agent_id,
229
- "user_id": user_id,
230
- "session_id": prepared.session_id,
231
- "invocation_id": prepared.invocation_id,
232
- }
233
- preview_payload = {
234
- "phase": "start",
319
+ source = SourceRef(
320
+ framework="ksadk",
321
+ metadata={
322
+ "total_chars": preview.total_chars,
323
+ "total_estimated_tokens": preview.total_estimated_tokens,
324
+ "group_count": preview.group_count,
325
+ "threshold_percentage": preview.auto_compact_threshold_percentage,
326
+ },
327
+ )
328
+ common = {
329
+ "schema_version": 2,
330
+ "seq": 0,
331
+ "timestamp": time.time(),
332
+ "run_id": prepared.invocation_id,
333
+ "scope_id": prepared.invocation_id,
334
+ "source": source,
235
335
  "trigger": trigger,
236
- "total_chars": preview.total_chars,
237
- "total_estimated_tokens": preview.total_estimated_tokens,
238
- "group_count": preview.group_count,
239
- "threshold_percentage": preview.auto_compact_threshold_percentage,
240
- }
241
- completed_payload = {
242
- **preview_payload,
243
- "phase": "done",
244
- "compacted_until_seq_id": int(prepared.compacted_until_seq_id or 0),
245
336
  }
246
337
  return [
247
- RuntimeEvent.create(
248
- EventType.CONTEXT_COMPACTION_STARTED,
249
- seq_id=0,
250
- payload=preview_payload,
251
- **scope,
338
+ ContextCompactionStarted(
339
+ event_id=f"compaction-start:{prepared.invocation_id}",
340
+ **common,
252
341
  ),
253
- RuntimeEvent.create(
254
- EventType.CONTEXT_COMPACTION_COMPLETED,
255
- seq_id=0,
256
- payload=completed_payload,
257
- **scope,
342
+ ContextCompactionCompleted(
343
+ event_id=f"compaction-completed:{prepared.invocation_id}",
344
+ compacted_until_seq=int(prepared.compacted_until_seq_id or 0),
345
+ **common,
258
346
  ),
259
347
  ]
260
348
 
261
349
 
350
+ def _record_canonical_baseline_turn(
351
+ *,
352
+ prepared: Any,
353
+ model: str | None,
354
+ usage: Mapping[str, int] | None,
355
+ turn_started_monotonic: float,
356
+ ) -> None:
357
+ """Keep v2 execution on the same env-gated measurement path as legacy runs."""
358
+
359
+ from ksadk.context_engine.baseline import record_baseline_turn
360
+
361
+ record_baseline_turn(
362
+ getattr(prepared, "shadow_context_plan", None),
363
+ session_id=prepared.session_id,
364
+ invocation_id=prepared.invocation_id,
365
+ model=str(model or ""),
366
+ usage=usage,
367
+ compaction_triggered=bool(getattr(prepared, "compaction_triggered", False)),
368
+ compaction_trigger=str(getattr(prepared, "compaction_trigger", "") or ""),
369
+ turn_latency_ms=int((time.monotonic() - turn_started_monotonic) * 1000),
370
+ )
371
+
372
+
262
373
  async def _project_runtime_run_status(
263
374
  event: RuntimeEvent,
264
375
  *,
376
+ session_id: str,
377
+ author: str,
265
378
  run_mode: str,
266
379
  run_trigger: str,
267
380
  session_service_provider: Callable[[], Any],
@@ -271,12 +384,12 @@ async def _project_runtime_run_status(
271
384
  status = _RUN_STATUS_BY_EVENT.get(event.event_type)
272
385
  if status is None:
273
386
  return
274
- detail = event.payload.get("error") or event.payload.get("detail")
387
+ detail = event.error.message if isinstance(event, RunFailed) else None
275
388
  await append_run_status_event(
276
- session_id=event.session_id,
277
- author=event.agent_id,
389
+ session_id=session_id,
390
+ author=author,
278
391
  status=status,
279
- invocation_id=event.invocation_id,
392
+ invocation_id=event.run_id,
280
393
  detail=str(detail) if detail else None,
281
394
  metadata={
282
395
  "runtime_event_id": event.event_id,
@@ -367,19 +480,12 @@ def _persisted_resume_native_ref(resume_input: Mapping[str, Any]) -> dict[str, A
367
480
 
368
481
 
369
482
  def _validate_event_scope(event: RuntimeEvent, request: StartRequest) -> None:
370
- expected = {
371
- "agent_id": str(request.agent_id or ""),
372
- "user_id": request.user_id,
373
- "session_id": request.session_id,
374
- "invocation_id": str(request.metadata["invocation_id"]),
375
- }
376
- mismatches = {
377
- field: (expected_value, getattr(event, field))
378
- for field, expected_value in expected.items()
379
- if getattr(event, field) != expected_value
380
- }
381
- if mismatches:
382
- raise ValueError(f"runtime event scope does not match request: {mismatches!r}")
483
+ expected_run_id = str(request.metadata["invocation_id"])
484
+ if event.schema_version != 2 or event.run_id != expected_run_id:
485
+ raise ValueError(
486
+ "runtime event scope does not match request: "
487
+ f"expected run_id={expected_run_id!r}, got {event.run_id!r}"
488
+ )
383
489
 
384
490
 
385
491
  async def iter_runtime_conversation_semantic_events(
@@ -387,104 +493,102 @@ async def iter_runtime_conversation_semantic_events(
387
493
  ) -> AsyncIterator[dict[str, Any]]:
388
494
  """Project canonical RuntimeEvents into the transport-neutral serializer input."""
389
495
 
390
- accumulated_text = ""
391
- usage: dict[str, Any] = {}
496
+ reducer = StreamReducer()
392
497
  approval: dict[str, Any] | None = None
393
- async for event in iter_runtime_conversation_events(**kwargs):
394
- payload = event.payload
395
- event_type = event.event_type
396
- if event_type == EventType.RUN_STARTED:
498
+ execution_context: dict[str, str] = {}
499
+ async for event in iter_runtime_conversation_events(
500
+ **kwargs, _execution_context=execution_context
501
+ ):
502
+ patch = reducer.apply(event)
503
+ if not patch.applied:
504
+ continue
505
+ projection = reducer.snapshot()
506
+ if isinstance(event, RunStarted):
397
507
  yield {
398
508
  "type": "started",
399
- "session_id": event.session_id,
400
- "metadata": dict(payload.get("metadata") or {}),
509
+ "session_id": execution_context.get("session_id", ""),
510
+ "metadata": dict(event.source.metadata),
401
511
  }
402
- elif event_type in {
403
- EventType.CONTEXT_COMPACTION_STARTED,
404
- EventType.CONTEXT_COMPACTION_COMPLETED,
405
- }:
406
- yield {
407
- "type": "compaction",
408
- **dict(payload),
512
+ elif isinstance(event, (ContextCompactionStarted, ContextCompactionCompleted)):
513
+ semantic = {"type": "compaction", "trigger": event.trigger}
514
+ # Distinguish start vs done for SSE projection (response.compaction.start/done)
515
+ if isinstance(event, ContextCompactionStarted):
516
+ semantic["phase"] = "start"
517
+ else:
518
+ semantic["phase"] = "done"
519
+ semantic["compacted_until_seq_id"] = event.compacted_until_seq
520
+ yield semantic
521
+ elif isinstance(event, ItemUpdated) and isinstance(event.update, TextContent):
522
+ item = next(
523
+ candidate
524
+ for candidate in projection.items
525
+ if candidate.scope_id == event.scope_id and candidate.item_id == event.item_id
526
+ )
527
+ semantic_type = (
528
+ "thinking"
529
+ if item.item_kind == "reasoning" or item.phase == "commentary"
530
+ else "text"
531
+ )
532
+ semantic: dict[str, Any] = {
533
+ "type": semantic_type,
534
+ "delta": event.update.text,
535
+ "scope_id": event.scope_id,
536
+ "item_id": event.item_id,
537
+ "part_id": event.update.part_id,
538
+ "operation": event.op,
409
539
  }
410
- elif event_type == EventType.TEXT_DELTA:
411
- delta = str(payload.get("text") or "")
412
- replace = bool(payload.get("replace"))
413
- accumulated_text = delta if replace else accumulated_text + delta
414
- semantic: dict[str, Any] = {"type": "text", "delta": delta}
415
- if replace:
540
+ if event.op == "replace":
416
541
  semantic["replace"] = True
417
542
  yield semantic
418
- elif event_type == EventType.TEXT_COMPLETED:
419
- snapshot = str(payload.get("text") or "")
420
- if snapshot != accumulated_text:
421
- if snapshot.startswith(accumulated_text):
422
- delta = snapshot[len(accumulated_text) :]
423
- if delta:
424
- yield {"type": "text", "delta": delta}
425
- else:
426
- yield {"type": "text", "delta": snapshot, "replace": True}
427
- accumulated_text = snapshot
428
- elif event_type == EventType.REASONING_DELTA:
429
- yield {"type": "thinking", "delta": str(payload.get("text") or "")}
430
- elif event_type == EventType.TOOL_CALL_BEGIN:
431
- yield {
432
- "type": "tool_call",
433
- "name": payload.get("name"),
434
- "args": dict(payload.get("args") or {}),
435
- "run_id": payload.get("call_id"),
436
- "stage": payload.get("stage"),
437
- "event_kind": payload.get("event_kind"),
438
- "display_title": payload.get("display_title"),
439
- "display_summary": payload.get("display_summary"),
440
- }
441
- elif event_type == EventType.TOOL_CALL_END:
442
- yield {
443
- "type": "tool_result",
444
- "name": payload.get("name"),
445
- "output": payload.get("result", payload.get("error", "")),
446
- "run_id": payload.get("call_id"),
447
- }
448
- elif event_type == EventType.APPROVAL_REQUESTED:
449
- detail = payload.get("detail")
450
- approval = dict(detail) if isinstance(detail, Mapping) else {}
451
- approval.setdefault("approval_request_id", payload.get("approval_id"))
452
- approval.setdefault("id", payload.get("approval_id"))
453
- approval.setdefault("call_id", payload.get("call_id"))
454
- # ``kind=tool`` only describes the interrupt category. It is not
455
- # a concrete tool name: inventing one would serialize a generic
456
- # interrupt as an MCP approval request and lose the extension
457
- # event that clients use to render a human-input prompt.
458
- if payload.get("tool_name"):
459
- approval.setdefault("tool_name", payload.get("tool_name"))
460
- elif event_type == EventType.USAGE_REPORTED:
461
- usage = dict(payload)
462
- elif event_type == EventType.RUN_INTERRUPTED:
543
+ elif isinstance(event, ItemStarted) and event.initial is not None:
544
+ for part in event.initial.parts:
545
+ if isinstance(part, ToolCallContent):
546
+ yield _tool_call_semantic(part)
547
+ elif isinstance(event, ItemCompleted):
548
+ for part in event.snapshot.parts:
549
+ if isinstance(part, ToolCallContent):
550
+ yield _tool_call_semantic(part)
551
+ elif isinstance(part, ToolResultContent):
552
+ yield {
553
+ "type": "tool_result",
554
+ "name": "",
555
+ "output": part.result,
556
+ "run_id": part.call_id,
557
+ }
558
+ elif isinstance(event, InteractionRequested):
559
+ if event.interaction_kind == "approval" and event.request.request_type == "approval":
560
+ detail = event.request.detail
561
+ approval = dict(detail) if isinstance(detail, Mapping) else {}
562
+ approval.setdefault("approval_request_id", event.interaction_id)
563
+ approval.setdefault("id", event.interaction_id)
564
+ approval.setdefault("call_id", event.request.call_id)
565
+ approval.setdefault("kind", event.request.kind)
566
+ elif isinstance(event, RunInterrupted):
463
567
  yield {
464
568
  "type": "interrupt",
465
- "interrupt_info": approval or dict(payload),
466
- "session_id": event.session_id,
569
+ "interrupt_info": approval
570
+ or {
571
+ "reason": event.reason,
572
+ "interaction_id": event.interaction_id,
573
+ "continuation_id": event.continuation_id,
574
+ },
575
+ "session_id": execution_context.get("session_id", ""),
467
576
  }
468
- elif event_type == EventType.RUN_FAILED:
577
+ elif isinstance(event, RunFailed):
469
578
  yield {
470
579
  "type": "error",
471
- "message": str(payload.get("error") or "Agent 运行失败"),
472
- "session_id": event.session_id,
473
- "usage": usage,
580
+ "message": event.error.message or "Agent 运行失败",
581
+ "session_id": execution_context.get("session_id", ""),
582
+ "usage": projection.usage.model_dump(),
474
583
  }
475
- elif event_type == EventType.RUN_CANCELED:
584
+ elif isinstance(event, RunCanceled):
476
585
  yield {
477
586
  "type": "cancelled",
478
- "session_id": event.session_id,
479
- "usage": usage,
587
+ "session_id": execution_context.get("session_id", ""),
588
+ "usage": projection.usage.model_dump(),
480
589
  }
481
- elif event_type == EventType.RUN_COMPLETED:
482
- raw_completion_metadata = payload.get("metadata")
483
- completion_metadata = (
484
- dict(raw_completion_metadata)
485
- if isinstance(raw_completion_metadata, Mapping)
486
- else {}
487
- )
590
+ elif isinstance(event, RunCompleted):
591
+ completion_metadata = dict(event.source.metadata)
488
592
  request_metadata = kwargs.get("request_metadata")
489
593
  requested_agentengine = (
490
594
  request_metadata.get("agentengine")
@@ -493,21 +597,51 @@ async def iter_runtime_conversation_semantic_events(
493
597
  )
494
598
  if isinstance(requested_agentengine, Mapping):
495
599
  completion_metadata["agentengine"] = dict(requested_agentengine)
496
- if isinstance(payload.get("agentengine"), Mapping):
497
- completion_metadata["agentengine"] = dict(payload["agentengine"])
498
600
  completion_metadata["runtime"] = {
499
- "duration_ms": payload.get("duration_ms"),
601
+ "duration_ms": event.source.metadata.get("duration_ms"),
500
602
  "runtime_type": kwargs["launch_context"].runtime_type,
501
603
  }
502
604
  yield {
503
605
  "type": "completed",
504
- "output_text": accumulated_text,
505
- "session_id": event.session_id,
506
- "usage": usage,
606
+ "output_text": _selected_output_text(projection, event),
607
+ "session_id": execution_context.get("session_id", ""),
608
+ "usage": projection.usage.model_dump(),
507
609
  "metadata": completion_metadata,
508
610
  }
509
611
 
510
612
 
613
+ def _tool_call_semantic(part: ToolCallContent) -> dict[str, Any]:
614
+ return {
615
+ "type": "tool_call",
616
+ "name": part.name,
617
+ "args": part.arguments if isinstance(part.arguments, dict) else {},
618
+ "run_id": part.call_id,
619
+ }
620
+
621
+
622
+ def _selected_output_text(projection: RunProjection, completed: RunCompleted) -> str:
623
+ """Resolve final text exclusively through authoritative run output refs."""
624
+
625
+ chunks: list[str] = []
626
+ for ref in completed.output_refs:
627
+ item = next(
628
+ (
629
+ candidate
630
+ for candidate in projection.items
631
+ if candidate.scope_id == ref.scope_id and candidate.item_id == ref.item_id
632
+ ),
633
+ None,
634
+ )
635
+ if item is None:
636
+ continue
637
+ for part in item.parts:
638
+ if isinstance(part, TextContent) and (
639
+ ref.part_id is None or ref.part_id == part.part_id
640
+ ):
641
+ chunks.append(part.text)
642
+ return "".join(chunks)
643
+
644
+
511
645
  async def invoke_runtime_conversation_once(
512
646
  **kwargs: Any,
513
647
  ) -> tuple[str, dict[str, Any]]: