agentengine-sdk-python 0.8.0__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 (494) hide show
  1. {agentengine_sdk_python-0.8.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/METADATA +43 -7
  2. agentengine_sdk_python-0.8.2.dist-info/RECORD +778 -0
  3. {agentengine_sdk_python-0.8.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/WHEEL +1 -1
  4. ksadk/a2a/__init__.py +2 -0
  5. ksadk/a2a/_space_client_events.py +381 -0
  6. ksadk/a2a/bootstrap.py +0 -2
  7. ksadk/a2a/card.py +6 -111
  8. ksadk/a2a/control_plane.py +239 -1
  9. ksadk/a2a/event_adapter.py +156 -64
  10. ksadk/a2a/executor.py +195 -172
  11. ksadk/a2a/routes.py +12 -5
  12. ksadk/a2a/server.py +1 -8
  13. ksadk/a2a/service_env.py +33 -0
  14. ksadk/a2a/space_client.py +43 -349
  15. ksadk/a2a_card.py +101 -0
  16. ksadk/a2ui/core.py +222 -53
  17. ksadk/agui/_agent_helpers.py +243 -0
  18. ksadk/agui/a2ui_projection.py +12 -5
  19. ksadk/agui/agent.py +474 -275
  20. ksadk/agui/config.py +11 -5
  21. ksadk/agui/routes.py +7 -15
  22. ksadk/api/client.py +530 -40
  23. ksadk/api/environment.py +27 -0
  24. ksadk/builders/code_builder.py +352 -53
  25. ksadk/builders/container_builder.py +71 -44
  26. ksadk/builders/framework_requirements.py +2 -1
  27. ksadk/builders/ks3_uploader.py +2 -2
  28. ksadk/builders/managed_runtime_builder.py +60 -28
  29. ksadk/cli/__init__.py +25 -0
  30. ksadk/cli/cmd_a2a.py +18 -31
  31. ksadk/cli/cmd_create.py +13 -26
  32. ksadk/cli/cmd_dashboard.py +15 -1
  33. ksadk/cli/cmd_deploy.py +28 -3
  34. ksadk/cli/cmd_eval.py +443 -0
  35. ksadk/cli/cmd_evalset.py +284 -0
  36. ksadk/cli/cmd_files.py +5 -1
  37. ksadk/cli/cmd_hermes.py +137 -163
  38. ksadk/cli/cmd_invoke.py +28 -38
  39. ksadk/cli/cmd_launch.py +12 -0
  40. ksadk/cli/cmd_managed_runtime.py +95 -0
  41. ksadk/cli/cmd_observe.py +85 -0
  42. ksadk/cli/cmd_openclaw.py +85 -479
  43. ksadk/cli/cmd_replay.py +28 -4
  44. ksadk/cli/cmd_run.py +29 -67
  45. ksadk/cli/cmd_studio.py +201 -0
  46. ksadk/cli/cmd_web.py +15 -6
  47. ksadk/cli/dry_run.py +2 -1
  48. ksadk/cli/env_options.py +83 -0
  49. ksadk/cli/global_options.py +3 -1
  50. ksadk/cli/hermes_env.py +151 -0
  51. ksadk/cli/invoke_payload.py +49 -0
  52. ksadk/cli/network_options.py +7 -5
  53. ksadk/cli/openclaw_env.py +458 -0
  54. ksadk/cli/runtime_bootstrap.py +51 -0
  55. ksadk/cli/ui.py +6 -0
  56. ksadk/cli/workflow_common.py +5 -5
  57. ksadk/codex/__init__.py +3 -3
  58. ksadk/codex/client.py +833 -49
  59. ksadk/codex/phase.py +1 -1
  60. ksadk/codex/runtime.py +720 -127
  61. ksadk/common/kop_client.py +232 -0
  62. ksadk/configs/__init__.py +1 -3
  63. ksadk/configs/env_registry.py +244 -45
  64. ksadk/configs/env_registry_pcm.py +181 -0
  65. ksadk/configs/env_var_spec.py +18 -0
  66. ksadk/configs/global_config.py +6 -1
  67. ksadk/configs/settings.py +5 -108
  68. ksadk/context_engine/__init__.py +98 -0
  69. ksadk/context_engine/assembler.py +176 -0
  70. ksadk/context_engine/baseline.py +419 -0
  71. ksadk/context_engine/cache_observability.py +228 -0
  72. ksadk/context_engine/capabilities.py +443 -0
  73. ksadk/context_engine/contributors.py +344 -0
  74. ksadk/context_engine/hosted_pipeline.py +417 -0
  75. ksadk/context_engine/models.py +117 -0
  76. ksadk/context_engine/planner.py +698 -0
  77. ksadk/context_engine/policies.py +319 -0
  78. ksadk/context_engine/projection.py +31 -0
  79. ksadk/context_engine/shadow_plan.py +266 -0
  80. ksadk/context_engine/tokenizer.py +164 -0
  81. ksadk/conversations/__init__.py +85 -94
  82. ksadk/conversations/context.py +126 -6
  83. ksadk/conversations/message_projection.py +292 -28
  84. ksadk/conversations/model_context.py +49 -3
  85. ksadk/conversations/runtime_compaction.py +207 -5
  86. ksadk/conversations/runtime_input.py +193 -3
  87. ksadk/conversations/runtime_invocation.py +81 -3
  88. ksadk/conversations/runtime_observability.py +157 -4
  89. ksadk/conversations/runtime_payloads.py +42 -0
  90. ksadk/conversations/runtime_preparation.py +280 -2
  91. ksadk/conversations/runtime_resume.py +71 -32
  92. ksadk/conversations/runtime_stream_events.py +94 -9
  93. ksadk/conversations/runtime_streaming.py +175 -22
  94. ksadk/conversations/semantic_summary.py +311 -1
  95. ksadk/conversations/session_lock.py +51 -0
  96. ksadk/deployment/env_forward.py +72 -0
  97. ksadk/deployment/managed_runtime.py +38 -0
  98. ksadk/deployment/manager.py +24 -8
  99. ksadk/deployment/providers/serverless.py +228 -92
  100. ksadk/evaluation/__init__.py +116 -0
  101. ksadk/evaluation/a2a_adapter.py +452 -0
  102. ksadk/evaluation/adapters.py +67 -0
  103. ksadk/evaluation/agent_eval_client.py +395 -0
  104. ksadk/evaluation/cloud_binding.py +80 -0
  105. ksadk/evaluation/cloud_converter.py +194 -0
  106. ksadk/evaluation/cloud_service.py +199 -0
  107. ksadk/evaluation/contracts.py +478 -0
  108. ksadk/evaluation/evalset.py +351 -0
  109. ksadk/evaluation/evaluators.py +627 -0
  110. ksadk/evaluation/evidence.py +258 -0
  111. ksadk/evaluation/executor.py +143 -0
  112. ksadk/evaluation/local_adapter.py +550 -0
  113. ksadk/evaluation/service_env.py +27 -0
  114. ksadk/evaluation/storage.py +68 -0
  115. ksadk/evaluation/studio_build_adapter.py +253 -0
  116. ksadk/evaluation/target.py +82 -0
  117. ksadk/events/__init__.py +13 -13
  118. ksadk/events/_v1_compat/__init__.py +1 -0
  119. ksadk/events/_v1_compat/models.py +299 -0
  120. ksadk/events/_v1_compat/parser.py +247 -0
  121. ksadk/events/_v1_compat/projection.py +753 -0
  122. ksadk/events/adapters/__init__.py +34 -0
  123. ksadk/events/adapters/_a2a_snapshot.py +622 -0
  124. ksadk/events/adapters/_a2a_support.py +275 -0
  125. ksadk/events/adapters/_codex_interactions.py +375 -0
  126. ksadk/events/adapters/_codex_items.py +801 -0
  127. ksadk/events/adapters/_codex_validators.py +311 -0
  128. ksadk/events/adapters/_langgraph_support.py +785 -0
  129. ksadk/events/adapters/a2a.py +841 -0
  130. ksadk/events/adapters/adk.py +503 -0
  131. ksadk/events/adapters/codex.py +717 -0
  132. ksadk/events/adapters/langgraph.py +745 -0
  133. ksadk/events/canonical.py +440 -0
  134. ksadk/events/canonical_replay.py +497 -0
  135. ksadk/events/canonical_store.py +468 -0
  136. ksadk/events/cold_recovery.py +257 -0
  137. ksadk/events/content.py +89 -0
  138. ksadk/events/identity.py +86 -0
  139. ksadk/events/pipeline.py +455 -0
  140. ksadk/events/projections.py +66 -0
  141. ksadk/events/reducer.py +661 -0
  142. ksadk/events/replay.py +3 -36
  143. ksadk/events/runtime_event.py +20 -256
  144. ksadk/events/session_event.py +324 -0
  145. ksadk/events/store.py +3 -316
  146. ksadk/events/v1_compat.py +41 -0
  147. ksadk/harness/__init__.py +3 -2
  148. ksadk/harness/app.py +114 -123
  149. ksadk/harness/config.py +1 -1
  150. ksadk/harness/runtime.py +467 -0
  151. ksadk/hermes_terminal.py +5 -0
  152. ksadk/identity/resolver.py +4 -3
  153. ksadk/interaction/__init__.py +28 -0
  154. ksadk/interaction/contracts.py +136 -0
  155. ksadk/interaction/ledger.py +189 -0
  156. ksadk/interaction/provider.py +122 -0
  157. ksadk/interaction/providers/__init__.py +52 -0
  158. ksadk/interaction/providers/adk.py +40 -0
  159. ksadk/interaction/providers/codex.py +94 -0
  160. ksadk/interaction/providers/langgraph.py +58 -0
  161. ksadk/kernel/__init__.py +117 -0
  162. ksadk/kernel/authorization.py +258 -0
  163. ksadk/kernel/bootstrap.py +1074 -0
  164. ksadk/kernel/contract_fingerprints.py +61 -0
  165. ksadk/kernel/contracts.py +362 -0
  166. ksadk/kernel/control.py +219 -0
  167. ksadk/kernel/errors.py +79 -0
  168. ksadk/kernel/ingress.py +1102 -0
  169. ksadk/kernel/mapping.py +111 -0
  170. ksadk/kernel/memory_store.py +1133 -0
  171. ksadk/kernel/postgres_store.py +1756 -0
  172. ksadk/kernel/recovery.py +452 -0
  173. ksadk/kernel/runtime_identity.py +103 -0
  174. ksadk/kernel/sql/001_agent_kernel.sql +120 -0
  175. ksadk/kernel/sqlite_store.py +1410 -0
  176. ksadk/kernel/state.py +145 -0
  177. ksadk/kernel/store.py +232 -0
  178. ksadk/kernel/worker.py +953 -0
  179. ksadk/knowledge_base/client.py +22 -4
  180. ksadk/knowledge_base/service.py +32 -5
  181. ksadk/managed_a2a_card.py +160 -0
  182. ksadk/managed_runtime.py +16 -9
  183. ksadk/memory/__init__.py +61 -0
  184. ksadk/memory/adk/backends/base_ltm_backend.py +96 -1
  185. ksadk/memory/adk/backends/http_ltm_backend.py +14 -5
  186. ksadk/memory/adk/backends/inmemory_ltm_backend.py +136 -3
  187. ksadk/memory/adk/backends/sdk_ltm_backend.py +394 -5
  188. ksadk/memory/adk/backends/sqlite_ltm_backend.py +95 -0
  189. ksadk/memory/adk/long_term_memory.py +3 -2
  190. ksadk/memory/coordinator.py +461 -0
  191. ksadk/memory/events.py +202 -0
  192. ksadk/memory/extraction.py +228 -0
  193. ksadk/memory/ltm_backend_factory.py +16 -3
  194. ksadk/memory/models.py +316 -0
  195. ksadk/memory/policy.py +215 -0
  196. ksadk/memory/provider.py +47 -0
  197. ksadk/memory/provider_adapter.py +159 -0
  198. ksadk/memory/provider_resolver.py +71 -0
  199. ksadk/memory/providers/__init__.py +5 -0
  200. ksadk/memory/providers/local_sqlite.py +490 -0
  201. ksadk/memory/resolved_policy.py +145 -0
  202. ksadk/memory/service.py +198 -8
  203. ksadk/memory/tool.py +4 -0
  204. ksadk/model_proxy/bootstrap.py +16 -9
  205. ksadk/model_proxy/config.py +22 -1
  206. ksadk/model_proxy/detect.py +202 -9
  207. ksadk/model_proxy/namespace.py +67 -15
  208. ksadk/model_proxy/server.py +168 -6
  209. ksadk/model_proxy/transform.py +105 -3
  210. ksadk/observability/__init__.py +25 -0
  211. ksadk/observability/session_log.py +420 -0
  212. ksadk/observability/trajectory.py +105 -0
  213. ksadk/prompts/__init__.py +71 -0
  214. ksadk/prompts/compiler.py +215 -0
  215. ksadk/prompts/models.py +82 -0
  216. ksadk/prompts/projection.py +89 -0
  217. ksadk/prompts/resolved.py +137 -0
  218. ksadk/prompts/sources.py +233 -0
  219. ksadk/runners/_langgraph_runner_streams.py +822 -0
  220. ksadk/runners/adk_runner.py +14 -31
  221. ksadk/runners/base_runner.py +44 -3
  222. ksadk/runners/factory.py +3 -3
  223. ksadk/runners/langgraph_runner.py +252 -433
  224. ksadk/runners/utils/__init__.py +0 -10
  225. ksadk/runners/utils/loader.py +16 -0
  226. ksadk/runtime/__init__.py +67 -41
  227. ksadk/runtime/_runner_adapter/__init__.py +1 -0
  228. ksadk/runtime/_runner_adapter/stream_mapping.py +788 -0
  229. ksadk/runtime/adapter.py +199 -16
  230. ksadk/runtime/conversation_execution.py +687 -0
  231. ksadk/runtime/executor.py +392 -0
  232. ksadk/runtime/factory.py +342 -0
  233. ksadk/runtime/framework_adapters.py +6 -12
  234. ksadk/runtime/hosted_finalizer.py +268 -0
  235. ksadk/runtime/launch.py +61 -0
  236. ksadk/runtime/preprocessing.py +49 -14
  237. ksadk/runtime/runner_adapter.py +330 -391
  238. ksadk/runtime/runner_loading.py +36 -0
  239. ksadk/runtime/usage.py +33 -0
  240. ksadk/sandbox/backends/e2b.py +36 -3
  241. ksadk/server/__init__.py +39 -4
  242. ksadk/server/app.py +18 -492
  243. ksadk/server/composition.py +36 -2
  244. ksadk/server/factory.py +210 -149
  245. ksadk/server/routes/common.py +15 -46
  246. ksadk/server/routes/control.py +13 -9
  247. ksadk/server/routes/kernel_ingress.py +258 -0
  248. ksadk/server/routes/misc.py +10 -33
  249. ksadk/server/routes/models.py +14 -6
  250. ksadk/server/routes/openai_compat.py +129 -27
  251. ksadk/server/routes/projection.py +84 -16
  252. ksadk/server/routes/run.py +347 -460
  253. ksadk/server/routes/sessions.py +37 -40
  254. ksadk/server/routes/streaming.py +52 -7
  255. ksadk/server/routes/workspace.py +54 -21
  256. ksadk/server/static/assets/{ArtifactsPanel-Cjnqt-8W.js → ArtifactsPanel-DSU1sWD_.js} +1 -1
  257. ksadk/server/static/assets/{CodeBlock-BqyqZfuB.js → CodeBlock-DOH6MVcn.js} +4 -4
  258. ksadk/server/static/assets/{MathMessageMarkdown-BpH7jiFM.js → MathMessageMarkdown-BL8my1R2.js} +4 -4
  259. ksadk/server/static/assets/MathMessageMarkdown-BorAY7qD.css +1 -0
  260. ksadk/server/static/assets/MermaidBlock-Dz4IP-Tx.js +312 -0
  261. ksadk/server/static/assets/NativeTerminalPanel-DUrK0JpZ.js +1 -0
  262. ksadk/server/static/assets/abnfDiagram-VCTEODGH-g20pFzNV.js +1 -0
  263. ksadk/server/static/assets/arc-C4FzinUA.js +1 -0
  264. ksadk/server/static/assets/architecture-7GRP2DOG-DjKratdf.js +1 -0
  265. ksadk/server/static/assets/architectureDiagram-5GKGNRK7-DpIqL5h4.js +36 -0
  266. ksadk/server/static/assets/blockDiagram-NRAW4CY4-BjkljTNz.js +129 -0
  267. ksadk/server/static/assets/c4Diagram-UCG6FXSJ-Dk_ieq2X.js +38 -0
  268. ksadk/server/static/assets/channel-4cQHKtx1.js +1 -0
  269. ksadk/server/static/assets/chunk-2Q5K7J3B-DmgWkESh.js +1 -0
  270. ksadk/server/static/assets/{chunk-FMBD7UC4-BGhvzDYt.js → chunk-5VM5RSS4-BVHAchFb.js} +1 -1
  271. ksadk/server/static/assets/{chunk-ND2GUHAM-D98vPd-E.js → chunk-F27PBJKO-C-ipQzuS.js} +1 -1
  272. ksadk/server/static/assets/chunk-G27WJ6UU-C2EyJbIK.js +231 -0
  273. ksadk/server/static/assets/{chunk-4BX2VUAB-CsWIQRhc.js → chunk-JWPE2WC7-vYvVJb_M.js} +1 -1
  274. ksadk/server/static/assets/chunk-LCL6LL3I-BcI6ysPT.js +206 -0
  275. ksadk/server/static/assets/chunk-POPQ4Y6H-C030x_Z1.js +1 -0
  276. ksadk/server/static/assets/chunk-RHFEMEQ7-yyGpsz4n.js +168 -0
  277. ksadk/server/static/assets/chunk-SVP7TREG-BLTlmMU7.js +88 -0
  278. ksadk/server/static/assets/chunk-XXDRQBXY-C_32ArgP.js +1 -0
  279. ksadk/server/static/assets/classDiagram-DTDB5LWJ-DLFd9Xi0.js +1 -0
  280. ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-DLFd9Xi0.js +1 -0
  281. ksadk/server/static/assets/{cose-bilkent-S5V4N54A-CX3yotHq.js → cose-bilkent-JH36ORCC-9YQYwdl0.js} +1 -1
  282. ksadk/server/static/assets/cynefin-OW5HDTMX-DjEM48Qp.js +1 -0
  283. ksadk/server/static/assets/cynefinDiagram-5FMLGOSQ-ErLF5N13.js +62 -0
  284. ksadk/server/static/assets/cytoscape.esm-CyCl8rPi.js +321 -0
  285. ksadk/server/static/assets/dagre-3AP2YEHR-DFiQF-6f.js +4 -0
  286. ksadk/server/static/assets/dagre-BuhGnRI1.js +1 -0
  287. ksadk/server/static/assets/diagram-S7CK7UJ4-Bt1v8-GC.js +30 -0
  288. ksadk/server/static/assets/diagram-UQ7AKVKN-DSCxJdBK.js +41 -0
  289. ksadk/server/static/assets/diagram-VSXAHHWV-DHfYwp_9.js +3 -0
  290. ksadk/server/static/assets/diagram-VX7I27RA-DdzD-4Le.js +24 -0
  291. ksadk/server/static/assets/diagram-Z3DM3KII-Du-nAJ9F.js +24 -0
  292. ksadk/server/static/assets/{dist-D82mtD2s.js → dist-8hqcx0sU.js} +1 -1
  293. ksadk/server/static/assets/dist-B7seoj3d.js +1 -0
  294. ksadk/server/static/assets/{dist-DHn6nBzr.js → dist-BE7bu-DL.js} +1 -1
  295. ksadk/server/static/assets/{dist-eoW6tZXA.js → dist-BVDffZ0U.js} +1 -1
  296. ksadk/server/static/assets/{dist-C2xjE7cO.js → dist-BX8z72IC.js} +1 -1
  297. ksadk/server/static/assets/{dist-CgF3fj15.js → dist-Bf2M8m3N.js} +1 -1
  298. ksadk/server/static/assets/{dist-Bs-jQcRX.js → dist-BjU6y-A2.js} +1 -1
  299. ksadk/server/static/assets/{dist-Djgl2wVZ.js → dist-BytlxIDT.js} +1 -1
  300. ksadk/server/static/assets/{dist-CVQRZjPu.js → dist-CSh_DE14.js} +1 -1
  301. ksadk/server/static/assets/{dist-6CVKuTAe.js → dist-CXYYBw3_.js} +1 -1
  302. ksadk/server/static/assets/{dist-DlzCRy0S.js → dist-C_wsv-Qd.js} +1 -1
  303. ksadk/server/static/assets/{dist-DF06ORQo.js → dist-ClxGviKw.js} +1 -1
  304. ksadk/server/static/assets/{dist-Cf23NY4L.js → dist-CttYUqzS.js} +1 -1
  305. ksadk/server/static/assets/{dist-ivOya1LD.js → dist-DNp6rLRA.js} +1 -1
  306. ksadk/server/static/assets/{dist-BibcG1V9.js → dist-DUX-id_F.js} +1 -1
  307. ksadk/server/static/assets/{dist-BUHRxvDG.js → dist-DmldrHd_.js} +1 -1
  308. ksadk/server/static/assets/{dist-BZ9n9AjO.js → dist-DnfXs8Vn.js} +2 -2
  309. ksadk/server/static/assets/{dist-DqNnNFrw.js → dist-Dq9gLD7L.js} +1 -1
  310. ksadk/server/static/assets/{dist-CGcp2ex8.js → dist-W-TIVntx.js} +1 -1
  311. ksadk/server/static/assets/{dist-Cwt7koer.js → dist-dDdADKFA.js} +1 -1
  312. ksadk/server/static/assets/{dist-C7-3jInC.js → dist-dydu68Fl.js} +1 -1
  313. ksadk/server/static/assets/{dist-C99THtIA.js → dist-ngtN0DJB.js} +1 -1
  314. ksadk/server/static/assets/ebnfDiagram-PWID7BFC-Da9C9NO1.js +1 -0
  315. ksadk/server/static/assets/erDiagram-SSCWMZ5O-EAGqqR79.js +99 -0
  316. ksadk/server/static/assets/eventmodeling-NTZA5JFV-CMgMaJrC.js +1 -0
  317. ksadk/server/static/assets/flowDiagram-A5DVABFB-BBKL0x3P.js +1 -0
  318. ksadk/server/static/assets/ganttDiagram-EL5Y4UJY-DqJsKb59.js +292 -0
  319. ksadk/server/static/assets/gitGraph-4MIJSDKK-Dw63mrhw.js +1 -0
  320. ksadk/server/static/assets/gitGraphDiagram-WWUBYQGX-B6g4dtDi.js +106 -0
  321. ksadk/server/static/assets/index-8ipRcQ-M.js +240 -0
  322. ksadk/server/static/assets/index-ByFCqjlh.css +2 -0
  323. ksadk/server/static/assets/info-A6RAGUB7-B6iAblII.js +1 -0
  324. ksadk/server/static/assets/infoDiagram-RXCK75RN-Djm_nbd5.js +2 -0
  325. ksadk/server/static/assets/{ishikawaDiagram-YF4QCWOH-DLOHGvWw.js → ishikawaDiagram-5VMMS53U-DWya9SG2.js} +6 -6
  326. ksadk/server/static/assets/{journeyDiagram-JHISSGLW-BIzKeejT.js → journeyDiagram-EYS64GPL-DutxhSNI.js} +6 -6
  327. ksadk/server/static/assets/{kanban-definition-UN3LZRKU-BWHoFSw2.js → kanban-definition-3QL26DDD-DJdOF8Fm.js} +10 -10
  328. ksadk/server/static/assets/katex-vFWytM5c.js +257 -0
  329. ksadk/server/static/assets/{linear-CvMBw9cA.js → linear-BHjG8b-J.js} +1 -1
  330. ksadk/server/static/assets/mermaid-parser.core-KGSy4jWT.js +166 -0
  331. ksadk/server/static/assets/{mindmap-definition-RKZ34NQL-CSAQxEAe.js → mindmap-definition-FBJOCRG2-9-HC88D4.js} +29 -29
  332. ksadk/server/static/assets/packet-AYTQ26CC-BOYAipuq.js +1 -0
  333. ksadk/server/static/assets/pegDiagram-XKGWAZYB-DrEZd4fD.js +1 -0
  334. ksadk/server/static/assets/pie-WAS4IAKB-Ctq0Kbku.js +1 -0
  335. ksadk/server/static/assets/pieDiagram-E7YTZNPT-DpjqOFFp.js +39 -0
  336. ksadk/server/static/assets/{quadrantDiagram-W4KKPZXB-CxIR4JXI.js → quadrantDiagram-AXDQQJYC-BiNhgOXX.js} +6 -6
  337. ksadk/server/static/assets/radar-RG4KPBEZ-DN0-ul_0.js +1 -0
  338. ksadk/server/static/assets/railroad-74A4TZTK-C6cC_to0.js +1 -0
  339. ksadk/server/static/assets/railroad-abnf-HS5TGJTU-BimjIuRc.js +1 -0
  340. ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-CvY65ABq.js +1 -0
  341. ksadk/server/static/assets/railroad-peg-WCYAUIDC-D72Iq_Tv.js +1 -0
  342. ksadk/server/static/assets/railroadDiagram-O6MQD6OU-_Y3Ojg6G.js +1 -0
  343. ksadk/server/static/assets/requirementDiagram-EFPCY7ZU-DeCFdg9K.js +84 -0
  344. ksadk/server/static/assets/{sankeyDiagram-5OEKKPKP-DpGa6EAV.js → sankeyDiagram-P5KCCOFB-CPH75rhw.js} +7 -7
  345. ksadk/server/static/assets/{sequenceDiagram-3UESZ5HK-NTKNGGe5.js → sequenceDiagram-WJ2MYXX4-OEpQQdr4.js} +10 -10
  346. ksadk/server/static/assets/sizeCapture-X5ZJPWSS-heUErzhI.js +1 -0
  347. ksadk/server/static/assets/stateDiagram-HBIQ2CUA-DvA3jSMB.js +1 -0
  348. ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-BgQY03nz.js +1 -0
  349. ksadk/server/static/assets/swimlanes-XN3QIQJK-CR-dfN_t.js +1 -0
  350. ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-DLVw3q5Q.js +8 -0
  351. ksadk/server/static/assets/{timeline-definition-PNZ67QCA-jqoYs3jQ.js → timeline-definition-24CTP7MA-DAVJf1TX.js} +7 -7
  352. ksadk/server/static/assets/treeView-Q6P3EWNA-BMpO0wsB.js +1 -0
  353. ksadk/server/static/assets/treemap-WGGIJYW6-Et0aqzU3.js +1 -0
  354. ksadk/server/static/assets/vennDiagram-4TSXK5OY-DwM8eDkh.js +34 -0
  355. ksadk/server/static/assets/wardley-WFR3VGLG-CbY0mhpl.js +1 -0
  356. ksadk/server/static/assets/wardleyDiagram-VM6X3IG4-DZL-Zz2t.js +78 -0
  357. ksadk/server/static/assets/xychartDiagram-S5SC5T6Z-Dy6Yh_hu.js +7 -0
  358. ksadk/server/static/index.html +2 -2
  359. ksadk/sessions/__init__.py +26 -9
  360. ksadk/sessions/_local_service_sync.py +688 -0
  361. ksadk/sessions/_local_tables.py +21 -0
  362. ksadk/sessions/_postgres_schema.py +305 -0
  363. ksadk/sessions/_postgres_tables.py +15 -0
  364. ksadk/sessions/base.py +80 -1
  365. ksadk/sessions/in_memory.py +53 -2
  366. ksadk/sessions/local_service.py +63 -604
  367. ksadk/sessions/postgres_service.py +58 -148
  368. ksadk/sessions/resilient.py +35 -1
  369. ksadk/skills/runtime/backends/e2b.py +1 -1
  370. ksadk/skills/service_client.py +13 -3
  371. ksadk/studio/__init__.py +5 -0
  372. ksadk/studio/agent_avatar_assets.py +120 -0
  373. ksadk/studio/agent_lifecycle.py +51 -0
  374. ksadk/studio/api.py +1598 -0
  375. ksadk/studio/api_catalog_routes.py +324 -0
  376. ksadk/studio/api_contracts.py +286 -0
  377. ksadk/studio/api_helpers.py +132 -0
  378. ksadk/studio/api_memory_routes.py +82 -0
  379. ksadk/studio/authoring.py +749 -0
  380. ksadk/studio/authoring_coordinator.py +1017 -0
  381. ksadk/studio/builder.py +397 -0
  382. ksadk/studio/capabilities.py +368 -0
  383. ksadk/studio/cloud.py +2099 -0
  384. ksadk/studio/codex_agent_service.py +694 -0
  385. ksadk/studio/codex_authoring.py +469 -0
  386. ksadk/studio/codex_builder.py +437 -0
  387. ksadk/studio/codex_manifest.py +307 -0
  388. ksadk/studio/codex_run.py +395 -0
  389. ksadk/studio/compiler.py +190 -0
  390. ksadk/studio/contracts.py +755 -0
  391. ksadk/studio/errors.py +47 -0
  392. ksadk/studio/event_store.py +214 -0
  393. ksadk/studio/framework_run.py +342 -0
  394. ksadk/studio/hosted_kernel.py +317 -0
  395. ksadk/studio/identifiers.py +33 -0
  396. ksadk/studio/manifest_resolver.py +131 -0
  397. ksadk/studio/mcp_runtime.py +229 -0
  398. ksadk/studio/model_client.py +629 -0
  399. ksadk/studio/model_profile_service.py +214 -0
  400. ksadk/studio/operations.py +275 -0
  401. ksadk/studio/otel_trace.py +1060 -0
  402. ksadk/studio/pagination.py +182 -0
  403. ksadk/studio/pcm_memory.py +85 -0
  404. ksadk/studio/python_tool_inspection.py +183 -0
  405. ksadk/studio/repository.py +327 -0
  406. ksadk/studio/resource_catalog.py +1260 -0
  407. ksadk/studio/run_service.py +1133 -0
  408. ksadk/studio/runtime_catalog.py +74 -0
  409. ksadk/studio/runtime_source.py +365 -0
  410. ksadk/studio/service.py +2249 -0
  411. ksadk/studio/shared_web.py +1004 -0
  412. ksadk/studio/skill_discovery.py +628 -0
  413. ksadk/studio/static/assets/PrismRenderer-IYN-ffww.js +3 -0
  414. ksadk/studio/static/assets/index-BLpcdrgW.css +1 -0
  415. ksadk/studio/static/assets/index-CYekR2Xv.js +260 -0
  416. ksadk/studio/static/assets/react-vendor-BNmTiJ-I.js +9 -0
  417. ksadk/studio/static/assets/rolldown-runtime-hePW80VL.js +1 -0
  418. ksadk/studio/static/index.html +15 -0
  419. ksadk/studio/templates.py +722 -0
  420. ksadk/studio/validator.py +265 -0
  421. ksadk/studio/workspace.py +135 -0
  422. ksadk/tools/gateway.py +9 -0
  423. ksadk/toolsets/__init__.py +27 -1
  424. ksadk/toolsets/a2a.py +426 -0
  425. ksadk/tracing/__init__.py +19 -21
  426. ksadk/tracing/setup.py +317 -403
  427. ksadk/tracing/span_utils.py +0 -44
  428. ksadk/version.py +1 -1
  429. ksadk_runtime_common/memory_backend/registry.py +56 -56
  430. ksadk_runtime_common/schemas/runtime_event_v1.json +37 -0
  431. ksadk_runtime_common/schemas/runtime_event_v2.json +271 -0
  432. ksadk_runtime_common/workspace_files/router.py +8 -2
  433. agentengine_sdk_python-0.8.0.dist-info/RECORD +0 -578
  434. ksadk/a2a/card_builder.py +0 -64
  435. ksadk/a2a/client.py +0 -309
  436. ksadk/events/parser.py +0 -191
  437. ksadk/harness/runner.py +0 -211
  438. ksadk/runners/codex_runner.py +0 -132
  439. ksadk/runners/utils/langfuse.py +0 -230
  440. ksadk/server/static/assets/MathMessageMarkdown-DeYh8QPr.css +0 -1
  441. ksadk/server/static/assets/MermaidBlock-DWuxETaJ.js +0 -303
  442. ksadk/server/static/assets/NativeTerminalPanel-MDTopWMO.js +0 -1
  443. ksadk/server/static/assets/arc-CFKwSk_B.js +0 -1
  444. ksadk/server/static/assets/architecture-7EHR7CIX-CynqOWjZ.js +0 -1
  445. ksadk/server/static/assets/architectureDiagram-3BPJPVTR-Dej8jX8c.js +0 -36
  446. ksadk/server/static/assets/blockDiagram-GPEHLZMM-1F64jqvy.js +0 -132
  447. ksadk/server/static/assets/c4Diagram-AAUBKEIU-9q7AUAKb.js +0 -10
  448. ksadk/server/static/assets/channel-iUGv2N24.js +0 -1
  449. ksadk/server/static/assets/chunk-2J33WTMH-6qgwJm7Q.js +0 -1
  450. ksadk/server/static/assets/chunk-55IACEB6-BK8paA20.js +0 -1
  451. ksadk/server/static/assets/chunk-727SXJPM-B-JEhy7h.js +0 -206
  452. ksadk/server/static/assets/chunk-AQP2D5EJ-DYBvMHAa.js +0 -231
  453. ksadk/server/static/assets/chunk-QZHKN3VN-YQIEXeF6.js +0 -1
  454. ksadk/server/static/assets/classDiagram-4FO5ZUOK-CDAUuoXK.js +0 -1
  455. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-CDAUuoXK.js +0 -1
  456. ksadk/server/static/assets/cytoscape.esm-DelgaX4f.js +0 -321
  457. ksadk/server/static/assets/dagre-BM42HDAG-C7TguAWo.js +0 -4
  458. ksadk/server/static/assets/dagre-Bx709z4p.js +0 -1
  459. ksadk/server/static/assets/diagram-2AECGRRQ-Dd17_kws.js +0 -43
  460. ksadk/server/static/assets/diagram-5GNKFQAL-DVIClIil.js +0 -10
  461. ksadk/server/static/assets/diagram-KO2AKTUF-Df_3gYQa.js +0 -3
  462. ksadk/server/static/assets/diagram-LMA3HP47-BhLk6ZtA.js +0 -24
  463. ksadk/server/static/assets/diagram-OG6HWLK6-D4GNGvuu.js +0 -24
  464. ksadk/server/static/assets/dist-DyvYLMW9.js +0 -1
  465. ksadk/server/static/assets/erDiagram-TEJ5UH35-CnfRcY2M.js +0 -85
  466. ksadk/server/static/assets/eventmodeling-FCH6USID-ChYO-ijM.js +0 -1
  467. ksadk/server/static/assets/flowDiagram-I6XJVG4X-DGaJjGNJ.js +0 -162
  468. ksadk/server/static/assets/ganttDiagram-6RSMTGT7-DpCoB2g9.js +0 -292
  469. ksadk/server/static/assets/gitGraph-WXDBUCRP-BN_0Fk-j.js +0 -1
  470. ksadk/server/static/assets/gitGraphDiagram-PVQCEYII-9IKVFBVT.js +0 -106
  471. ksadk/server/static/assets/graphlib-B8gBHxth.js +0 -1
  472. ksadk/server/static/assets/index-QSwCHuB8.js +0 -177
  473. ksadk/server/static/assets/index-jOPmTOZH.css +0 -2
  474. ksadk/server/static/assets/info-J43DQDTF-Cp6o3vId.js +0 -1
  475. ksadk/server/static/assets/infoDiagram-5YYISTIA-CYIIsb8y.js +0 -2
  476. ksadk/server/static/assets/katex-DATssjp1.js +0 -265
  477. ksadk/server/static/assets/mermaid-parser.core-mGAcEwcq.js +0 -161
  478. ksadk/server/static/assets/packet-YPE3B663-wQzct3cT.js +0 -1
  479. ksadk/server/static/assets/pie-LRSECV5Y-BgTQiv-9.js +0 -1
  480. ksadk/server/static/assets/pieDiagram-4H26LBE5-By-ra07M.js +0 -30
  481. ksadk/server/static/assets/radar-GUYGQ44K-BIq5fXsn.js +0 -1
  482. ksadk/server/static/assets/requirementDiagram-4Y6WPE33-DpW90iu3.js +0 -84
  483. ksadk/server/static/assets/stateDiagram-AJRCARHV-DGpd9yFG.js +0 -1
  484. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-B3o579IQ.js +0 -1
  485. ksadk/server/static/assets/treeView-BLDUP644-Dqi-E0EM.js +0 -1
  486. ksadk/server/static/assets/treemap-LRROVOQU-ClQP9CJ9.js +0 -1
  487. ksadk/server/static/assets/vennDiagram-CIIHVFJN-l3Z7-wbP.js +0 -34
  488. ksadk/server/static/assets/wardley-L42UT6IY-8XLvnNIs.js +0 -1
  489. ksadk/server/static/assets/wardleyDiagram-YWT4CUSO-BR54GPmr.js +0 -78
  490. ksadk/server/static/assets/xychartDiagram-2RQKCTM6-SkiH8GsK.js +0 -7
  491. ksadk/tracing/exporters/langfuse_exporter.py +0 -460
  492. {agentengine_sdk_python-0.8.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/entry_points.txt +0 -0
  493. {agentengine_sdk_python-0.8.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/licenses/LICENSE +0 -0
  494. {agentengine_sdk_python-0.8.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/top_level.txt +0 -0
ksadk/agui/agent.py CHANGED
@@ -7,6 +7,7 @@ import copy
7
7
  import hashlib
8
8
  import json
9
9
  import logging
10
+ import time
10
11
  from dataclasses import dataclass, field
11
12
  from importlib import import_module
12
13
  from typing import Any, AsyncIterator, Callable, Mapping, Optional, cast
@@ -36,20 +37,43 @@ from ag_ui.core import (
36
37
  ToolCallStartEvent,
37
38
  )
38
39
 
39
- from ksadk.agui.a2ui_projection import project_a2ui_operations
40
+ from ksadk.agui import _agent_helpers
40
41
  from ksadk.conversations.runtime_metadata import (
41
42
  _update_session_metadata_after_assistant_turn,
42
43
  prime_session_metadata_for_user_turn,
43
44
  )
44
- from ksadk.events.runtime_event import EventType, RuntimeEvent
45
+ from ksadk.events.canonical import (
46
+ ApprovalResponse,
47
+ ContentSnapshot,
48
+ ContinuationCreated,
49
+ InteractionRequested,
50
+ InteractionResolved,
51
+ ItemCompleted,
52
+ ItemSnapshotReplaced,
53
+ ItemStarted,
54
+ ItemUpdated,
55
+ RunCanceled,
56
+ RunCompleted,
57
+ RunFailed,
58
+ RunInterrupted,
59
+ RunStarted,
60
+ RuntimeEvent,
61
+ SourceRef,
62
+ )
63
+ from ksadk.events.content import (
64
+ TextContent,
65
+ ToolCallContent,
66
+ ToolResultContent,
67
+ )
45
68
  from ksadk.runtime.adapter import (
46
69
  CancelResult,
47
70
  ResumePayload,
48
71
  ResumeTarget,
49
72
  RunHandle,
50
- RuntimeAdapter,
73
+ RuntimeLaunchContext,
51
74
  StartRequest,
52
75
  )
76
+ from ksadk.runtime.executor import RuntimeExecutor
53
77
 
54
78
  EventStoreFactory = Callable[[], Any]
55
79
  SessionServiceFactory = Callable[[], Any]
@@ -85,7 +109,8 @@ class _ThreadRun:
85
109
 
86
110
  @dataclass
87
111
  class _SharedRuntime:
88
- adapter: RuntimeAdapter
112
+ executor: RuntimeExecutor
113
+ launch_context: RuntimeLaunchContext
89
114
  event_store_factory: Optional[EventStoreFactory]
90
115
  session_service_factory: Optional[SessionServiceFactory]
91
116
  threads: dict[str, _ThreadRun] = field(default_factory=dict)
@@ -103,6 +128,7 @@ class _WireState:
103
128
  reasoning_open: bool = False
104
129
  terminal: bool = False
105
130
  text_content: str = ""
131
+ reasoning_content: str = ""
106
132
 
107
133
 
108
134
  class KsadkAGUIAgent:
@@ -118,22 +144,35 @@ class KsadkAGUIAgent:
118
144
  self,
119
145
  *,
120
146
  name: str,
121
- adapter: RuntimeAdapter,
147
+ executor: RuntimeExecutor | None = None,
148
+ launch_context: RuntimeLaunchContext | None = None,
122
149
  event_store_factory: Optional[EventStoreFactory] = None,
123
150
  session_service_factory: Optional[SessionServiceFactory] = None,
124
151
  _shared: Optional[_SharedRuntime] = None,
125
152
  ) -> None:
126
153
  self.name = name
127
- self._shared = _shared or _SharedRuntime(
128
- adapter,
129
- event_store_factory,
130
- session_service_factory,
131
- )
154
+ if _shared is not None:
155
+ self._shared = _shared
156
+ else:
157
+ if executor is None or launch_context is None:
158
+ raise ValueError("AG-UI requires RuntimeExecutor and RuntimeLaunchContext")
159
+ self._shared = _SharedRuntime(
160
+ executor,
161
+ launch_context,
162
+ event_store_factory,
163
+ session_service_factory,
164
+ )
132
165
 
133
166
  def clone(self) -> "KsadkAGUIAgent":
134
- return type(self)(name=self.name, adapter=self._shared.adapter, _shared=self._shared)
167
+ return type(self)(name=self.name, _shared=self._shared)
135
168
 
136
169
  async def run(self, input: RunAgentInput) -> AsyncIterator[BaseEvent]:
170
+ from ksadk.kernel import ingress as _kernel_ingress
171
+
172
+ if _kernel_ingress.kernel_route_active():
173
+ async for event in self._kernel_run(input):
174
+ yield event
175
+ return
137
176
  wire = _WireState(
138
177
  thread_id=input.thread_id,
139
178
  run_id=input.run_id,
@@ -160,8 +199,11 @@ class KsadkAGUIAgent:
160
199
  return
161
200
 
162
201
  run.active = True
163
- async for runtime_event in self._shared.adapter.stream(run.handle):
164
- persisted = await self._persist(self._event_for_persistence(runtime_event, run))
202
+ async for runtime_event in self._shared.executor.stream(run.handle):
203
+ persisted = await self._persist(
204
+ self._event_for_persistence(runtime_event, run),
205
+ session_id=input.thread_id,
206
+ )
165
207
  async for event in self._project(persisted, wire, run):
166
208
  yield event
167
209
  if not wire.terminal:
@@ -193,6 +235,102 @@ class KsadkAGUIAgent:
193
235
  if run is not None and not run.cancel_failed:
194
236
  run.active = False
195
237
 
238
+ async def _kernel_run(self, input: RunAgentInput) -> AsyncIterator[BaseEvent]:
239
+ """kernel 路径(灰度 opt-in):AG-UI run -> AgentControlCommand -> receipt。
240
+
241
+ mutation 只走 kernel.submit;AG-UI 事件 shape 保留,cursor 源自同一
242
+ Session seq(SessionEventSubscription.after_seq)。
243
+ """
244
+ from ksadk.kernel import ingress as _kernel_ingress
245
+
246
+ yield RunStartedEvent(
247
+ thread_id=input.thread_id,
248
+ run_id=input.run_id,
249
+ parent_run_id=input.parent_run_id,
250
+ input=input,
251
+ )
252
+ message_id = f"{input.run_id}:assistant"
253
+ text = ""
254
+ try:
255
+ trusted = _kernel_ingress.trusted_context(
256
+ source_kind="agui",
257
+ source_ref=input.run_id,
258
+ session_id=input.thread_id,
259
+ operations=("enqueue",),
260
+ launch_context=self._shared.launch_context,
261
+ )
262
+ command = _kernel_ingress.map_agui_request(
263
+ session_id=input.thread_id,
264
+ idempotency_key=input.run_id,
265
+ content=[
266
+ {"role": "user", "content": _agui_user_text(input)}
267
+ ],
268
+ run_id=input.run_id,
269
+ trusted=trusted,
270
+ )
271
+ receipt = await _kernel_ingress.submit_command(
272
+ command, permit=trusted.permit
273
+ )
274
+ if receipt.status not in ("accepted", "duplicate"):
275
+ yield RunErrorEvent(
276
+ message=f"agent kernel rejected command: {receipt.status}",
277
+ code=receipt.status.upper(),
278
+ )
279
+ return
280
+ text_open = False
281
+ async for _seq, payload in _kernel_ingress.subscribe_projected(
282
+ input.thread_id,
283
+ trusted=trusted,
284
+ after_seq=int(receipt.accepted_seq or 0),
285
+ projector=_agui_envelope_payload,
286
+ ):
287
+ if payload is None:
288
+ continue
289
+ kind, value = payload
290
+ if kind == "delta":
291
+ if not text_open:
292
+ text_open = True
293
+ yield TextMessageStartEvent(message_id=message_id)
294
+ text += value
295
+ yield TextMessageContentEvent(message_id=message_id, delta=value)
296
+ elif kind == "completed":
297
+ final = value or text
298
+ if final and not text_open:
299
+ text_open = True
300
+ yield TextMessageStartEvent(message_id=message_id)
301
+ if final.startswith(text) and len(final) > len(text):
302
+ yield TextMessageContentEvent(
303
+ message_id=message_id, delta=final[len(text):]
304
+ )
305
+ text = final
306
+ if text_open:
307
+ yield TextMessageEndEvent(message_id=message_id)
308
+ yield RunFinishedEvent(
309
+ thread_id=input.thread_id,
310
+ run_id=input.run_id,
311
+ outcome=RunFinishedSuccessOutcome(),
312
+ result={"output_text": text},
313
+ )
314
+ return
315
+ if text_open:
316
+ yield TextMessageEndEvent(message_id=message_id)
317
+ yield RunFinishedEvent(
318
+ thread_id=input.thread_id,
319
+ run_id=input.run_id,
320
+ outcome=RunFinishedSuccessOutcome(),
321
+ result={"output_text": text},
322
+ )
323
+ except Exception:
324
+ logger.exception(
325
+ "AG-UI kernel ingress failed for thread=%s run=%s",
326
+ input.thread_id,
327
+ input.run_id,
328
+ )
329
+ yield RunErrorEvent(
330
+ message="Agent kernel ingress failed",
331
+ code="KERNEL_ERROR",
332
+ )
333
+
196
334
  async def _resolve_run(self, input: RunAgentInput) -> tuple[_ThreadRun, bool]:
197
335
  async with self._shared.lock:
198
336
  if input.resume:
@@ -230,7 +368,10 @@ class KsadkAGUIAgent:
230
368
  config=request_config,
231
369
  metadata={"invocation_id": input.run_id, "transport": "ag-ui"},
232
370
  )
233
- handle = await self._shared.adapter.start(request)
371
+ handle = await self._shared.executor.start(
372
+ self._shared.launch_context,
373
+ request,
374
+ )
234
375
  await self._persist_user_input(input, request, handle)
235
376
  run = _ThreadRun(handle=handle)
236
377
  self._shared.threads[input.thread_id] = run
@@ -287,7 +428,7 @@ class KsadkAGUIAgent:
287
428
  for interrupt_id, fingerprint in fingerprints.items():
288
429
  self._shared.consumed_resumes[(input.thread_id, interrupt_id)] = fingerprint
289
430
 
290
- resumed = await self._shared.adapter.resume(
431
+ resumed = await self._shared.executor.resume(
291
432
  current.handle,
292
433
  ResumeTarget(kind="checkpoint_id", id=next(iter(checkpoint_ids))),
293
434
  ResumePayload(
@@ -319,155 +460,183 @@ class KsadkAGUIAgent:
319
460
  default=str,
320
461
  )
321
462
  decision = self._approval_decision_for_audit(entry.status, entry.payload)
322
- event = RuntimeEvent.create(
323
- EventType.APPROVAL_RESOLVED,
463
+ event = InteractionResolved(
464
+ schema_version=2,
324
465
  event_id=f"evt_agui_resume_{hashlib.sha256(event_key.encode()).hexdigest()}",
325
- agent_id=str(run.handle.native_ref.get("agent_id") or self.name),
326
- user_id=str(run.handle.native_ref.get("user_id") or "agui-user"),
327
- session_id=input.thread_id,
328
- invocation_id=run.handle.run_id,
329
- seq_id=0,
330
- payload={
331
- "approval_id": entry.interrupt_id,
332
- "call_id": entry.interrupt_id,
333
- "decision": decision,
334
- "resume_fingerprint": fingerprint,
335
- "protocol": "ag-ui",
336
- },
466
+ seq=0,
467
+ timestamp=time.time(),
468
+ run_id=run.handle.run_id,
469
+ scope_id=f"ksadk:{run.handle.run_id}",
470
+ source=SourceRef(
471
+ framework="ksadk",
472
+ metadata={
473
+ "agent_id": str(run.handle.native_ref.get("agent_id") or self.name),
474
+ "user_id": str(run.handle.native_ref.get("user_id") or "agui-user"),
475
+ "session_id": input.thread_id,
476
+ "protocol": "ag-ui",
477
+ "resume_fingerprint": fingerprint,
478
+ },
479
+ ),
480
+ interaction_id=entry.interrupt_id,
481
+ interaction_kind="approval",
482
+ response=ApprovalResponse(
483
+ response_type="approval",
484
+ decision=(
485
+ decision if decision in ("approved", "rejected", "canceled") else "rejected"
486
+ ),
487
+ data={"call_id": entry.interrupt_id},
488
+ ),
337
489
  )
338
490
  if index == 0:
339
- _persisted, reservation_created = await self._reserve(event)
491
+ _persisted, reservation_created = await self._reserve(
492
+ event, session_id=input.thread_id
493
+ )
340
494
  if not reservation_created:
341
495
  return False
342
496
  else:
343
- await self._persist(event)
497
+ await self._persist(event, session_id=input.thread_id)
344
498
  return reservation_created
345
499
 
346
- @staticmethod
347
- def _approval_decision_for_audit(status: str, payload: Any) -> str:
348
- """Persist a stable decision value while accepting official AG-UI envelopes."""
349
-
350
- if status != "resolved":
351
- return "rejected"
352
- if payload is True:
353
- return "approved"
354
- if isinstance(payload, Mapping):
355
- for key in ("approve", "approved"):
356
- if key in payload:
357
- return "approved" if bool(payload[key]) else "rejected"
358
- for key in ("decision", "type"):
359
- if key in payload:
360
- return KsadkAGUIAgent._approval_decision_for_audit(status, payload[key])
361
- return "rejected"
362
- if isinstance(payload, str) and payload.strip().lower() in {"approve", "approved"}:
363
- return "approved"
364
- return "rejected"
365
-
366
500
  async def _project(
367
501
  self,
368
502
  event: RuntimeEvent,
369
503
  wire: _WireState,
370
504
  run: _ThreadRun,
371
505
  ) -> AsyncIterator[BaseEvent]:
372
- payload = event.payload
373
- event_type = event.event_type
374
-
375
- if event_type in (EventType.TEXT_DELTA, EventType.TEXT_COMPLETED):
506
+ # ---- message (text) ----
507
+ if isinstance(event, (ItemUpdated, ItemSnapshotReplaced)) and event.item_kind == "message":
376
508
  if not wire.text_open:
377
509
  wire.text_open = True
378
510
  yield TextMessageStartEvent(message_id=wire.message_id)
379
- text = str(payload.get("text") or "")
380
- if event_type == EventType.TEXT_COMPLETED and wire.text_content:
381
- text = text[len(wire.text_content) :] if text.startswith(wire.text_content) else ""
511
+ if isinstance(event, ItemSnapshotReplaced):
512
+ # atomic snapshot replace: close and reopen with full text
513
+ wire.text_open = False
514
+ wire.text_content = ""
515
+ yield TextMessageEndEvent(message_id=wire.message_id)
516
+ wire.text_open = True
517
+ yield TextMessageStartEvent(message_id=wire.message_id)
518
+ text = self._extract_text(event.snapshot)
519
+ elif event.op == "replace":
520
+ wire.text_open = False
521
+ wire.text_content = ""
522
+ yield TextMessageEndEvent(message_id=wire.message_id)
523
+ wire.text_open = True
524
+ yield TextMessageStartEvent(message_id=wire.message_id)
525
+ text = event.update.text if isinstance(event.update, TextContent) else ""
526
+ else:
527
+ text = event.update.text if isinstance(event.update, TextContent) else ""
382
528
  if text:
383
529
  yield TextMessageContentEvent(message_id=wire.message_id, delta=text)
384
530
  wire.text_content += text
385
- if event_type == EventType.TEXT_COMPLETED:
386
- wire.text_open = False
387
- yield TextMessageEndEvent(message_id=wire.message_id)
388
531
  return
389
532
 
390
- if event_type in (EventType.REASONING_DELTA, EventType.REASONING_COMPLETED):
533
+ if isinstance(event, ItemCompleted) and event.item_kind == "message":
534
+ if not wire.text_open:
535
+ wire.text_open = True
536
+ yield TextMessageStartEvent(message_id=wire.message_id)
537
+ # ItemCompleted is the authoritative snapshot; do NOT re-append
538
+ # the full text when deltas already covered the content.
539
+ if not wire.text_content:
540
+ text = self._extract_text(event.snapshot)
541
+ if text:
542
+ yield TextMessageContentEvent(message_id=wire.message_id, delta=text)
543
+ wire.text_content += text
544
+ wire.text_open = False
545
+ yield TextMessageEndEvent(message_id=wire.message_id)
546
+ return
547
+
548
+ if isinstance(event, ItemStarted) and event.item_kind == "message":
549
+ # ItemStarted for messages is a tracking signal; the text message
550
+ # opens lazily on the first content delta or completed snapshot.
551
+ return
552
+
553
+ # ---- reasoning ----
554
+ if (
555
+ isinstance(event, (ItemUpdated, ItemSnapshotReplaced))
556
+ and event.item_kind == "reasoning"
557
+ ):
391
558
  if not wire.reasoning_open:
392
559
  wire.reasoning_open = True
393
560
  yield ReasoningStartEvent(message_id=wire.reasoning_id)
394
561
  yield ReasoningMessageStartEvent(message_id=wire.reasoning_id, role="reasoning")
395
- text = str(payload.get("text") or "")
562
+ if isinstance(event, ItemSnapshotReplaced):
563
+ wire.reasoning_content = ""
564
+ text = self._extract_text(event.snapshot)
565
+ else:
566
+ text = event.update.text if isinstance(event.update, TextContent) else ""
396
567
  if text:
397
568
  yield ReasoningMessageContentEvent(message_id=wire.reasoning_id, delta=text)
398
- if event_type == EventType.REASONING_COMPLETED:
399
- wire.reasoning_open = False
400
- yield ReasoningMessageEndEvent(message_id=wire.reasoning_id)
401
- yield ReasoningEndEvent(message_id=wire.reasoning_id)
569
+ wire.reasoning_content += text
402
570
  return
403
571
 
404
- if event_type == EventType.TOOL_CALL_BEGIN:
405
- call_id = str(payload.get("call_id") or "tool")
406
- yield ToolCallStartEvent(
407
- tool_call_id=call_id,
408
- tool_call_name=str(payload.get("name") or "tool"),
409
- parent_message_id=wire.message_id,
410
- )
411
- if "args" in payload:
572
+ if isinstance(event, ItemCompleted) and event.item_kind == "reasoning":
573
+ if not wire.reasoning_open:
574
+ wire.reasoning_open = True
575
+ yield ReasoningStartEvent(message_id=wire.reasoning_id)
576
+ yield ReasoningMessageStartEvent(message_id=wire.reasoning_id, role="reasoning")
577
+ if not wire.reasoning_content:
578
+ text = self._extract_text(event.snapshot)
579
+ if text:
580
+ yield ReasoningMessageContentEvent(message_id=wire.reasoning_id, delta=text)
581
+ wire.reasoning_content += text
582
+ wire.reasoning_open = False
583
+ yield ReasoningMessageEndEvent(message_id=wire.reasoning_id)
584
+ yield ReasoningEndEvent(message_id=wire.reasoning_id)
585
+ return
586
+
587
+ if isinstance(event, ItemStarted) and event.item_kind == "reasoning":
588
+ return
589
+
590
+ # ---- tool call ----
591
+ if isinstance(event, ItemStarted) and event.item_kind == "tool_call":
592
+ part = self._first_part(event.initial)
593
+ if isinstance(part, ToolCallContent):
594
+ call_id = part.call_id
595
+ yield ToolCallStartEvent(
596
+ tool_call_id=call_id,
597
+ tool_call_name=part.name,
598
+ parent_message_id=wire.message_id,
599
+ )
412
600
  yield ToolCallArgsEvent(
413
601
  tool_call_id=call_id,
414
- delta=json.dumps(payload.get("args"), ensure_ascii=False, default=str),
602
+ delta=json.dumps(part.arguments, ensure_ascii=False, default=str),
415
603
  )
416
604
  return
417
605
 
418
- if event_type == EventType.TOOL_CALL_END:
419
- call_id = str(payload.get("call_id") or "tool")
420
- content = (
421
- payload.get("result") if payload.get("error") is None else payload.get("error")
422
- )
423
- # AG-UI closes the active call at TOOL_CALL_END. Sending a result
424
- # first makes official clients discard the call, then reject this
425
- # end event as orphaned.
606
+ if isinstance(event, ItemCompleted) and event.item_kind == "tool_call":
607
+ part = self._first_part(event.snapshot)
608
+ call_id = part.call_id if isinstance(part, ToolCallContent) else "tool"
426
609
  yield ToolCallEndEvent(tool_call_id=call_id)
427
- yield ToolCallResultEvent(
428
- message_id=f"{wire.run_id}:tool:{call_id}",
429
- tool_call_id=call_id,
430
- content=json.dumps(content, ensure_ascii=False, default=str),
431
- role="tool",
432
- )
433
610
  return
434
611
 
435
- if event_type == EventType.CHECKPOINT_CREATED:
436
- yield StateSnapshotEvent(snapshot={"checkpoint": copy.deepcopy(payload)})
612
+ if isinstance(event, ItemCompleted) and event.item_kind == "tool_result":
613
+ part = self._first_part(event.snapshot)
614
+ if isinstance(part, ToolResultContent):
615
+ call_id = part.call_id
616
+ content = part.result
617
+ yield ToolCallResultEvent(
618
+ message_id=f"{wire.run_id}:tool:{call_id}",
619
+ tool_call_id=call_id,
620
+ content=json.dumps(content, ensure_ascii=False, default=str),
621
+ role="tool",
622
+ )
437
623
  return
438
624
 
439
- if event_type == EventType.APPROVAL_REQUESTED:
440
- interrupt_id = str(payload.get("approval_id") or payload.get("call_id") or "")
441
- checkpoint_id = str(run.handle.native_ref.get("checkpoint_id") or "")
442
- if not checkpoint_id:
443
- known = run.handle.native_ref.get("known_checkpoint_ids") or []
444
- checkpoint_id = str(known[-1]) if known else ""
445
- raw_detail = payload.get("detail")
446
- detail: dict[str, Any] = raw_detail if isinstance(raw_detail, dict) else {}
447
- interrupt = Interrupt(
448
- id=interrupt_id,
449
- reason=str(detail.get("reason") or payload.get("kind") or "approval"),
450
- message=self._approval_message(detail, payload),
451
- tool_call_id=str(payload.get("call_id") or "") or None,
452
- response_schema=detail.get("response_schema"),
453
- metadata=self._approval_metadata(detail, payload),
454
- )
455
- run.pending[interrupt_id] = _PendingInterrupt(interrupt, checkpoint_id)
625
+ if isinstance(event, ItemStarted) and event.item_kind == "tool_result":
456
626
  return
457
627
 
458
- if event_type in {
459
- EventType.A2UI_SURFACE_BEGIN,
460
- EventType.A2UI_SURFACE_UPDATE,
461
- EventType.A2UI_SURFACE_END,
462
- }:
463
- operations = project_a2ui_operations(event_type, payload)
628
+ # ---- A2UI surface (item_kind="data" + source.protocol="a2ui") ----
629
+ if (
630
+ isinstance(event, (ItemStarted, ItemUpdated, ItemCompleted))
631
+ and event.item_kind == "data"
632
+ and event.source.protocol == "a2ui"
633
+ ):
634
+ surface_id = str(event.source.metadata.get("surface_id") or "")
635
+ operations = self._a2ui_operations(event, surface_id)
464
636
  if operations:
465
- surface_id = str(payload.get("surface_id") or payload.get("surfaceId") or "")
466
637
  yield ActivitySnapshotEvent(
467
638
  message_id=f"{wire.run_id}:a2ui:{surface_id}",
468
639
  activity_type="a2ui-surface",
469
- # The client renderer addresses a surface by this value.
470
- # ``message_id`` is a transport id, not the A2UI surface id.
471
640
  content={
472
641
  "surfaceId": surface_id,
473
642
  "a2ui_operations": operations,
@@ -476,18 +645,62 @@ class KsadkAGUIAgent:
476
645
  )
477
646
  return
478
647
 
479
- if event_type == EventType.RUN_INTERRUPTED:
648
+ # ---- checkpoint ----
649
+ if isinstance(event, ContinuationCreated):
650
+ # Track checkpoint id in handle native_ref for downstream approval
651
+ # resolution (pending interrupts need a resumable checkpoint_id).
652
+ ckpt_id = str(event.ref.get("checkpoint_id") or "")
653
+ if ckpt_id:
654
+ run.handle.native_ref["checkpoint_id"] = ckpt_id
655
+ known = run.handle.native_ref.setdefault("known_checkpoint_ids", [])
656
+ if ckpt_id not in known:
657
+ known.append(ckpt_id)
658
+ yield StateSnapshotEvent(snapshot={"checkpoint": copy.deepcopy(event.ref)})
659
+ return
660
+
661
+ # ---- approval ----
662
+ if isinstance(event, InteractionRequested):
663
+ interrupt = self._interrupt_from_interaction(event)
664
+ checkpoint_id = str(run.handle.native_ref.get("checkpoint_id") or "")
665
+ if not checkpoint_id:
666
+ known = run.handle.native_ref.get("known_checkpoint_ids") or []
667
+ checkpoint_id = str(known[-1]) if known else ""
668
+ run.pending[interrupt.id] = _PendingInterrupt(interrupt, checkpoint_id)
669
+ return
670
+
671
+ # ---- run lifecycle ----
672
+ if isinstance(event, RunInterrupted):
480
673
  async for close_event in self._close_open_messages(wire):
481
674
  yield close_event
482
675
  if not run.pending:
483
676
  raise ValueError("runtime interrupted without a pending approval")
484
- checkpoint_id = str(run.handle.native_ref.get("checkpoint_id") or "")
677
+ # If checkpoint_id wasn't set by ContinuationCreated (e.g. langgraph
678
+ # canonical stream without checkpoint_ref on first run), try to
679
+ # extract it from the RunInterrupted event's continuation_id or
680
+ # the executor's checkpoint descriptor.
681
+ if event.continuation_id:
682
+ checkpoint_id = str(event.continuation_id)
683
+ else:
684
+ checkpoint_id = str(run.handle.native_ref.get("checkpoint_id") or "")
485
685
  if not checkpoint_id:
486
686
  known = run.handle.native_ref.get("known_checkpoint_ids") or []
487
687
  checkpoint_id = str(known[-1]) if known else ""
488
- for pending in run.pending.values():
489
- if not pending.checkpoint_id:
490
- pending.checkpoint_id = checkpoint_id
688
+ if not checkpoint_id:
689
+ # Last resort: query the executor for the native checkpoint.
690
+ try:
691
+ descriptor = await self._shared.executor.checkpoint(run.handle)
692
+ checkpoint_id = str(descriptor.checkpoint_id or "")
693
+ if checkpoint_id:
694
+ run.handle.native_ref["checkpoint_id"] = checkpoint_id
695
+ known = run.handle.native_ref.setdefault("known_checkpoint_ids", [])
696
+ if checkpoint_id not in known:
697
+ known.append(checkpoint_id)
698
+ except Exception:
699
+ pass
700
+ if checkpoint_id:
701
+ for pending in run.pending.values():
702
+ if not pending.checkpoint_id:
703
+ pending.checkpoint_id = checkpoint_id
491
704
  run.interrupted = True
492
705
  wire.terminal = True
493
706
  yield RunFinishedEvent(
@@ -499,23 +712,30 @@ class KsadkAGUIAgent:
499
712
  )
500
713
  return
501
714
 
502
- if event_type == EventType.RUN_COMPLETED:
715
+ if isinstance(event, RunCompleted):
503
716
  async for finish_event in self._finish_success(wire):
504
717
  yield finish_event
505
718
  return
506
719
 
507
- if event_type in (EventType.RUN_FAILED, EventType.RUN_CANCELED):
720
+ if isinstance(event, RunCanceled):
508
721
  async for close_event in self._close_open_messages(wire):
509
722
  yield close_event
510
723
  wire.terminal = True
511
724
  yield RunErrorEvent(
512
- message=(
513
- "Runtime run was cancelled"
514
- if event_type == EventType.RUN_CANCELED
515
- else "Runtime execution failed"
516
- ),
517
- code=("CANCELLED" if event_type == EventType.RUN_CANCELED else "RUNTIME_ERROR"),
725
+ message=event.reason or "Runtime run was cancelled",
726
+ code="CANCELLED",
727
+ )
728
+ return
729
+
730
+ if isinstance(event, RunFailed):
731
+ async for close_event in self._close_open_messages(wire):
732
+ yield close_event
733
+ wire.terminal = True
734
+ yield RunErrorEvent(
735
+ message=event.error.message or "Runtime execution failed",
736
+ code="RUNTIME_ERROR",
518
737
  )
738
+ return
519
739
 
520
740
  async def _finish_success(self, wire: _WireState) -> AsyncIterator[BaseEvent]:
521
741
  async for event in self._close_open_messages(wire):
@@ -538,14 +758,17 @@ class KsadkAGUIAgent:
538
758
  wire.text_open = False
539
759
  yield TextMessageEndEvent(message_id=wire.message_id)
540
760
 
541
- async def _persist(self, event: RuntimeEvent) -> RuntimeEvent:
761
+ async def _persist(self, event: RuntimeEvent, *, session_id: str = "") -> RuntimeEvent:
542
762
  factory = self._shared.event_store_factory
543
763
  if factory is None:
544
764
  return event
545
765
  store = factory()
546
- return cast(RuntimeEvent, await store.append_one(event))
766
+ sid = str(event.source.metadata.get("session_id") or session_id or "")
767
+ return cast(RuntimeEvent, await store.append_one(sid, event))
547
768
 
548
- async def _reserve(self, event: RuntimeEvent) -> tuple[RuntimeEvent, bool]:
769
+ async def _reserve(
770
+ self, event: RuntimeEvent, *, session_id: str = ""
771
+ ) -> tuple[RuntimeEvent, bool]:
549
772
  factory = self._shared.event_store_factory
550
773
  if factory is None:
551
774
  return event, True
@@ -554,7 +777,8 @@ class KsadkAGUIAgent:
554
777
  if callable(reserve):
555
778
  persisted, created = await reserve(event)
556
779
  return cast(RuntimeEvent, persisted), bool(created)
557
- return cast(RuntimeEvent, await store.append_one(event)), True
780
+ sid = str(event.source.metadata.get("session_id") or session_id or "")
781
+ return cast(RuntimeEvent, await store.append_one(sid, event)), True
558
782
 
559
783
  async def _persist_user_input(
560
784
  self,
@@ -564,21 +788,27 @@ class KsadkAGUIAgent:
564
788
  ) -> None:
565
789
  event_key = json.dumps([input.thread_id, input.run_id, "user"], ensure_ascii=False)
566
790
  await self._persist(
567
- RuntimeEvent.create(
568
- EventType.RUN_STARTED,
791
+ RunStarted(
792
+ schema_version=2,
569
793
  event_id=f"evt_agui_input_{hashlib.sha256(event_key.encode()).hexdigest()}",
570
- agent_id=self.name,
571
- user_id=request.user_id,
572
- session_id=input.thread_id,
573
- invocation_id=input.run_id,
574
- seq_id=0,
575
- payload={
576
- "status": "in_progress",
577
- "input": self._json_safe(request.input),
578
- "source": "ag-ui",
579
- "runtime_type": handle.runtime_type,
580
- },
581
- )
794
+ seq=0,
795
+ timestamp=time.time(),
796
+ run_id=input.run_id,
797
+ scope_id=f"ksadk:{input.run_id}",
798
+ source=SourceRef(
799
+ framework="ksadk",
800
+ metadata={
801
+ "agent_id": self.name,
802
+ "user_id": request.user_id,
803
+ "session_id": input.thread_id,
804
+ "input": self._json_safe(request.input),
805
+ "source": "ag-ui",
806
+ "runtime_type": handle.runtime_type,
807
+ },
808
+ ),
809
+ status="running",
810
+ ),
811
+ session_id=input.thread_id,
582
812
  )
583
813
  await self._prime_session_metadata_for_user_turn(
584
814
  session_id=input.thread_id,
@@ -626,21 +856,22 @@ class KsadkAGUIAgent:
626
856
  logger.debug("failed to update AG-UI session metadata", exc_info=True)
627
857
 
628
858
  def _event_for_persistence(self, event: RuntimeEvent, run: _ThreadRun) -> RuntimeEvent:
629
- if event.event_type in {
630
- EventType.APPROVAL_REQUESTED,
631
- EventType.APPROVAL_RESOLVED,
632
- }:
633
- return event.model_copy(update={"payload": {**event.payload, "protocol": "ag-ui"}})
634
- if event.event_type != EventType.RUN_INTERRUPTED:
859
+ if isinstance(event, (InteractionRequested, InteractionResolved)):
860
+ new_source = event.source.model_copy(
861
+ update={"metadata": {**event.source.metadata, "protocol": "ag-ui"}}
862
+ )
863
+ return event.model_copy(update={"source": new_source})
864
+ if not isinstance(event, RunInterrupted):
635
865
  return event
636
- return event.model_copy(
866
+ new_source = event.source.model_copy(
637
867
  update={
638
- "payload": {
639
- **event.payload,
868
+ "metadata": {
869
+ **event.source.metadata,
640
870
  "runtime_handle": self._durable_handle(run.handle),
641
871
  }
642
872
  }
643
873
  )
874
+ return event.model_copy(update={"source": new_source})
644
875
 
645
876
  async def _restore_durable_run(
646
877
  self,
@@ -651,13 +882,15 @@ class KsadkAGUIAgent:
651
882
  if not events:
652
883
  return None, False
653
884
  resolved = {
654
- str(event.payload.get("approval_id") or event.payload.get("call_id") or ""): event
885
+ str(event.interaction_id): event
655
886
  for event in events
656
- if event.event_type == EventType.APPROVAL_RESOLVED
887
+ if isinstance(event, InteractionResolved)
657
888
  }
658
889
  if fingerprints and all(interrupt_id in resolved for interrupt_id in fingerprints):
659
890
  for interrupt_id, fingerprint in fingerprints.items():
660
- persisted = str(resolved[interrupt_id].payload.get("resume_fingerprint") or "")
891
+ persisted = str(
892
+ resolved[interrupt_id].source.metadata.get("resume_fingerprint") or ""
893
+ )
661
894
  if persisted and persisted != fingerprint:
662
895
  raise ValueError(f"interrupt {interrupt_id!r} was resolved differently")
663
896
  return None, True
@@ -665,22 +898,21 @@ class KsadkAGUIAgent:
665
898
  raise ValueError("resume set is only partially resolved")
666
899
 
667
900
  interrupted = next(
668
- (event for event in reversed(events) if event.event_type == EventType.RUN_INTERRUPTED),
901
+ (event for event in reversed(events) if isinstance(event, RunInterrupted)),
669
902
  None,
670
903
  )
671
904
  if interrupted is None:
672
905
  return None, False
673
- raw_handle = interrupted.payload.get("runtime_handle")
906
+ raw_handle = interrupted.source.metadata.get("runtime_handle")
674
907
  if not isinstance(raw_handle, dict):
675
908
  return None, False
676
909
  handle = RunHandle.model_validate(raw_handle)
677
910
  requests = [
678
911
  event
679
912
  for event in events
680
- if event.invocation_id == interrupted.invocation_id
681
- and event.event_type == EventType.APPROVAL_REQUESTED
682
- and str(event.payload.get("approval_id") or event.payload.get("call_id") or "")
683
- not in resolved
913
+ if isinstance(event, InteractionRequested)
914
+ and event.run_id == interrupted.run_id
915
+ and str(event.interaction_id) not in resolved
684
916
  ]
685
917
  pending: dict[str, _PendingInterrupt] = {}
686
918
  checkpoint_id = str(handle.native_ref.get("checkpoint_id") or "")
@@ -688,12 +920,15 @@ class KsadkAGUIAgent:
688
920
  known = handle.native_ref.get("known_checkpoint_ids") or []
689
921
  checkpoint_id = str(known[-1]) if known else ""
690
922
  for request in requests:
691
- interrupt = self._interrupt_from_payload(request.payload)
923
+ interrupt = self._interrupt_from_interaction(request)
692
924
  pending[interrupt.id] = _PendingInterrupt(interrupt, checkpoint_id)
693
925
  if not pending:
694
926
  return None, False
695
- if not self._shared.adapter.is_handle_attached(handle):
696
- handle = await self._shared.adapter.attach(handle)
927
+ if not self._shared.executor.is_attached(handle):
928
+ handle = await self._shared.executor.attach(
929
+ self._shared.launch_context,
930
+ handle,
931
+ )
697
932
  return _ThreadRun(handle=handle, interrupted=True, pending=pending), False
698
933
 
699
934
  async def _durable_events(self, session_id: str) -> list[RuntimeEvent]:
@@ -706,65 +941,16 @@ class KsadkAGUIAgent:
706
941
  return []
707
942
  return list(await list_events(session_id))
708
943
 
709
- @staticmethod
710
- def _durable_handle(handle: RunHandle) -> dict[str, Any]:
711
- allowed = {
712
- "agent_id",
713
- "user_id",
714
- "checkpoint_id",
715
- "known_checkpoint_ids",
716
- "pending_approval_ids",
717
- "framework_ref",
718
- "thread_id",
719
- "checkpoint_ns",
720
- "resume_thread_id",
721
- }
722
- native_ref = {key: value for key, value in handle.native_ref.items() if key in allowed}
723
- return {
724
- "run_id": handle.run_id,
725
- "session_id": handle.session_id,
726
- "runtime_type": handle.runtime_type,
727
- "native_ref": KsadkAGUIAgent._json_safe(native_ref),
728
- }
729
-
730
- @staticmethod
731
- def _interrupt_from_payload(payload: Mapping[str, Any]) -> Interrupt:
732
- interrupt_id = str(payload.get("approval_id") or payload.get("call_id") or "")
733
- raw_detail = payload.get("detail")
734
- detail = raw_detail if isinstance(raw_detail, dict) else {}
735
- return Interrupt(
736
- id=interrupt_id,
737
- reason=str(detail.get("reason") or payload.get("kind") or "approval"),
738
- message=KsadkAGUIAgent._approval_message(detail, payload),
739
- tool_call_id=str(payload.get("call_id") or "") or None,
740
- response_schema=detail.get("response_schema"),
741
- metadata=KsadkAGUIAgent._approval_metadata(detail, payload),
742
- )
743
-
744
- @staticmethod
745
- def _duplicate_run(input: RunAgentInput) -> _ThreadRun:
746
- return _ThreadRun(
747
- handle=RunHandle(
748
- run_id=input.run_id,
749
- session_id=input.thread_id,
750
- runtime_type="ag-ui-duplicate",
751
- )
752
- )
753
-
754
- @staticmethod
755
- def _json_safe(value: Any) -> Any:
756
- return json.loads(json.dumps(value, ensure_ascii=False, default=str))
757
-
758
944
  async def _close_thread(self, thread_id: str, run: _ThreadRun) -> None:
759
945
  try:
760
- await self._shared.adapter.close(run.handle)
946
+ await self._shared.executor.close(run.handle)
761
947
  finally:
762
948
  async with self._shared.lock:
763
949
  if self._shared.threads.get(thread_id) is run:
764
950
  self._shared.threads.pop(thread_id, None)
765
951
 
766
952
  async def _cancel_and_close(self, thread_id: str, run: _ThreadRun) -> CancelResult:
767
- result = await self._shared.adapter.cancel(run.handle)
953
+ result = await self._shared.executor.cancel(run.handle)
768
954
  if result in {
769
955
  CancelResult.INTERRUPTED_ACTIVE_TURN,
770
956
  CancelResult.PENDING_CANCEL_RECORDED,
@@ -778,80 +964,93 @@ class KsadkAGUIAgent:
778
964
  run.active = True
779
965
  return result
780
966
 
967
+ @staticmethod
968
+ def _approval_decision_for_audit(status: str, payload: Any) -> str:
969
+ return _agent_helpers.approval_decision_for_audit(status, payload)
970
+
971
+ @staticmethod
972
+ def _durable_handle(handle: RunHandle) -> dict[str, Any]:
973
+ return _agent_helpers.durable_handle(handle)
974
+
975
+ @staticmethod
976
+ def _interrupt_from_payload(payload: Mapping[str, Any]) -> Interrupt:
977
+ return _agent_helpers.interrupt_from_payload(payload)
978
+
979
+ @staticmethod
980
+ def _interrupt_from_interaction(event: InteractionRequested) -> Interrupt:
981
+ return _agent_helpers.interrupt_from_interaction(event)
982
+
983
+ @staticmethod
984
+ def _extract_text(snapshot: ContentSnapshot | None) -> str:
985
+ return _agent_helpers.extract_text(snapshot)
986
+
987
+ @staticmethod
988
+ def _first_part(snapshot: ContentSnapshot | None) -> Any:
989
+ return _agent_helpers.first_part(snapshot)
990
+
991
+ @staticmethod
992
+ def _a2ui_operations(
993
+ event: ItemStarted | ItemUpdated | ItemCompleted,
994
+ surface_id: str,
995
+ ) -> list[dict[str, Any]]:
996
+ return _agent_helpers.a2ui_operations(event, surface_id)
997
+
998
+ @staticmethod
999
+ def _duplicate_run(input: RunAgentInput) -> _ThreadRun:
1000
+ return _agent_helpers.duplicate_run(input)
1001
+
1002
+ @staticmethod
1003
+ def _json_safe(value: Any) -> Any:
1004
+ return _agent_helpers.json_safe(value)
1005
+
781
1006
  @staticmethod
782
1007
  def _latest_user_input(input: RunAgentInput) -> Any:
783
- for message in reversed(input.messages):
784
- if getattr(message, "role", None) == "user":
785
- return getattr(message, "content", "")
786
- return ""
1008
+ return _agent_helpers.latest_user_input(input)
787
1009
 
788
1010
  @staticmethod
789
1011
  def _input_text(value: Any) -> str:
790
- if isinstance(value, str):
791
- return value.strip()
792
- if isinstance(value, Mapping):
793
- return str(value.get("text") or value.get("content") or "").strip()
794
- return str(value or "").strip()
1012
+ return _agent_helpers.input_text(value)
795
1013
 
796
1014
  @staticmethod
797
1015
  def _approval_action(detail: Mapping[str, Any]) -> Mapping[str, Any]:
798
- nested_request = detail.get("approval_requests")
799
- actions = (
800
- nested_request.get("action_requests")
801
- if isinstance(nested_request, Mapping)
802
- else detail.get("action_requests")
803
- )
804
- if isinstance(actions, list):
805
- for action in actions:
806
- if isinstance(action, Mapping):
807
- return action
808
- return {}
1016
+ return _agent_helpers.approval_action(detail)
809
1017
 
810
1018
  @staticmethod
811
1019
  def _approval_metadata(
812
1020
  detail: Mapping[str, Any],
813
1021
  payload: Mapping[str, Any],
814
1022
  ) -> dict[str, Any]:
815
- action = KsadkAGUIAgent._approval_action(detail)
816
- arguments = (
817
- action.get("args")
818
- or action.get("arguments")
819
- or detail.get("arguments")
820
- or detail.get("args")
821
- or payload.get("args")
822
- )
823
- metadata: dict[str, Any] = {
824
- "tool_name": str(
825
- action.get("name")
826
- or detail.get("tool_name")
827
- or payload.get("name")
828
- or payload.get("kind")
829
- or "approval"
830
- ),
831
- "arguments": arguments if arguments is not None else {},
832
- }
833
- approval_level = (
834
- action.get("approval_level")
835
- or detail.get("approval_level")
836
- or payload.get("approval_level")
837
- )
838
- if approval_level:
839
- metadata["approval_level"] = str(approval_level)
840
- return metadata
1023
+ return _agent_helpers.approval_metadata(detail, payload)
841
1024
 
842
1025
  @staticmethod
843
1026
  def _approval_message(detail: Mapping[str, Any], payload: Mapping[str, Any]) -> str:
844
- action = KsadkAGUIAgent._approval_action(detail)
845
- return str(
846
- action.get("description")
847
- or detail.get("message")
848
- or payload.get("message")
849
- or "Approval required"
850
- )
1027
+ return _agent_helpers.approval_message(detail, payload)
851
1028
 
852
1029
  @staticmethod
853
1030
  def _resume_fingerprint(status: str, payload: Any) -> Any:
854
- return json.dumps([status, payload], sort_keys=True, ensure_ascii=False, default=str)
1031
+ return _agent_helpers.resume_fingerprint(status, payload)
855
1032
 
856
1033
 
857
1034
  __all__ = ["KsadkAGUIAgent"]
1035
+
1036
+ def _agui_user_text(input: RunAgentInput) -> str:
1037
+ parts = []
1038
+ for message in input.messages or []:
1039
+ content = getattr(message, "content", "")
1040
+ if isinstance(content, str):
1041
+ parts.append(content)
1042
+ elif content is not None:
1043
+ parts.append(str(content))
1044
+ return "\n".join(parts)
1045
+
1046
+
1047
+ def _agui_envelope_payload(envelope) -> tuple[str, str] | None:
1048
+ """Session envelope -> AG-UI 文本投影;cursor 仍用 envelope.seq。"""
1049
+
1050
+ payload = envelope.payload or {}
1051
+ if envelope.event_type == "run.completed":
1052
+ return "completed", str(payload.get("output_text") or "")
1053
+ text = str(payload.get("delta") or payload.get("text") or "")
1054
+ if text:
1055
+ return "delta", text
1056
+ return None