agentengine-sdk-python 0.8.1__py3-none-any.whl → 0.8.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (411) hide show
  1. {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.2.dist-info}/METADATA +22 -2
  2. {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.2.dist-info}/RECORD +356 -222
  3. ksadk/a2a/_space_client_events.py +381 -0
  4. ksadk/a2a/event_adapter.py +156 -64
  5. ksadk/a2a/executor.py +179 -63
  6. ksadk/a2a/space_client.py +6 -333
  7. ksadk/a2ui/core.py +222 -53
  8. ksadk/agui/_agent_helpers.py +243 -0
  9. ksadk/agui/a2ui_projection.py +12 -5
  10. ksadk/agui/agent.py +443 -259
  11. ksadk/api/client.py +525 -27
  12. ksadk/builders/code_builder.py +284 -8
  13. ksadk/builders/container_builder.py +8 -1
  14. ksadk/builders/managed_runtime_builder.py +39 -35
  15. ksadk/cli/__init__.py +17 -0
  16. ksadk/cli/cmd_dashboard.py +15 -1
  17. ksadk/cli/cmd_deploy.py +10 -2
  18. ksadk/cli/cmd_eval.py +66 -9
  19. ksadk/cli/cmd_evalset.py +284 -0
  20. ksadk/cli/cmd_files.py +5 -1
  21. ksadk/cli/cmd_hermes.py +1 -126
  22. ksadk/cli/cmd_invoke.py +28 -38
  23. ksadk/cli/cmd_managed_runtime.py +95 -0
  24. ksadk/cli/cmd_observe.py +85 -0
  25. ksadk/cli/cmd_openclaw.py +1 -435
  26. ksadk/cli/cmd_replay.py +28 -4
  27. ksadk/cli/cmd_studio.py +99 -8
  28. ksadk/cli/cmd_web.py +10 -2
  29. ksadk/cli/hermes_env.py +151 -0
  30. ksadk/cli/invoke_payload.py +49 -0
  31. ksadk/cli/openclaw_env.py +458 -0
  32. ksadk/codex/client.py +180 -30
  33. ksadk/codex/runtime.py +428 -326
  34. ksadk/configs/env_registry.py +66 -12
  35. ksadk/configs/env_registry_pcm.py +181 -0
  36. ksadk/configs/env_var_spec.py +18 -0
  37. ksadk/configs/global_config.py +5 -0
  38. ksadk/context_engine/__init__.py +98 -0
  39. ksadk/context_engine/assembler.py +176 -0
  40. ksadk/context_engine/baseline.py +419 -0
  41. ksadk/context_engine/cache_observability.py +228 -0
  42. ksadk/context_engine/capabilities.py +443 -0
  43. ksadk/context_engine/contributors.py +344 -0
  44. ksadk/context_engine/hosted_pipeline.py +417 -0
  45. ksadk/context_engine/models.py +117 -0
  46. ksadk/context_engine/planner.py +698 -0
  47. ksadk/context_engine/policies.py +319 -0
  48. ksadk/context_engine/projection.py +31 -0
  49. ksadk/context_engine/shadow_plan.py +266 -0
  50. ksadk/context_engine/tokenizer.py +164 -0
  51. ksadk/conversations/context.py +126 -6
  52. ksadk/conversations/message_projection.py +292 -28
  53. ksadk/conversations/model_context.py +49 -3
  54. ksadk/conversations/runtime_compaction.py +207 -5
  55. ksadk/conversations/runtime_input.py +184 -2
  56. ksadk/conversations/runtime_invocation.py +81 -3
  57. ksadk/conversations/runtime_observability.py +141 -0
  58. ksadk/conversations/runtime_payloads.py +42 -0
  59. ksadk/conversations/runtime_preparation.py +272 -2
  60. ksadk/conversations/runtime_resume.py +20 -1
  61. ksadk/conversations/runtime_stream_events.py +94 -9
  62. ksadk/conversations/semantic_summary.py +311 -1
  63. ksadk/conversations/session_lock.py +51 -0
  64. ksadk/deployment/env_forward.py +72 -0
  65. ksadk/deployment/managed_runtime.py +5 -0
  66. ksadk/deployment/providers/serverless.py +143 -69
  67. ksadk/evaluation/__init__.py +32 -0
  68. ksadk/evaluation/a2a_adapter.py +9 -1
  69. ksadk/evaluation/adapters.py +18 -5
  70. ksadk/evaluation/agent_eval_client.py +395 -0
  71. ksadk/evaluation/cloud_binding.py +80 -0
  72. ksadk/evaluation/cloud_converter.py +194 -0
  73. ksadk/evaluation/cloud_service.py +199 -0
  74. ksadk/evaluation/contracts.py +73 -4
  75. ksadk/evaluation/evaluators.py +183 -17
  76. ksadk/evaluation/evidence.py +258 -0
  77. ksadk/evaluation/executor.py +31 -6
  78. ksadk/evaluation/local_adapter.py +550 -0
  79. ksadk/evaluation/service_env.py +27 -0
  80. ksadk/evaluation/studio_build_adapter.py +253 -0
  81. ksadk/evaluation/target.py +15 -6
  82. ksadk/events/__init__.py +13 -13
  83. ksadk/events/_v1_compat/__init__.py +1 -0
  84. ksadk/events/_v1_compat/models.py +299 -0
  85. ksadk/events/_v1_compat/parser.py +247 -0
  86. ksadk/events/_v1_compat/projection.py +753 -0
  87. ksadk/events/adapters/__init__.py +34 -0
  88. ksadk/events/adapters/_a2a_snapshot.py +622 -0
  89. ksadk/events/adapters/_a2a_support.py +275 -0
  90. ksadk/events/adapters/_codex_interactions.py +375 -0
  91. ksadk/events/adapters/_codex_items.py +801 -0
  92. ksadk/events/adapters/_codex_validators.py +311 -0
  93. ksadk/events/adapters/_langgraph_support.py +785 -0
  94. ksadk/events/adapters/a2a.py +841 -0
  95. ksadk/events/adapters/adk.py +503 -0
  96. ksadk/events/adapters/codex.py +717 -0
  97. ksadk/events/adapters/langgraph.py +745 -0
  98. ksadk/events/canonical.py +440 -0
  99. ksadk/events/canonical_replay.py +497 -0
  100. ksadk/events/canonical_store.py +468 -0
  101. ksadk/events/cold_recovery.py +257 -0
  102. ksadk/events/content.py +89 -0
  103. ksadk/events/identity.py +86 -0
  104. ksadk/events/pipeline.py +455 -0
  105. ksadk/events/projections.py +66 -0
  106. ksadk/events/reducer.py +661 -0
  107. ksadk/events/replay.py +3 -36
  108. ksadk/events/runtime_event.py +20 -265
  109. ksadk/events/session_event.py +324 -0
  110. ksadk/events/store.py +3 -316
  111. ksadk/events/v1_compat.py +41 -0
  112. ksadk/harness/runtime.py +160 -57
  113. ksadk/identity/resolver.py +4 -3
  114. ksadk/interaction/__init__.py +28 -0
  115. ksadk/interaction/contracts.py +136 -0
  116. ksadk/interaction/ledger.py +189 -0
  117. ksadk/interaction/provider.py +122 -0
  118. ksadk/interaction/providers/__init__.py +52 -0
  119. ksadk/interaction/providers/adk.py +40 -0
  120. ksadk/interaction/providers/codex.py +94 -0
  121. ksadk/interaction/providers/langgraph.py +58 -0
  122. ksadk/kernel/__init__.py +117 -0
  123. ksadk/kernel/authorization.py +258 -0
  124. ksadk/kernel/bootstrap.py +1074 -0
  125. ksadk/kernel/contract_fingerprints.py +61 -0
  126. ksadk/kernel/contracts.py +362 -0
  127. ksadk/kernel/control.py +219 -0
  128. ksadk/kernel/errors.py +79 -0
  129. ksadk/kernel/ingress.py +1102 -0
  130. ksadk/kernel/mapping.py +111 -0
  131. ksadk/kernel/memory_store.py +1133 -0
  132. ksadk/kernel/postgres_store.py +1756 -0
  133. ksadk/kernel/recovery.py +452 -0
  134. ksadk/kernel/runtime_identity.py +103 -0
  135. ksadk/kernel/sql/001_agent_kernel.sql +120 -0
  136. ksadk/kernel/sqlite_store.py +1410 -0
  137. ksadk/kernel/state.py +145 -0
  138. ksadk/kernel/store.py +232 -0
  139. ksadk/kernel/worker.py +953 -0
  140. ksadk/knowledge_base/client.py +7 -0
  141. ksadk/knowledge_base/service.py +32 -5
  142. ksadk/memory/__init__.py +61 -0
  143. ksadk/memory/adk/backends/base_ltm_backend.py +96 -1
  144. ksadk/memory/adk/backends/http_ltm_backend.py +14 -5
  145. ksadk/memory/adk/backends/inmemory_ltm_backend.py +136 -3
  146. ksadk/memory/adk/backends/sdk_ltm_backend.py +384 -2
  147. ksadk/memory/adk/backends/sqlite_ltm_backend.py +95 -0
  148. ksadk/memory/coordinator.py +461 -0
  149. ksadk/memory/events.py +202 -0
  150. ksadk/memory/extraction.py +228 -0
  151. ksadk/memory/ltm_backend_factory.py +16 -3
  152. ksadk/memory/models.py +316 -0
  153. ksadk/memory/policy.py +215 -0
  154. ksadk/memory/provider.py +47 -0
  155. ksadk/memory/provider_adapter.py +159 -0
  156. ksadk/memory/provider_resolver.py +71 -0
  157. ksadk/memory/providers/__init__.py +5 -0
  158. ksadk/memory/providers/local_sqlite.py +490 -0
  159. ksadk/memory/resolved_policy.py +145 -0
  160. ksadk/memory/service.py +188 -6
  161. ksadk/model_proxy/bootstrap.py +16 -9
  162. ksadk/model_proxy/detect.py +202 -9
  163. ksadk/model_proxy/namespace.py +39 -15
  164. ksadk/model_proxy/server.py +24 -5
  165. ksadk/model_proxy/transform.py +60 -2
  166. ksadk/observability/__init__.py +25 -0
  167. ksadk/observability/session_log.py +420 -0
  168. ksadk/observability/trajectory.py +105 -0
  169. ksadk/prompts/__init__.py +71 -0
  170. ksadk/prompts/compiler.py +215 -0
  171. ksadk/prompts/models.py +82 -0
  172. ksadk/prompts/projection.py +89 -0
  173. ksadk/prompts/resolved.py +137 -0
  174. ksadk/prompts/sources.py +233 -0
  175. ksadk/runners/_langgraph_runner_streams.py +822 -0
  176. ksadk/runners/adk_runner.py +5 -5
  177. ksadk/runners/base_runner.py +16 -0
  178. ksadk/runners/factory.py +1 -2
  179. ksadk/runners/langgraph_runner.py +198 -437
  180. ksadk/runtime/_runner_adapter/__init__.py +1 -0
  181. ksadk/runtime/_runner_adapter/stream_mapping.py +788 -0
  182. ksadk/runtime/adapter.py +118 -2
  183. ksadk/runtime/conversation_execution.py +316 -182
  184. ksadk/runtime/executor.py +144 -3
  185. ksadk/runtime/factory.py +193 -7
  186. ksadk/runtime/hosted_finalizer.py +268 -0
  187. ksadk/runtime/launch.py +14 -1
  188. ksadk/runtime/preprocessing.py +25 -3
  189. ksadk/runtime/runner_adapter.py +288 -508
  190. ksadk/runtime/usage.py +33 -0
  191. ksadk/sandbox/backends/e2b.py +35 -2
  192. ksadk/server/composition.py +8 -0
  193. ksadk/server/factory.py +69 -6
  194. ksadk/server/routes/kernel_ingress.py +258 -0
  195. ksadk/server/routes/openai_compat.py +88 -8
  196. ksadk/server/routes/projection.py +35 -20
  197. ksadk/server/routes/run.py +94 -0
  198. ksadk/server/routes/sessions.py +2 -0
  199. ksadk/server/routes/streaming.py +5 -2
  200. ksadk/server/static/assets/{ArtifactsPanel-CakCqxEN.js → ArtifactsPanel-DSU1sWD_.js} +1 -1
  201. ksadk/server/static/assets/{CodeBlock-CynLknyO.js → CodeBlock-DOH6MVcn.js} +4 -4
  202. ksadk/server/static/assets/{MathMessageMarkdown-3sQdOysS.js → MathMessageMarkdown-BL8my1R2.js} +4 -4
  203. ksadk/server/static/assets/MathMessageMarkdown-BorAY7qD.css +1 -0
  204. ksadk/server/static/assets/MermaidBlock-Dz4IP-Tx.js +312 -0
  205. ksadk/server/static/assets/NativeTerminalPanel-DUrK0JpZ.js +1 -0
  206. ksadk/server/static/assets/abnfDiagram-VCTEODGH-g20pFzNV.js +1 -0
  207. ksadk/server/static/assets/arc-C4FzinUA.js +1 -0
  208. ksadk/server/static/assets/architecture-7GRP2DOG-DjKratdf.js +1 -0
  209. ksadk/server/static/assets/architectureDiagram-5GKGNRK7-DpIqL5h4.js +36 -0
  210. ksadk/server/static/assets/blockDiagram-NRAW4CY4-BjkljTNz.js +129 -0
  211. ksadk/server/static/assets/c4Diagram-UCG6FXSJ-Dk_ieq2X.js +38 -0
  212. ksadk/server/static/assets/channel-4cQHKtx1.js +1 -0
  213. ksadk/server/static/assets/chunk-2Q5K7J3B-DmgWkESh.js +1 -0
  214. ksadk/server/static/assets/{chunk-FMBD7UC4-B_fH2YuH.js → chunk-5VM5RSS4-BVHAchFb.js} +1 -1
  215. ksadk/server/static/assets/{chunk-ND2GUHAM-D6rFLaVV.js → chunk-F27PBJKO-C-ipQzuS.js} +1 -1
  216. ksadk/server/static/assets/chunk-G27WJ6UU-C2EyJbIK.js +231 -0
  217. ksadk/server/static/assets/{chunk-4BX2VUAB-B9drTgOW.js → chunk-JWPE2WC7-vYvVJb_M.js} +1 -1
  218. ksadk/server/static/assets/chunk-LCL6LL3I-BcI6ysPT.js +206 -0
  219. ksadk/server/static/assets/chunk-POPQ4Y6H-C030x_Z1.js +1 -0
  220. ksadk/server/static/assets/chunk-RHFEMEQ7-yyGpsz4n.js +168 -0
  221. ksadk/server/static/assets/chunk-SVP7TREG-BLTlmMU7.js +88 -0
  222. ksadk/server/static/assets/chunk-XXDRQBXY-C_32ArgP.js +1 -0
  223. ksadk/server/static/assets/classDiagram-DTDB5LWJ-DLFd9Xi0.js +1 -0
  224. ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-DLFd9Xi0.js +1 -0
  225. ksadk/server/static/assets/{cose-bilkent-S5V4N54A-ChNs_Mdk.js → cose-bilkent-JH36ORCC-9YQYwdl0.js} +1 -1
  226. ksadk/server/static/assets/cynefin-OW5HDTMX-DjEM48Qp.js +1 -0
  227. ksadk/server/static/assets/cynefinDiagram-5FMLGOSQ-ErLF5N13.js +62 -0
  228. ksadk/server/static/assets/cytoscape.esm-CyCl8rPi.js +321 -0
  229. ksadk/server/static/assets/dagre-3AP2YEHR-DFiQF-6f.js +4 -0
  230. ksadk/server/static/assets/dagre-BuhGnRI1.js +1 -0
  231. ksadk/server/static/assets/diagram-S7CK7UJ4-Bt1v8-GC.js +30 -0
  232. ksadk/server/static/assets/diagram-UQ7AKVKN-DSCxJdBK.js +41 -0
  233. ksadk/server/static/assets/diagram-VSXAHHWV-DHfYwp_9.js +3 -0
  234. ksadk/server/static/assets/diagram-VX7I27RA-DdzD-4Le.js +24 -0
  235. ksadk/server/static/assets/diagram-Z3DM3KII-Du-nAJ9F.js +24 -0
  236. ksadk/server/static/assets/{dist-Dli7qW-B.js → dist-8hqcx0sU.js} +1 -1
  237. ksadk/server/static/assets/dist-B7seoj3d.js +1 -0
  238. ksadk/server/static/assets/{dist-C1sz5Eo3.js → dist-BE7bu-DL.js} +1 -1
  239. ksadk/server/static/assets/{dist-fhOuWds5.js → dist-BVDffZ0U.js} +1 -1
  240. ksadk/server/static/assets/{dist-BjOdlDjj.js → dist-BX8z72IC.js} +1 -1
  241. ksadk/server/static/assets/{dist-DsHPdk3W.js → dist-Bf2M8m3N.js} +1 -1
  242. ksadk/server/static/assets/{dist-o2OVmKvt.js → dist-BjU6y-A2.js} +1 -1
  243. ksadk/server/static/assets/{dist-DWKByxWV.js → dist-BytlxIDT.js} +1 -1
  244. ksadk/server/static/assets/{dist-DJN_6Y39.js → dist-CSh_DE14.js} +1 -1
  245. ksadk/server/static/assets/{dist-DQU9EWw-.js → dist-CXYYBw3_.js} +1 -1
  246. ksadk/server/static/assets/{dist-4N2NMVYg.js → dist-C_wsv-Qd.js} +1 -1
  247. ksadk/server/static/assets/{dist-gLnrGsoU.js → dist-ClxGviKw.js} +1 -1
  248. ksadk/server/static/assets/{dist-j6Dxmf_j.js → dist-CttYUqzS.js} +1 -1
  249. ksadk/server/static/assets/{dist-D6MpCZtz.js → dist-DNp6rLRA.js} +1 -1
  250. ksadk/server/static/assets/{dist-BB3-OwTQ.js → dist-DUX-id_F.js} +1 -1
  251. ksadk/server/static/assets/{dist-_pHPTyZ-.js → dist-DmldrHd_.js} +1 -1
  252. ksadk/server/static/assets/{dist-CWV4lDr1.js → dist-DnfXs8Vn.js} +2 -2
  253. ksadk/server/static/assets/{dist-B5oS1zcj.js → dist-Dq9gLD7L.js} +1 -1
  254. ksadk/server/static/assets/{dist-B-jNR6Vn.js → dist-W-TIVntx.js} +1 -1
  255. ksadk/server/static/assets/{dist-BIlKoW0k.js → dist-dDdADKFA.js} +1 -1
  256. ksadk/server/static/assets/{dist-X4TnqwOK.js → dist-dydu68Fl.js} +1 -1
  257. ksadk/server/static/assets/{dist-CmZHzlwZ.js → dist-ngtN0DJB.js} +1 -1
  258. ksadk/server/static/assets/ebnfDiagram-PWID7BFC-Da9C9NO1.js +1 -0
  259. ksadk/server/static/assets/erDiagram-SSCWMZ5O-EAGqqR79.js +99 -0
  260. ksadk/server/static/assets/eventmodeling-NTZA5JFV-CMgMaJrC.js +1 -0
  261. ksadk/server/static/assets/flowDiagram-A5DVABFB-BBKL0x3P.js +1 -0
  262. ksadk/server/static/assets/ganttDiagram-EL5Y4UJY-DqJsKb59.js +292 -0
  263. ksadk/server/static/assets/gitGraph-4MIJSDKK-Dw63mrhw.js +1 -0
  264. ksadk/server/static/assets/gitGraphDiagram-WWUBYQGX-B6g4dtDi.js +106 -0
  265. ksadk/server/static/assets/index-8ipRcQ-M.js +240 -0
  266. ksadk/server/static/assets/index-ByFCqjlh.css +2 -0
  267. ksadk/server/static/assets/info-A6RAGUB7-B6iAblII.js +1 -0
  268. ksadk/server/static/assets/infoDiagram-RXCK75RN-Djm_nbd5.js +2 -0
  269. ksadk/server/static/assets/{ishikawaDiagram-YF4QCWOH-K0OOfVna.js → ishikawaDiagram-5VMMS53U-DWya9SG2.js} +6 -6
  270. ksadk/server/static/assets/{journeyDiagram-JHISSGLW-8LeOJaZp.js → journeyDiagram-EYS64GPL-DutxhSNI.js} +6 -6
  271. ksadk/server/static/assets/{kanban-definition-UN3LZRKU-C6uCgZrW.js → kanban-definition-3QL26DDD-DJdOF8Fm.js} +10 -10
  272. ksadk/server/static/assets/katex-vFWytM5c.js +257 -0
  273. ksadk/server/static/assets/{linear-hdBcYzM8.js → linear-BHjG8b-J.js} +1 -1
  274. ksadk/server/static/assets/mermaid-parser.core-KGSy4jWT.js +166 -0
  275. ksadk/server/static/assets/{mindmap-definition-RKZ34NQL-Bjy_2v4_.js → mindmap-definition-FBJOCRG2-9-HC88D4.js} +29 -29
  276. ksadk/server/static/assets/packet-AYTQ26CC-BOYAipuq.js +1 -0
  277. ksadk/server/static/assets/pegDiagram-XKGWAZYB-DrEZd4fD.js +1 -0
  278. ksadk/server/static/assets/pie-WAS4IAKB-Ctq0Kbku.js +1 -0
  279. ksadk/server/static/assets/pieDiagram-E7YTZNPT-DpjqOFFp.js +39 -0
  280. ksadk/server/static/assets/{quadrantDiagram-W4KKPZXB-BmkRbwCg.js → quadrantDiagram-AXDQQJYC-BiNhgOXX.js} +6 -6
  281. ksadk/server/static/assets/radar-RG4KPBEZ-DN0-ul_0.js +1 -0
  282. ksadk/server/static/assets/railroad-74A4TZTK-C6cC_to0.js +1 -0
  283. ksadk/server/static/assets/railroad-abnf-HS5TGJTU-BimjIuRc.js +1 -0
  284. ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-CvY65ABq.js +1 -0
  285. ksadk/server/static/assets/railroad-peg-WCYAUIDC-D72Iq_Tv.js +1 -0
  286. ksadk/server/static/assets/railroadDiagram-O6MQD6OU-_Y3Ojg6G.js +1 -0
  287. ksadk/server/static/assets/requirementDiagram-EFPCY7ZU-DeCFdg9K.js +84 -0
  288. ksadk/server/static/assets/{sankeyDiagram-5OEKKPKP-l6iXmU65.js → sankeyDiagram-P5KCCOFB-CPH75rhw.js} +7 -7
  289. ksadk/server/static/assets/{sequenceDiagram-3UESZ5HK-Cq6UBeQB.js → sequenceDiagram-WJ2MYXX4-OEpQQdr4.js} +10 -10
  290. ksadk/server/static/assets/sizeCapture-X5ZJPWSS-heUErzhI.js +1 -0
  291. ksadk/server/static/assets/stateDiagram-HBIQ2CUA-DvA3jSMB.js +1 -0
  292. ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-BgQY03nz.js +1 -0
  293. ksadk/server/static/assets/swimlanes-XN3QIQJK-CR-dfN_t.js +1 -0
  294. ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-DLVw3q5Q.js +8 -0
  295. ksadk/server/static/assets/{timeline-definition-PNZ67QCA-DEz24vV0.js → timeline-definition-24CTP7MA-DAVJf1TX.js} +7 -7
  296. ksadk/server/static/assets/treeView-Q6P3EWNA-BMpO0wsB.js +1 -0
  297. ksadk/server/static/assets/treemap-WGGIJYW6-Et0aqzU3.js +1 -0
  298. ksadk/server/static/assets/vennDiagram-4TSXK5OY-DwM8eDkh.js +34 -0
  299. ksadk/server/static/assets/wardley-WFR3VGLG-CbY0mhpl.js +1 -0
  300. ksadk/server/static/assets/wardleyDiagram-VM6X3IG4-DZL-Zz2t.js +78 -0
  301. ksadk/server/static/assets/xychartDiagram-S5SC5T6Z-Dy6Yh_hu.js +7 -0
  302. ksadk/server/static/index.html +2 -2
  303. ksadk/sessions/__init__.py +26 -9
  304. ksadk/sessions/_local_service_sync.py +688 -0
  305. ksadk/sessions/_local_tables.py +21 -0
  306. ksadk/sessions/_postgres_schema.py +305 -0
  307. ksadk/sessions/_postgres_tables.py +15 -0
  308. ksadk/sessions/base.py +80 -1
  309. ksadk/sessions/in_memory.py +53 -2
  310. ksadk/sessions/local_service.py +63 -604
  311. ksadk/sessions/postgres_service.py +58 -148
  312. ksadk/sessions/resilient.py +35 -1
  313. ksadk/studio/api.py +577 -25
  314. ksadk/studio/api_contracts.py +114 -5
  315. ksadk/studio/api_memory_routes.py +82 -0
  316. ksadk/studio/authoring.py +252 -27
  317. ksadk/studio/authoring_coordinator.py +799 -67
  318. ksadk/studio/builder.py +88 -11
  319. ksadk/studio/capabilities.py +17 -0
  320. ksadk/studio/cloud.py +1916 -95
  321. ksadk/studio/codex_agent_service.py +125 -14
  322. ksadk/studio/codex_authoring.py +469 -0
  323. ksadk/studio/codex_builder.py +138 -25
  324. ksadk/studio/codex_manifest.py +51 -22
  325. ksadk/studio/codex_run.py +46 -3
  326. ksadk/studio/compiler.py +1 -0
  327. ksadk/studio/contracts.py +114 -3
  328. ksadk/studio/event_store.py +25 -95
  329. ksadk/studio/framework_run.py +231 -3
  330. ksadk/studio/hosted_kernel.py +317 -0
  331. ksadk/studio/manifest_resolver.py +131 -0
  332. ksadk/studio/model_client.py +95 -9
  333. ksadk/studio/model_profile_service.py +1 -1
  334. ksadk/studio/operations.py +37 -5
  335. ksadk/studio/otel_trace.py +348 -42
  336. ksadk/studio/pcm_memory.py +85 -0
  337. ksadk/studio/repository.py +23 -2
  338. ksadk/studio/resource_catalog.py +43 -0
  339. ksadk/studio/run_service.py +563 -137
  340. ksadk/studio/runtime_source.py +42 -16
  341. ksadk/studio/service.py +1180 -72
  342. ksadk/studio/shared_web.py +32 -22
  343. ksadk/studio/static/assets/index-BLpcdrgW.css +1 -0
  344. ksadk/studio/static/assets/index-CYekR2Xv.js +260 -0
  345. ksadk/studio/static/index.html +2 -2
  346. ksadk/studio/templates.py +100 -8
  347. ksadk/studio/validator.py +19 -0
  348. ksadk/studio/workspace.py +30 -32
  349. ksadk/tracing/setup.py +304 -3
  350. ksadk/version.py +1 -1
  351. ksadk_runtime_common/schemas/runtime_event_v1.json +37 -0
  352. ksadk_runtime_common/schemas/runtime_event_v2.json +271 -0
  353. ksadk/events/parser.py +0 -191
  354. ksadk/server/static/assets/MathMessageMarkdown-DeYh8QPr.css +0 -1
  355. ksadk/server/static/assets/MermaidBlock-NERD_ef7.js +0 -303
  356. ksadk/server/static/assets/NativeTerminalPanel-CiHWf82q.js +0 -1
  357. ksadk/server/static/assets/arc-DrgjcKhl.js +0 -1
  358. ksadk/server/static/assets/architecture-7EHR7CIX-CpZLRCcY.js +0 -1
  359. ksadk/server/static/assets/architectureDiagram-3BPJPVTR-BXoVRbQ6.js +0 -36
  360. ksadk/server/static/assets/blockDiagram-GPEHLZMM-BnaB3Ywv.js +0 -132
  361. ksadk/server/static/assets/c4Diagram-AAUBKEIU-Dw4weZcp.js +0 -10
  362. ksadk/server/static/assets/channel-Dt3rQTFI.js +0 -1
  363. ksadk/server/static/assets/chunk-2J33WTMH-ChjpLK7j.js +0 -1
  364. ksadk/server/static/assets/chunk-55IACEB6-CK4ROATy.js +0 -1
  365. ksadk/server/static/assets/chunk-727SXJPM-B9KtTTgw.js +0 -206
  366. ksadk/server/static/assets/chunk-AQP2D5EJ-1O1mki3m.js +0 -231
  367. ksadk/server/static/assets/chunk-QZHKN3VN-iXEZtKQc.js +0 -1
  368. ksadk/server/static/assets/classDiagram-4FO5ZUOK-DIveV17Q.js +0 -1
  369. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-DIveV17Q.js +0 -1
  370. ksadk/server/static/assets/cytoscape.esm-DelgaX4f.js +0 -321
  371. ksadk/server/static/assets/dagre-BM42HDAG-D0QXg_MQ.js +0 -4
  372. ksadk/server/static/assets/dagre-Bx709z4p.js +0 -1
  373. ksadk/server/static/assets/diagram-2AECGRRQ-DBDDKwBQ.js +0 -43
  374. ksadk/server/static/assets/diagram-5GNKFQAL-BkwDOxmO.js +0 -10
  375. ksadk/server/static/assets/diagram-KO2AKTUF-Bv8waYvY.js +0 -3
  376. ksadk/server/static/assets/diagram-LMA3HP47-e1VECDdu.js +0 -24
  377. ksadk/server/static/assets/diagram-OG6HWLK6-Ds9adfRl.js +0 -24
  378. ksadk/server/static/assets/dist-B5J2uhNk.js +0 -1
  379. ksadk/server/static/assets/erDiagram-TEJ5UH35-BPItFKH6.js +0 -85
  380. ksadk/server/static/assets/eventmodeling-FCH6USID-DYFSxbqr.js +0 -1
  381. ksadk/server/static/assets/flowDiagram-I6XJVG4X-BbYB9w5Y.js +0 -162
  382. ksadk/server/static/assets/ganttDiagram-6RSMTGT7-TQXa0KXv.js +0 -292
  383. ksadk/server/static/assets/gitGraph-WXDBUCRP-DyNYp6BN.js +0 -1
  384. ksadk/server/static/assets/gitGraphDiagram-PVQCEYII-bKblCnpa.js +0 -106
  385. ksadk/server/static/assets/graphlib-B8gBHxth.js +0 -1
  386. ksadk/server/static/assets/index-R52pJJvg.js +0 -177
  387. ksadk/server/static/assets/index-jJr3_955.css +0 -2
  388. ksadk/server/static/assets/info-J43DQDTF-WUx7qTde.js +0 -1
  389. ksadk/server/static/assets/infoDiagram-5YYISTIA-BGVT7J_i.js +0 -2
  390. ksadk/server/static/assets/katex-CYWseY5E.js +0 -265
  391. ksadk/server/static/assets/mermaid-parser.core-BWrDjSZM.js +0 -161
  392. ksadk/server/static/assets/packet-YPE3B663-BN13y_xl.js +0 -1
  393. ksadk/server/static/assets/pie-LRSECV5Y-ftSLXhhc.js +0 -1
  394. ksadk/server/static/assets/pieDiagram-4H26LBE5-GmmqNiVH.js +0 -30
  395. ksadk/server/static/assets/radar-GUYGQ44K-jaICkIeO.js +0 -1
  396. ksadk/server/static/assets/requirementDiagram-4Y6WPE33-DSWFqL7c.js +0 -84
  397. ksadk/server/static/assets/stateDiagram-AJRCARHV-qzTQpg3Y.js +0 -1
  398. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-BYCoYGAN.js +0 -1
  399. ksadk/server/static/assets/treeView-BLDUP644-Cpib_vlz.js +0 -1
  400. ksadk/server/static/assets/treemap-LRROVOQU-DQxfmVHK.js +0 -1
  401. ksadk/server/static/assets/vennDiagram-CIIHVFJN-CMCixki2.js +0 -34
  402. ksadk/server/static/assets/wardley-L42UT6IY-BQYHnnkU.js +0 -1
  403. ksadk/server/static/assets/wardleyDiagram-YWT4CUSO-CVzB8F9K.js +0 -78
  404. ksadk/server/static/assets/xychartDiagram-2RQKCTM6-BFBqBLc1.js +0 -7
  405. ksadk/studio/evaluation.py +0 -192
  406. ksadk/studio/static/assets/index-CaEN0eTR.css +0 -1
  407. ksadk/studio/static/assets/index-DI2eY_NH.js +0 -252
  408. {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.2.dist-info}/WHEEL +0 -0
  409. {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.2.dist-info}/entry_points.txt +0 -0
  410. {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.2.dist-info}/licenses/LICENSE +0 -0
  411. {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,455 @@
1
+ """Validated canonical event ingestion and deterministic conformance recovery."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ import copy
7
+ import hashlib
8
+ import json
9
+ from collections import Counter
10
+ from collections.abc import Awaitable, Callable
11
+ from typing import Any, cast
12
+
13
+ from ksadk.events.canonical import (
14
+ ErrorInfo,
15
+ ItemCompleted,
16
+ ItemFailed,
17
+ ItemKind,
18
+ ItemSnapshotReplaced,
19
+ RunFailed,
20
+ RuntimeEvent,
21
+ SourceRef,
22
+ dump_runtime_event,
23
+ )
24
+ from ksadk.events.canonical_store import RuntimeEventStore
25
+ from ksadk.events.identity import stable_event_id
26
+ from ksadk.events.reducer import StreamConformanceError, StreamReducer
27
+ from ksadk.kernel.contracts import ActivationWriteGuard, WriteContext
28
+
29
+ Publisher = Callable[[str, RuntimeEvent], Awaitable[None]]
30
+
31
+
32
+ def _reconciliation_reason(event: RuntimeEvent) -> str:
33
+ if isinstance(event, ItemCompleted):
34
+ return "completed_snapshot_mismatch"
35
+ if isinstance(event, ItemSnapshotReplaced):
36
+ return "authoritative_snapshot_replace"
37
+ raise RuntimeError(f"reconciled patch has no declared metric semantics: {event.event_type!r}")
38
+
39
+
40
+ class PipelineMetrics:
41
+ """Small metrics seam; production collectors can mirror ``increment``."""
42
+
43
+ def __init__(self) -> None:
44
+ self._counts: Counter[tuple[str, tuple[tuple[str, str], ...]]] = Counter()
45
+
46
+ def increment(self, name: str, **labels: str) -> None:
47
+ self._counts[(name, tuple(sorted(labels.items())))] += 1
48
+
49
+ def value(self, name: str, **labels: str) -> int:
50
+ return self._counts[(name, tuple(sorted(labels.items())))]
51
+
52
+
53
+ class CanonicalEventPipeline:
54
+ """Prevalidate, persist, reduce and publish one canonical source mutation."""
55
+
56
+ def __init__(
57
+ self,
58
+ store: RuntimeEventStore,
59
+ *,
60
+ session_id: str,
61
+ reducer: StreamReducer | None = None,
62
+ publisher: Publisher | None = None,
63
+ metrics: PipelineMetrics | None = None,
64
+ ) -> None:
65
+ if not session_id.strip():
66
+ raise ValueError("session_id must be nonempty")
67
+ self.store = store
68
+ self.session_id = session_id
69
+ self.reducer = reducer or StreamReducer()
70
+ self.publisher = publisher
71
+ self.metrics = metrics or PipelineMetrics()
72
+ self._ingest_lock = asyncio.Lock()
73
+ self._hydrated_run_id = self.reducer.snapshot().run_id
74
+
75
+ async def ingest(self, event: RuntimeEvent) -> tuple[RuntimeEvent, ...]:
76
+ """Ingest one fact; invalid source facts become durable failure facts."""
77
+
78
+ async with self._ingest_lock:
79
+ return await self._ingest_locked(event)
80
+
81
+ async def emit(
82
+ self, event: RuntimeEvent, *, write_context: WriteContext
83
+ ) -> RuntimeEvent:
84
+ """Fenced typed append: persist (guard CAS) before publish.
85
+
86
+ 与 :meth:`ingest` 的差异:``emit`` 是 owner 内部写入路径,要求
87
+ ``WriteContext(activation_id, fencing_token)``,通过 typed
88
+ ``RuntimeEventStore``(SessionEventStore envelope 视图)走
89
+ ``append(event, guard=write_context)``;Store 在事务内比较 fence 后
90
+ 才分配 seq,旧 owner 在 takeover 后写入会得到
91
+ :class:`~ksadk.kernel.errors.StaleFenceError`。WriteContext 只作为
92
+ 写权限 guard,不进入 RuntimeEvent payload,也不进入公网 projection。
93
+ """
94
+
95
+ if not isinstance(write_context, ActivationWriteGuard):
96
+ raise TypeError(
97
+ "emit requires a typed WriteContext(activation_id, fencing_token)"
98
+ )
99
+ if self.store.event_store is None:
100
+ raise RuntimeError(
101
+ "emit requires a SessionEventStore-backed typed RuntimeEventStore"
102
+ )
103
+ if getattr(self.store, "session_id", None) != self.session_id:
104
+ raise ValueError("typed RuntimeEventStore session does not match pipeline")
105
+ # 先在影子 reducer 上预检 conformance,非法事实绝不落库。
106
+ shadow = copy.deepcopy(self.reducer)
107
+ shadow.apply(event.model_copy(update={"seq": self._validation_seq(event)}))
108
+ persisted = await self.store.append(event, guard=write_context)
109
+ last_seq = self.reducer.snapshot().last_seq
110
+ if last_seq is None or persisted.seq > last_seq:
111
+ self.reducer.apply(persisted)
112
+ await self._publish(persisted)
113
+ return persisted
114
+
115
+ async def _ingest_locked(self, event: RuntimeEvent) -> tuple[RuntimeEvent, ...]:
116
+ await self._hydrate_run_if_needed(event.run_id)
117
+ existing = await self.store.resolve_existing(self.session_id, event)
118
+ if existing is not None:
119
+ last_seq = self.reducer.snapshot().last_seq
120
+ if last_seq is None or existing.seq > last_seq:
121
+ self.reducer.apply(existing)
122
+ await self._publish(existing)
123
+ return (existing,)
124
+
125
+ candidate = event.model_copy(update={"seq": self._validation_seq(event)})
126
+ shadow = copy.deepcopy(self.reducer)
127
+ try:
128
+ preview = shadow.apply(candidate)
129
+ except StreamConformanceError as error:
130
+ return await self._recover(event, error)
131
+ reconciliation_reason = _reconciliation_reason(candidate) if preview.reconciled else None
132
+
133
+ persisted, created = await self.store.persist_one(self.session_id, event)
134
+ self.reducer.apply(persisted)
135
+ if created and reconciliation_reason is not None:
136
+ self.metrics.increment(
137
+ "stream_projection_reconciled_total",
138
+ source=event.source.framework,
139
+ reason=reconciliation_reason,
140
+ )
141
+ await self._publish(persisted)
142
+ return (persisted,)
143
+
144
+ async def _hydrate_run_if_needed(self, run_id: str) -> None:
145
+ if self._hydrated_run_id == run_id:
146
+ return
147
+ snapshot = self.reducer.snapshot()
148
+ if snapshot.run_id is not None and snapshot.run_id != run_id:
149
+ # Let the reducer produce its normal structured run-id error.
150
+ return
151
+ for persisted in await self.store.list(self.session_id, run_id=run_id):
152
+ self.reducer.apply(persisted)
153
+ self._hydrated_run_id = run_id
154
+
155
+ def _validation_seq(self, event: RuntimeEvent) -> int:
156
+ last_seq = self.reducer.snapshot().last_seq
157
+ return max((last_seq or 0) + 1, event.seq)
158
+
159
+ async def _recover(
160
+ self, offending: RuntimeEvent, error: StreamConformanceError
161
+ ) -> tuple[RuntimeEvent, ...]:
162
+ fingerprint = _canonical_fingerprint(offending)
163
+ terminal = await self.store.event_by_id(
164
+ self.session_id,
165
+ self._recovery_terminal_event_id(offending),
166
+ )
167
+ owner_locator = await self.store.event_by_id(
168
+ self.session_id,
169
+ self._recovery_owner_event_id(offending),
170
+ )
171
+ if terminal is not None or owner_locator is not None:
172
+ plan = self._load_recovery_plan(
173
+ offending,
174
+ fingerprint,
175
+ terminal=terminal,
176
+ owner_locator=owner_locator,
177
+ )
178
+ else:
179
+ plan = self._new_recovery_plan(offending, error, fingerprint)
180
+ self.metrics.increment(
181
+ "stream_conformance_error_total",
182
+ source=error.source,
183
+ reason=error.code,
184
+ )
185
+
186
+ planned = self._recovery_facts(offending, plan, fingerprint)
187
+ persisted_group: list[RuntimeEvent] = []
188
+ # Persist the complete plan before changing live projection or emitting.
189
+ for fact in planned:
190
+ persisted, _created = await self.store.persist_one(self.session_id, fact)
191
+ persisted_group.append(persisted)
192
+ # Apply the complete durable group before the first publish attempt.
193
+ for persisted in persisted_group:
194
+ last_seq = self.reducer.snapshot().last_seq
195
+ if last_seq is None or persisted.seq > last_seq:
196
+ self.reducer.apply(persisted)
197
+ # A retry republishes the whole group from its first member. Duplicate
198
+ # event ids are allowed at this live boundary; missing facts are not.
199
+ for persisted in persisted_group:
200
+ await self._publish(persisted)
201
+ return tuple(persisted_group)
202
+
203
+ def _load_recovery_plan(
204
+ self,
205
+ offending: RuntimeEvent,
206
+ fingerprint: str,
207
+ *,
208
+ terminal: RuntimeEvent | None,
209
+ owner_locator: RuntimeEvent | None,
210
+ ) -> dict[str, Any]:
211
+ terminal_id = self._recovery_terminal_event_id(offending)
212
+ owner_locator_id = self._recovery_owner_event_id(offending)
213
+ existing = tuple(event for event in (terminal, owner_locator) if event is not None)
214
+ owner_ids: set[str] = set()
215
+ for persisted in existing:
216
+ metadata = persisted.source.metadata
217
+ if (
218
+ metadata.get("recovery_for_event_id") != offending.event_id
219
+ or metadata.get("offending_fingerprint") != fingerprint
220
+ ):
221
+ raise ValueError(f"RuntimeEvent recovery collision for {offending.event_id!r}")
222
+ owner_id = metadata.get("recovery_plan_owner_event_id")
223
+ if not isinstance(owner_id, str) or not owner_id:
224
+ raise ValueError("persisted recovery is missing its plan owner ref")
225
+ owner_ids.add(owner_id)
226
+ if len(owner_ids) != 1:
227
+ raise ValueError(f"RuntimeEvent recovery collision for {offending.event_id!r}")
228
+
229
+ owner_id = owner_ids.pop()
230
+ if owner_id == terminal_id:
231
+ owner = terminal
232
+ elif owner_id == owner_locator_id:
233
+ owner = owner_locator
234
+ else:
235
+ raise ValueError(f"RuntimeEvent recovery collision for {offending.event_id!r}")
236
+ if owner is None:
237
+ raise ValueError("persisted recovery plan owner is missing")
238
+ if terminal is not None and (
239
+ terminal.event_id != terminal_id or terminal.event_type != "run.failed"
240
+ ):
241
+ raise ValueError(f"RuntimeEvent recovery collision for {offending.event_id!r}")
242
+ if owner_locator is not None and (
243
+ owner_locator.event_id != owner_locator_id or owner_locator.event_type != "item.failed"
244
+ ):
245
+ raise ValueError(f"RuntimeEvent recovery collision for {offending.event_id!r}")
246
+ owner_metadata = owner.source.metadata
247
+ if (
248
+ owner.event_id != owner_id
249
+ or owner_metadata.get("recovery_for_event_id") != offending.event_id
250
+ or owner_metadata.get("offending_fingerprint") != fingerprint
251
+ or owner_metadata.get("recovery_plan_owner_event_id") != owner_id
252
+ ):
253
+ raise ValueError(f"RuntimeEvent recovery collision for {offending.event_id!r}")
254
+ plan_value = owner_metadata.get("recovery_plan")
255
+ if not isinstance(plan_value, dict):
256
+ raise ValueError("persisted recovery plan owner is missing its complete plan")
257
+ if (
258
+ plan_value.get("offending_fingerprint") != fingerprint
259
+ or plan_value.get("owner_event_id") != owner_id
260
+ ):
261
+ raise ValueError(f"RuntimeEvent recovery collision for {offending.event_id!r}")
262
+ entries = plan_value.get("events")
263
+ if (
264
+ not isinstance(entries, list)
265
+ or not entries
266
+ or not isinstance(entries[0], dict)
267
+ or entries[0].get("event_id") != owner_id
268
+ or entries[0].get("event_type")
269
+ != ("run.failed" if owner_id == terminal_id else "item.failed")
270
+ or not isinstance(entries[-1], dict)
271
+ or entries[-1].get("event_id") != terminal_id
272
+ or entries[-1].get("event_type") != "run.failed"
273
+ ):
274
+ raise ValueError(f"RuntimeEvent recovery collision for {offending.event_id!r}")
275
+ return plan_value
276
+
277
+ def _new_recovery_plan(
278
+ self,
279
+ offending: RuntimeEvent,
280
+ error: StreamConformanceError,
281
+ fingerprint: str,
282
+ ) -> dict[str, Any]:
283
+ entries: list[dict[str, Any]] = []
284
+ open_items = sorted(
285
+ (item for item in self.reducer.snapshot().items if item.status == "open"),
286
+ key=lambda item: (item.scope_id, item.item_id),
287
+ )
288
+ for index, item in enumerate(open_items):
289
+ entries.append(
290
+ {
291
+ "event_id": (
292
+ self._recovery_owner_event_id(offending)
293
+ if index == 0
294
+ else stable_event_id(
295
+ "ksadk",
296
+ item.scope_id,
297
+ item.item_id,
298
+ "item.failed",
299
+ "recovery",
300
+ offending.event_id,
301
+ 0,
302
+ )
303
+ ),
304
+ "event_type": "item.failed",
305
+ "scope_id": item.scope_id,
306
+ "item_id": item.item_id,
307
+ "item_kind": item.item_kind,
308
+ }
309
+ )
310
+ entries.append(
311
+ {
312
+ "event_id": self._recovery_terminal_event_id(offending),
313
+ "event_type": "run.failed",
314
+ "scope_id": offending.scope_id,
315
+ }
316
+ )
317
+ owner_event_id = str(entries[0]["event_id"])
318
+ return {
319
+ "version": 1,
320
+ "owner_event_id": owner_event_id,
321
+ "offending_fingerprint": fingerprint,
322
+ "error": {
323
+ "code": error.code,
324
+ "source": error.source,
325
+ "scope_id": error.scope_id,
326
+ "item_id": error.item_id,
327
+ },
328
+ "events": entries,
329
+ }
330
+
331
+ @staticmethod
332
+ def _recovery_owner_event_id(offending: RuntimeEvent) -> str:
333
+ return stable_event_id(
334
+ "ksadk",
335
+ "recovery",
336
+ offending.event_id,
337
+ "item.failed",
338
+ "plan-owner",
339
+ offending.event_id,
340
+ 0,
341
+ )
342
+
343
+ @staticmethod
344
+ def _recovery_terminal_event_id(offending: RuntimeEvent) -> str:
345
+ # The session-scoped offending event id is the collision domain. Do
346
+ # not include mutable candidate facts such as run/scope here: a retry
347
+ # that reuses event_id with different facts must hit this tombstone and
348
+ # fail fingerprint validation before writing a second recovery group.
349
+ return stable_event_id(
350
+ "ksadk",
351
+ "recovery",
352
+ offending.event_id,
353
+ "run.failed",
354
+ "tombstone",
355
+ offending.event_id,
356
+ 0,
357
+ )
358
+
359
+ @staticmethod
360
+ def _recovery_facts(
361
+ offending: RuntimeEvent,
362
+ plan: dict[str, Any],
363
+ fingerprint: str,
364
+ ) -> tuple[RuntimeEvent, ...]:
365
+ error_payload = plan.get("error")
366
+ entries = plan.get("events")
367
+ owner_event_id = plan.get("owner_event_id")
368
+ if (
369
+ not isinstance(error_payload, dict)
370
+ or not isinstance(entries, list)
371
+ or not isinstance(owner_event_id, str)
372
+ or not owner_event_id
373
+ ):
374
+ raise ValueError("persisted recovery plan is malformed")
375
+ error_info = ErrorInfo(
376
+ code=str(error_payload.get("code") or "stream_conformance_error"),
377
+ message="Canonical stream conformance failure",
378
+ source=str(error_payload.get("source") or offending.source.framework),
379
+ scope_id=str(error_payload.get("scope_id") or offending.scope_id),
380
+ item_id=(str(error_payload["item_id"]) if error_payload.get("item_id") else None),
381
+ source_ref=offending.source,
382
+ )
383
+ facts: list[RuntimeEvent] = []
384
+ for entry in entries:
385
+ if not isinstance(entry, dict):
386
+ raise ValueError("persisted recovery plan event is malformed")
387
+ event_id = str(entry.get("event_id") or "")
388
+ metadata: dict[str, Any] = {
389
+ "recovery_for_event_id": offending.event_id,
390
+ "offending_fingerprint": fingerprint,
391
+ "recovery_plan_owner_event_id": owner_event_id,
392
+ }
393
+ if event_id == owner_event_id:
394
+ metadata["recovery_plan"] = plan
395
+ recovery_source = SourceRef(
396
+ framework="ksadk",
397
+ native_event_id=offending.event_id,
398
+ native_run_id=offending.run_id,
399
+ metadata=metadata,
400
+ )
401
+ if entry.get("event_type") == "item.failed":
402
+ scope_id = str(entry.get("scope_id") or "")
403
+ item_id = str(entry.get("item_id") or "")
404
+ facts.append(
405
+ ItemFailed(
406
+ schema_version=2,
407
+ event_id=event_id,
408
+ seq=0,
409
+ timestamp=offending.timestamp,
410
+ run_id=offending.run_id,
411
+ run_seq=offending.run_seq,
412
+ scope_id=scope_id,
413
+ source=recovery_source,
414
+ item_id=item_id,
415
+ item_kind=cast(ItemKind, entry.get("item_kind") or "message"),
416
+ error=error_info.model_copy(
417
+ update={"scope_id": scope_id, "item_id": item_id}
418
+ ),
419
+ )
420
+ )
421
+ elif entry.get("event_type") == "run.failed":
422
+ facts.append(
423
+ RunFailed(
424
+ schema_version=2,
425
+ event_id=event_id,
426
+ seq=0,
427
+ timestamp=offending.timestamp,
428
+ run_id=offending.run_id,
429
+ run_seq=offending.run_seq,
430
+ scope_id=str(entry.get("scope_id") or offending.scope_id),
431
+ parent_scope_id=offending.parent_scope_id,
432
+ source=recovery_source,
433
+ status="failed",
434
+ error=error_info,
435
+ )
436
+ )
437
+ else:
438
+ raise ValueError("persisted recovery plan has unsupported event type")
439
+ return tuple(facts)
440
+
441
+ async def _publish(self, event: RuntimeEvent) -> None:
442
+ if self.publisher is not None:
443
+ await self.publisher(self.session_id, event)
444
+
445
+
446
+ __all__ = ["CanonicalEventPipeline", "PipelineMetrics"]
447
+
448
+
449
+ def _canonical_fingerprint(event: RuntimeEvent) -> str:
450
+ payload = dump_runtime_event(event)
451
+ payload.pop("seq", None)
452
+ encoded = json.dumps(payload, ensure_ascii=False, separators=(",", ":"), sort_keys=True).encode(
453
+ "utf-8"
454
+ )
455
+ return hashlib.sha256(encoded).hexdigest()
@@ -0,0 +1,66 @@
1
+ """Canonical 内部事实与公开投影的边界(重设计要素 3/3)。
2
+
3
+ canonical store(``ksadk/events/canonical_store.py`` 及 ``canonical.py`` 的事件
4
+ 模型)是唯一的存储事实(append-only、schema_version=2、含内部字段如
5
+ ``seq``/``run_seq``/``native_*``/``source.metadata``)。所有对外 wire 形态都是
6
+ 从 canonical 事实派生的**投影**:投影只承诺下表列出的最小公开字段集,除此之外
7
+ 的字段(含内部序号、native 游标、source 原始 metadata)均属内部不保证字段,
8
+ 消费方不得依赖。
9
+
10
+ 本模块是边界的**声明处**;契约的**执行形态**是 golden 测试
11
+ ``tests/protocol/test_cross_projection_golden.py`` 与 fixture
12
+ ``tests/events/fixtures/runtime_projection_golden.json``。修改任何投影的公开字段
13
+ 承诺必须同时更新本表与 golden 测试。
14
+
15
+ 投影矩阵(投影 | 实现位置 | 消费方 | 最小公开字段承诺):
16
+
17
+ | 投影 | 实现位置 | 消费方 | 公开承诺字段 |
18
+ | --- | --- | --- | --- |
19
+ | v1 legacy wire | ``events/v1_compat.py::project_to_v1`` | canonical_replay、cli cmd_replay、旧 SDK 客户端 | RuntimeEventV1 事件类型 + 各类型 payload(approval_id/call_id/kind/detail、surface_id/block_id/data、output_refs、status/error/reason)+ 身份字段 run_id/scope_id/item_id |
20
+ | Studio 事件流 | ``studio/run_service.py::project_runtime_event`` | 本地/托管 Studio UI(SSE) | ``runId``/``scopeId`` 全事件;message.*/thinking.* 含 ``itemId``/``partId``;tool.*/command.*/approval.*/a2ui.* 含 ``itemId``;a2ui.surface.* 含 ``surfaceId``/``a2uiOperations`` |
21
+ | AG-UI/A2UI operations | ``agui/a2ui_projection.py::project_a2ui_operations`` | AG-UI 兼容客户端与 message_projection | 操作列表 ``[{version: "v0.9", createSurface|updateComponents|updateDataModel|deleteSurface: ...}]``,每条含 ``surfaceId`` |
22
+ | 会话消息历史 | ``conversations/message_projection.py::project_session_messages`` | server GetSession/ListMessages、hosted UI 历史接口 | 消息 dict:``Role``/``Content.text``/``SeqId``/``StartSeqId``,可选 ``Reasoning``/``ToolEvents``(approval 含 ``ApprovalRequestId``)/``Activities``(含 ``surfaceId``) |
23
+ | Responses 历史 | ``conversations/context.py::project_responses_history`` | Responses API 请求回放 input | OpenAI Responses input items(``type``/``call_id``/``output``/role 消息),仅可靠 call_id 的 tool 项 |
24
+ | 模型 history | ``conversations/context.py::project_model_messages`` | 运行时模型上下文(内部投喂) | ``role``/``content`` 消息列表;control 事件不进入上下文 |
25
+ | server checkpoint payload | ``server/routes/projection.py::_checkpoint_event_to_action_payload`` | REST 断点续跑/预览接口 | ``EventId``/``SessionId``/``RunId``/``CheckpointId``/``Framework``/``FrameworkRef``/``IsResumable``/``ResumeStatus``/``IsTerminal``/``NextNode``(经 ``run_checkpoint`` 元数据或 ``continuation.created`` 投影) |
26
+ | server 动作事件 payload | ``server/routes/projection.py::_event_to_action_payload`` | REST 会话动作接口(事件原始形态透传) | ``EventId``/``SessionId``/``Author``/``EventType``/``Content``/``Timestamp``/``SeqId``(可选 ``InvocationId``)——序列化存储形态本身,非 canonical 派生 |
27
+
28
+ 内部不保证(任何投影都不承诺、消费方不得依赖):
29
+ - ``seq``/``run_seq`` 的具体数值与连续性(仅保序语义);
30
+ - ``source.native_event_id``/``native_cursor``/``native_run_id``/``native_item_id``;
31
+ - ``source.metadata`` 原始键值(capability 等仅经投影显式提炼后可见);
32
+ - 未列入上表的 payload 附加键。
33
+
34
+ 内部投影(非 wire,不构成公开承诺):
35
+ - ``events/reducer.py::StreamReducer.snapshot`` — 进程内 UI 聚合状态;
36
+ - ``events/canonical_replay.py::replay_projection`` — 内部重建 RunProjection 的路径,
37
+ 其 v1 输出复用 ``project_to_v1`` 的承诺。
38
+ """
39
+
40
+ from __future__ import annotations
41
+
42
+ PROJECTION_CONTRACT_VERSION = 1
43
+
44
+ #: 各投影实现位置的机器可读索引(供文档/校验工具引用;承诺文本见模块 docstring)。
45
+ PROJECTIONS: dict[str, str] = {
46
+ "v1": "ksadk.events.v1_compat:project_to_v1",
47
+ "studio": "ksadk.studio.run_service:project_runtime_event",
48
+ "a2ui": "ksadk.agui.a2ui_projection:project_a2ui_operations",
49
+ "session_messages": "ksadk.conversations.message_projection:project_session_messages",
50
+ "responses_history": "ksadk.conversations.context:project_responses_history",
51
+ "model_messages": "ksadk.conversations.context:project_model_messages",
52
+ "server_checkpoint": "ksadk.server.routes.projection:_checkpoint_event_to_action_payload",
53
+ "server_action_event": "ksadk.server.routes.projection:_event_to_action_payload",
54
+ }
55
+
56
+ #: 仅内部使用的投影(对外无 wire 契约)。
57
+ INTERNAL_PROJECTIONS: dict[str, str] = {
58
+ "stream_reducer": "ksadk.events.reducer:StreamReducer",
59
+ "replay_projection": "ksadk.events.canonical_replay:replay_projection",
60
+ }
61
+
62
+ __all__ = [
63
+ "INTERNAL_PROJECTIONS",
64
+ "PROJECTION_CONTRACT_VERSION",
65
+ "PROJECTIONS",
66
+ ]