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
@@ -0,0 +1,661 @@
1
+ """Single canonical reducer for live delivery and durable event replay."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from collections import OrderedDict
7
+ from dataclasses import dataclass
8
+ from typing import Literal
9
+
10
+ from pydantic import BaseModel, ConfigDict, Field, JsonValue, model_validator
11
+
12
+ from ksadk.events.canonical import (
13
+ ContextCompactionCompleted,
14
+ ContextCompactionStarted,
15
+ ContinuationCreated,
16
+ ContinuationKind,
17
+ ContinuationResumed,
18
+ ErrorInfo,
19
+ EventPhase,
20
+ InteractionKind,
21
+ InteractionRequest,
22
+ InteractionRequested,
23
+ InteractionResolved,
24
+ InteractionResponse,
25
+ ItemCompleted,
26
+ ItemFailed,
27
+ ItemKind,
28
+ ItemSnapshotReplaced,
29
+ ItemStarted,
30
+ ItemUpdated,
31
+ OutputRef,
32
+ RunCanceled,
33
+ RunCompleted,
34
+ RunFailed,
35
+ RunInterrupted,
36
+ RunProgress,
37
+ RunStarted,
38
+ RuntimeEvent,
39
+ UsageReported,
40
+ dump_runtime_event,
41
+ )
42
+ from ksadk.events.content import ContentValue, DataContent, JsonContent, TextContent
43
+
44
+ RunStatus = Literal["running", "interrupted", "completed", "failed", "canceled"]
45
+ ItemStatus = Literal["open", "completed", "failed"]
46
+ _TERMINAL_RUN_STATUSES = frozenset({"completed", "failed", "canceled"})
47
+ _RUN_STATUS_TRANSITIONS: dict[RunStatus | None, frozenset[str]] = {
48
+ None: frozenset(
49
+ {
50
+ "run.started",
51
+ "run.progress",
52
+ "run.interrupted",
53
+ "run.completed",
54
+ "run.failed",
55
+ "run.canceled",
56
+ }
57
+ ),
58
+ "running": frozenset(
59
+ {
60
+ "run.progress",
61
+ "run.interrupted",
62
+ "run.completed",
63
+ "run.failed",
64
+ "run.canceled",
65
+ }
66
+ ),
67
+ "interrupted": frozenset({"run.progress", "run.completed", "run.failed", "run.canceled"}),
68
+ "completed": frozenset(),
69
+ "failed": frozenset(),
70
+ "canceled": frozenset(),
71
+ }
72
+ _RUN_LIFECYCLE_EVENT_TYPES = _RUN_STATUS_TRANSITIONS[None]
73
+
74
+
75
+ class _ProjectionModel(BaseModel):
76
+ model_config = ConfigDict(extra="forbid")
77
+
78
+
79
+ class ItemProjection(_ProjectionModel):
80
+ scope_id: str
81
+ item_id: str
82
+ item_kind: ItemKind
83
+ phase: EventPhase | None = None
84
+ status: ItemStatus = "open"
85
+ parts: tuple[ContentValue, ...] = ()
86
+ error: ErrorInfo | None = None
87
+
88
+
89
+ class InteractionProjection(_ProjectionModel):
90
+ scope_id: str
91
+ interaction_id: str
92
+ interaction_kind: InteractionKind
93
+ status: Literal["requested", "resolved"]
94
+ request: InteractionRequest
95
+ response: InteractionResponse | None = None
96
+
97
+
98
+ class ContinuationProjection(_ProjectionModel):
99
+ scope_id: str
100
+ continuation_id: str
101
+ continuation_kind: ContinuationKind
102
+ resumable: bool
103
+ ref: dict[str, JsonValue]
104
+ resume_attempt_ids: tuple[str, ...] = ()
105
+
106
+
107
+ class ContextCompactionProjection(_ProjectionModel):
108
+ scope_id: str
109
+ trigger: str
110
+ status: Literal["started", "completed"]
111
+ compacted_until_seq: int | None = None
112
+
113
+
114
+ class UsageProjection(_ProjectionModel):
115
+ input_tokens: int = 0
116
+ output_tokens: int = 0
117
+ total_tokens: int = 0
118
+ cached_tokens: int = 0
119
+ reasoning_tokens: int = 0
120
+
121
+
122
+ class ProjectionPatch(_ProjectionModel):
123
+ event_id: str
124
+ seq: int
125
+ event_type: str
126
+ applied: bool = True
127
+ mutation: RuntimeEvent | None
128
+ reconciled: bool = False
129
+
130
+ @model_validator(mode="after")
131
+ def _mutation_matches_envelope(self) -> "ProjectionPatch":
132
+ if self.applied != (self.mutation is not None):
133
+ raise ValueError("applied patches require exactly one typed mutation")
134
+ if self.mutation is not None and (
135
+ self.event_id != self.mutation.event_id
136
+ or self.seq != self.mutation.seq
137
+ or self.event_type != self.mutation.event_type
138
+ ):
139
+ raise ValueError("patch envelope must match its typed mutation")
140
+ return self
141
+
142
+
143
+ class RunProjection(_ProjectionModel):
144
+ run_id: str | None = None
145
+ status: RunStatus | None = None
146
+ last_seq: int | None = None
147
+ items: tuple[ItemProjection, ...] = ()
148
+ output_refs: tuple[OutputRef, ...] = ()
149
+ interactions: tuple[InteractionProjection, ...] = ()
150
+ continuations: tuple[ContinuationProjection, ...] = ()
151
+ context_compactions: tuple[ContextCompactionProjection, ...] = ()
152
+ usage: UsageProjection = Field(default_factory=UsageProjection)
153
+
154
+
155
+ class StreamConformanceError(ValueError):
156
+ """Structured rejection of an invalid canonical stream transition."""
157
+
158
+ code: str
159
+ source: str
160
+ scope_id: str
161
+ item_id: str | None
162
+
163
+ def __init__(
164
+ self,
165
+ code: str,
166
+ message: str,
167
+ *,
168
+ source: str,
169
+ scope_id: str,
170
+ item_id: str | None = None,
171
+ ) -> None:
172
+ super().__init__(message)
173
+ self.code = code
174
+ self.source = source
175
+ self.scope_id = scope_id
176
+ self.item_id = item_id
177
+
178
+
179
+ @dataclass(frozen=True)
180
+ class _RecentEvent:
181
+ event_id: str
182
+ fingerprint: str
183
+
184
+
185
+ class StreamReducer:
186
+ """Reduce canonical mutations into one identity-aware run projection."""
187
+
188
+ RECENT_EVENT_LIMIT = 1024
189
+
190
+ def __init__(self) -> None:
191
+ self._run_id: str | None = None
192
+ self._status: RunStatus | None = None
193
+ self._last_seq: int | None = None
194
+ self._items: OrderedDict[tuple[str, str], ItemProjection] = OrderedDict()
195
+ self._interactions: OrderedDict[tuple[str, str], InteractionProjection] = OrderedDict()
196
+ self._continuations: OrderedDict[tuple[str, str], ContinuationProjection] = OrderedDict()
197
+ self._context_compactions: list[ContextCompactionProjection] = []
198
+ self._usage = UsageProjection()
199
+ self._output_refs: tuple[OutputRef, ...] = ()
200
+ self._recent_events: OrderedDict[int, _RecentEvent] = OrderedDict()
201
+ self._recent_event_ids: dict[str, int] = {}
202
+
203
+ @property
204
+ def recent_event_count(self) -> int:
205
+ """Number of retained event fingerprints (diagnostic state only)."""
206
+
207
+ return len(self._recent_events)
208
+
209
+ def apply(self, event: RuntimeEvent) -> ProjectionPatch:
210
+ """Apply one event or return an idempotent no-op for a recent replay."""
211
+
212
+ fingerprint = self._fingerprint(event)
213
+ duplicate = self._check_recent(event, fingerprint)
214
+ if duplicate:
215
+ return self._noop_patch(event)
216
+ if self._last_seq is not None and event.seq <= self._last_seq:
217
+ if self._status in _TERMINAL_RUN_STATUSES:
218
+ self._validate_run(event)
219
+ return self._noop_patch(event)
220
+
221
+ self._validate_run(event)
222
+ patch = self._apply_event(event)
223
+ if self._run_id is None:
224
+ self._run_id = event.run_id
225
+ self._last_seq = event.seq
226
+ self._record_recent(event, fingerprint)
227
+ return patch
228
+
229
+ def snapshot(self) -> RunProjection:
230
+ """Return a detached projection suitable for live output or replay."""
231
+
232
+ return RunProjection(
233
+ run_id=self._run_id,
234
+ status=self._status,
235
+ last_seq=self._last_seq,
236
+ items=tuple(item.model_copy(deep=True) for item in self._items.values()),
237
+ output_refs=self._output_refs,
238
+ interactions=tuple(
239
+ interaction.model_copy(deep=True) for interaction in self._interactions.values()
240
+ ),
241
+ continuations=tuple(
242
+ continuation.model_copy(deep=True) for continuation in self._continuations.values()
243
+ ),
244
+ context_compactions=tuple(
245
+ compaction.model_copy(deep=True) for compaction in self._context_compactions
246
+ ),
247
+ usage=self._usage.model_copy(deep=True),
248
+ )
249
+
250
+ def _apply_event(self, event: RuntimeEvent) -> ProjectionPatch:
251
+ if isinstance(event, (RunStarted, RunProgress)):
252
+ self._status = "running"
253
+ return self._patch(event)
254
+ if isinstance(event, RunInterrupted):
255
+ self._status = "interrupted"
256
+ return self._patch(event)
257
+ if isinstance(event, RunCompleted):
258
+ self._ensure_no_open_items(event)
259
+ self._validate_output_refs(event)
260
+ self._status = "completed"
261
+ self._output_refs = event.output_refs
262
+ return self._patch(event)
263
+ if isinstance(event, RunFailed):
264
+ self._status = "failed"
265
+ return self._patch(event)
266
+ if isinstance(event, RunCanceled):
267
+ self._status = "canceled"
268
+ return self._patch(event)
269
+ if isinstance(event, ItemStarted):
270
+ return self._start_item(event)
271
+ if isinstance(event, ItemUpdated):
272
+ return self._update_item(event)
273
+ if isinstance(event, ItemSnapshotReplaced):
274
+ return self._replace_item_snapshot(event)
275
+ if isinstance(event, ItemCompleted):
276
+ return self._complete_item(event)
277
+ if isinstance(event, ItemFailed):
278
+ return self._fail_item(event)
279
+ if isinstance(event, InteractionRequested):
280
+ return self._request_interaction(event)
281
+ if isinstance(event, InteractionResolved):
282
+ return self._resolve_interaction(event)
283
+ if isinstance(event, ContinuationCreated):
284
+ return self._create_continuation(event)
285
+ if isinstance(event, ContinuationResumed):
286
+ return self._resume_continuation(event)
287
+ if isinstance(event, ContextCompactionStarted):
288
+ projection = ContextCompactionProjection(
289
+ scope_id=event.scope_id,
290
+ trigger=event.trigger,
291
+ status="started",
292
+ )
293
+ self._context_compactions.append(projection)
294
+ return self._patch(event)
295
+ if isinstance(event, ContextCompactionCompleted):
296
+ projection = ContextCompactionProjection(
297
+ scope_id=event.scope_id,
298
+ trigger=event.trigger,
299
+ status="completed",
300
+ compacted_until_seq=event.compacted_until_seq,
301
+ )
302
+ self._context_compactions.append(projection)
303
+ return self._patch(event)
304
+ if isinstance(event, UsageReported):
305
+ self._usage = UsageProjection(
306
+ input_tokens=event.input_tokens,
307
+ output_tokens=event.output_tokens,
308
+ total_tokens=event.total_tokens,
309
+ cached_tokens=event.cached_tokens,
310
+ reasoning_tokens=event.reasoning_tokens,
311
+ )
312
+ return self._patch(event)
313
+ raise TypeError(f"unsupported runtime event: {type(event).__name__}")
314
+
315
+ def _start_item(self, event: ItemStarted) -> ProjectionPatch:
316
+ key = (event.scope_id, event.item_id)
317
+ if key in self._items:
318
+ raise self._error(
319
+ event,
320
+ "item_already_started",
321
+ f"item {event.item_id!r} was already started",
322
+ )
323
+ parts = event.initial.parts if event.initial is not None else ()
324
+ self._validate_unique_parts(event, parts)
325
+ item = ItemProjection(
326
+ scope_id=event.scope_id,
327
+ item_id=event.item_id,
328
+ item_kind=event.item_kind,
329
+ phase=event.phase,
330
+ parts=parts,
331
+ )
332
+ self._items[key] = item
333
+ return self._patch(event)
334
+
335
+ def _update_item(self, event: ItemUpdated) -> ProjectionPatch:
336
+ key, item = self._open_item(event)
337
+ parts = list(item.parts)
338
+ matching_index = next(
339
+ (index for index, part in enumerate(parts) if part.part_id == event.update.part_id),
340
+ None,
341
+ )
342
+ if event.op == "replace" or matching_index is None:
343
+ if matching_index is None:
344
+ parts.append(event.update)
345
+ else:
346
+ parts[matching_index] = event.update
347
+ else:
348
+ current = parts[matching_index]
349
+ parts[matching_index] = self._append_part(event, current, event.update)
350
+ updated = item.model_copy(update={"parts": tuple(parts)})
351
+ self._items[key] = updated
352
+ return self._patch(event)
353
+
354
+ def _replace_item_snapshot(self, event: ItemSnapshotReplaced) -> ProjectionPatch:
355
+ key, item = self._open_item(event)
356
+ self._validate_unique_parts(event, event.snapshot.parts)
357
+ reconciled = item.parts != event.snapshot.parts
358
+ self._items[key] = item.model_copy(update={"parts": event.snapshot.parts})
359
+ return self._patch(event, reconciled=reconciled)
360
+
361
+ def _complete_item(self, event: ItemCompleted) -> ProjectionPatch:
362
+ key, item = self._open_item(event)
363
+ self._validate_unique_parts(event, event.snapshot.parts)
364
+ reconciled = item.parts != event.snapshot.parts
365
+ completed = item.model_copy(update={"parts": event.snapshot.parts, "status": "completed"})
366
+ self._items[key] = completed
367
+ return self._patch(event, reconciled=reconciled)
368
+
369
+ def _fail_item(self, event: ItemFailed) -> ProjectionPatch:
370
+ key, item = self._open_item(event)
371
+ failed = item.model_copy(update={"status": "failed", "error": event.error})
372
+ self._items[key] = failed
373
+ return self._patch(event)
374
+
375
+ def _open_item(
376
+ self, event: ItemUpdated | ItemSnapshotReplaced | ItemCompleted | ItemFailed
377
+ ) -> tuple[tuple[str, str], ItemProjection]:
378
+ key = (event.scope_id, event.item_id)
379
+ item = self._items.get(key)
380
+ if item is None:
381
+ raise self._error(
382
+ event,
383
+ "item_not_started",
384
+ f"item {event.item_id!r} was not started",
385
+ )
386
+ if item.item_kind != event.item_kind:
387
+ raise self._error(
388
+ event,
389
+ "incompatible_item_kind",
390
+ f"item {event.item_id!r} changed kind from "
391
+ f"{item.item_kind!r} to {event.item_kind!r}",
392
+ )
393
+ if item.status != "open":
394
+ raise self._error(
395
+ event,
396
+ "item_already_closed",
397
+ f"item {event.item_id!r} is already closed",
398
+ )
399
+ return key, item
400
+
401
+ def _append_part(
402
+ self,
403
+ event: ItemUpdated,
404
+ current: ContentValue,
405
+ update: ContentValue,
406
+ ) -> ContentValue:
407
+ if current.content_type != update.content_type:
408
+ raise self._error(
409
+ event,
410
+ "incompatible_part_kind",
411
+ f"part {update.part_id!r} changed content type",
412
+ )
413
+ if isinstance(current, TextContent) and isinstance(update, TextContent):
414
+ return current.model_copy(update={"text": current.text + update.text})
415
+ if isinstance(current, JsonContent) and isinstance(update, JsonContent):
416
+ if isinstance(current.value, list) and isinstance(update.value, list):
417
+ return current.model_copy(update={"value": current.value + update.value})
418
+ if isinstance(current, DataContent) and isinstance(update, DataContent):
419
+ if isinstance(current.data, list) and isinstance(update.data, list):
420
+ return current.model_copy(update={"data": current.data + update.data})
421
+ raise self._error(
422
+ event,
423
+ "unsupported_part_append",
424
+ f"part {update.part_id!r} does not support append",
425
+ )
426
+
427
+ def _request_interaction(self, event: InteractionRequested) -> ProjectionPatch:
428
+ key = (event.scope_id, event.interaction_id)
429
+ if key in self._interactions:
430
+ raise self._error(
431
+ event,
432
+ "interaction_already_requested",
433
+ f"interaction {event.interaction_id!r} was already requested",
434
+ )
435
+ interaction = InteractionProjection(
436
+ scope_id=event.scope_id,
437
+ interaction_id=event.interaction_id,
438
+ interaction_kind=event.interaction_kind,
439
+ status="requested",
440
+ request=event.request,
441
+ )
442
+ self._interactions[key] = interaction
443
+ return self._patch(event)
444
+
445
+ def _resolve_interaction(self, event: InteractionResolved) -> ProjectionPatch:
446
+ key = (event.scope_id, event.interaction_id)
447
+ interaction = self._interactions.get(key)
448
+ if interaction is None:
449
+ raise self._error(
450
+ event,
451
+ "interaction_not_requested",
452
+ f"interaction {event.interaction_id!r} was not requested",
453
+ )
454
+ if interaction.status == "resolved":
455
+ raise self._error(
456
+ event,
457
+ "interaction_already_resolved",
458
+ f"interaction {event.interaction_id!r} was already resolved",
459
+ )
460
+ if interaction.interaction_kind != event.interaction_kind:
461
+ raise self._error(
462
+ event,
463
+ "incompatible_interaction_kind",
464
+ f"interaction {event.interaction_id!r} changed kind",
465
+ )
466
+ resolved = interaction.model_copy(update={"status": "resolved", "response": event.response})
467
+ self._interactions[key] = resolved
468
+ return self._patch(event)
469
+
470
+ def _create_continuation(self, event: ContinuationCreated) -> ProjectionPatch:
471
+ key = (event.scope_id, event.continuation_id)
472
+ if key in self._continuations:
473
+ raise self._error(
474
+ event,
475
+ "continuation_already_created",
476
+ f"continuation {event.continuation_id!r} was already created",
477
+ )
478
+ continuation = ContinuationProjection(
479
+ scope_id=event.scope_id,
480
+ continuation_id=event.continuation_id,
481
+ continuation_kind=event.continuation_kind,
482
+ resumable=event.resumable,
483
+ ref=event.ref,
484
+ )
485
+ self._continuations[key] = continuation
486
+ return self._patch(event)
487
+
488
+ def _resume_continuation(self, event: ContinuationResumed) -> ProjectionPatch:
489
+ key = (event.scope_id, event.continuation_id)
490
+ continuation = self._continuations.get(key)
491
+ if continuation is None:
492
+ raise self._error(
493
+ event,
494
+ "continuation_not_created",
495
+ f"continuation {event.continuation_id!r} was not created",
496
+ )
497
+ if continuation.continuation_kind != event.continuation_kind:
498
+ raise self._error(
499
+ event,
500
+ "incompatible_continuation_kind",
501
+ f"continuation {event.continuation_id!r} changed kind",
502
+ )
503
+ resumed = continuation.model_copy(
504
+ update={
505
+ "resume_attempt_ids": continuation.resume_attempt_ids + (event.resume_attempt_id,)
506
+ }
507
+ )
508
+ self._continuations[key] = resumed
509
+ return self._patch(event)
510
+
511
+ def _ensure_no_open_items(self, event: RunCompleted) -> None:
512
+ open_item = next((item for item in self._items.values() if item.status == "open"), None)
513
+ if open_item is not None:
514
+ raise self._error(
515
+ event,
516
+ "run_completed_with_open_items",
517
+ "run cannot complete while items remain open",
518
+ item_id=open_item.item_id,
519
+ )
520
+
521
+ def _validate_output_refs(self, event: RunCompleted) -> None:
522
+ for ref in event.output_refs:
523
+ item = self._items.get((ref.scope_id, ref.item_id))
524
+ if item is None or item.status != "completed":
525
+ raise self._error(
526
+ event,
527
+ "invalid_output_ref",
528
+ f"output item {ref.item_id!r} is not completed",
529
+ item_id=ref.item_id,
530
+ )
531
+ if ref.part_id is not None and all(part.part_id != ref.part_id for part in item.parts):
532
+ raise self._error(
533
+ event,
534
+ "invalid_output_ref",
535
+ f"output part {ref.part_id!r} does not exist",
536
+ item_id=ref.item_id,
537
+ )
538
+
539
+ def _validate_unique_parts(
540
+ self,
541
+ event: ItemStarted | ItemSnapshotReplaced | ItemCompleted,
542
+ parts: tuple[ContentValue, ...],
543
+ ) -> None:
544
+ part_ids = [part.part_id for part in parts]
545
+ if len(set(part_ids)) != len(part_ids):
546
+ raise self._error(
547
+ event,
548
+ "duplicate_part_id",
549
+ f"item {event.item_id!r} contains duplicate part ids",
550
+ )
551
+
552
+ def _validate_run(self, event: RuntimeEvent) -> None:
553
+ if self._run_id is not None and self._run_id != event.run_id:
554
+ raise self._error(
555
+ event,
556
+ "incompatible_run_id",
557
+ f"reducer belongs to run {self._run_id!r}, not {event.run_id!r}",
558
+ )
559
+ if self._status in _TERMINAL_RUN_STATUSES:
560
+ raise self._error(
561
+ event,
562
+ "run_already_terminal",
563
+ f"run is already terminal with status {self._status!r}",
564
+ )
565
+ if (
566
+ event.event_type in _RUN_LIFECYCLE_EVENT_TYPES
567
+ and event.event_type not in _RUN_STATUS_TRANSITIONS[self._status]
568
+ ):
569
+ raise self._error(
570
+ event,
571
+ "invalid_run_transition",
572
+ f"event {event.event_type!r} is invalid after status {self._status!r}",
573
+ )
574
+
575
+ def _check_recent(self, event: RuntimeEvent, fingerprint: str) -> bool:
576
+ same_seq = self._recent_events.get(event.seq)
577
+ if same_seq is not None:
578
+ if same_seq.event_id == event.event_id and same_seq.fingerprint == fingerprint:
579
+ return True
580
+ raise self._error(
581
+ event,
582
+ "conflicting_seq",
583
+ f"seq {event.seq} was reused with different content",
584
+ )
585
+ existing_seq = self._recent_event_ids.get(event.event_id)
586
+ if existing_seq is not None:
587
+ existing = self._recent_events[existing_seq]
588
+ if existing.fingerprint == fingerprint:
589
+ return True
590
+ raise self._error(
591
+ event,
592
+ "conflicting_event_id",
593
+ f"event_id {event.event_id!r} was reused with different content",
594
+ )
595
+ return False
596
+
597
+ def _record_recent(self, event: RuntimeEvent, fingerprint: str) -> None:
598
+ self._recent_events[event.seq] = _RecentEvent(event.event_id, fingerprint)
599
+ self._recent_event_ids[event.event_id] = event.seq
600
+ while len(self._recent_events) > self.RECENT_EVENT_LIMIT:
601
+ old_seq, old = self._recent_events.popitem(last=False)
602
+ if self._recent_event_ids.get(old.event_id) == old_seq:
603
+ del self._recent_event_ids[old.event_id]
604
+
605
+ @staticmethod
606
+ def _fingerprint(event: RuntimeEvent) -> str:
607
+ return json.dumps(
608
+ dump_runtime_event(event),
609
+ ensure_ascii=False,
610
+ separators=(",", ":"),
611
+ sort_keys=True,
612
+ )
613
+
614
+ @staticmethod
615
+ def _patch(event: RuntimeEvent, *, reconciled: bool = False) -> ProjectionPatch:
616
+ return ProjectionPatch(
617
+ event_id=event.event_id,
618
+ seq=event.seq,
619
+ event_type=event.event_type,
620
+ mutation=event,
621
+ reconciled=reconciled,
622
+ )
623
+
624
+ @staticmethod
625
+ def _noop_patch(event: RuntimeEvent) -> ProjectionPatch:
626
+ return ProjectionPatch(
627
+ event_id=event.event_id,
628
+ seq=event.seq,
629
+ event_type=event.event_type,
630
+ applied=False,
631
+ mutation=None,
632
+ )
633
+
634
+ @staticmethod
635
+ def _error(
636
+ event: RuntimeEvent,
637
+ code: str,
638
+ message: str,
639
+ *,
640
+ item_id: str | None = None,
641
+ ) -> StreamConformanceError:
642
+ return StreamConformanceError(
643
+ code,
644
+ message,
645
+ source=event.source.framework,
646
+ scope_id=event.scope_id,
647
+ item_id=item_id if item_id is not None else getattr(event, "item_id", None),
648
+ )
649
+
650
+
651
+ __all__ = [
652
+ "ContextCompactionProjection",
653
+ "ContinuationProjection",
654
+ "InteractionProjection",
655
+ "ItemProjection",
656
+ "ProjectionPatch",
657
+ "RunProjection",
658
+ "StreamConformanceError",
659
+ "StreamReducer",
660
+ "UsageProjection",
661
+ ]
ksadk/events/replay.py CHANGED
@@ -1,37 +1,4 @@
1
- """历史 replay — 基于 session 级 cursor 的跨 invocation 回放 (goal-12)。
1
+ """Public canonical replay and temporary mixed-schema read boundary."""
2
2
 
3
- replay 与 live 渲染**共用** :class:`~ksadk.events.parser.RuntimeEventParser`(单实现),
4
- 回放只是"从 store 按 cursor 读事件、喂同一个 parser"。因此 live 与 replay 不可能漂移
5
- (H2 高风险项),由 conformance fixture 逐字节断言兜底。
6
- """
7
-
8
- from __future__ import annotations
9
-
10
- from typing import Optional
11
-
12
- from ksadk.events.parser import RuntimeEventParser
13
- from ksadk.events.store import RuntimeEventStore
14
-
15
-
16
- async def replay_transcript(
17
- store: RuntimeEventStore,
18
- session_id: str,
19
- *,
20
- after_seq_id: int = 0,
21
- before_seq_id: Optional[int] = None,
22
- parser: Optional[RuntimeEventParser] = None,
23
- ) -> RuntimeEventParser:
24
- """跨 invocation 历史回放:按 session cursor 读事件,经共享 parser 折叠成 transcript。
25
-
26
- 与 live 渲染同一条 parser 路径——live 是"事件边来边 feed",replay 是"从 store 读完
27
- 再 feed 同一个 parser",产物逐字节一致(conformance fixture 证明)。
28
- """
29
- parser = parser or RuntimeEventParser()
30
- events = await store.list(session_id, after_seq_id=after_seq_id, before_seq_id=before_seq_id)
31
- for event in events:
32
- event.validate_conformance()
33
- parser.feed(event)
34
- return parser
35
-
36
-
37
- __all__ = ["replay_transcript"]
3
+ from ksadk.events.canonical_replay import * # noqa: F403
4
+ from ksadk.events.canonical_replay import __all__