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,452 @@
1
+ # -*- coding: utf-8 -*-
2
+ """冷恢复决策表:RecoveryCoordinator(Phase 1 Task 7)。
3
+
4
+ 接管一个 agent_instance 的 open run 时按固定决策表收口:
5
+
6
+ - run 已终态(或不存在 open run)→ ``no_op``;
7
+ - ``attach`` + ``durable_restore`` 能力可用且 durable handle digest 有效 →
8
+ ``attach``(跨进程接回 live handle);
9
+ - ``resume`` 能力可用且存在 continuation → ``resume``(从最后 continuation 续跑);
10
+ - 否则 → 确定性 ``interrupted``(唯一 ``run.interrupted`` + open item close),
11
+ reason 固定为 ``runtime_not_durably_attachable``。
12
+
13
+ 每个决定都追加一条 fenced ``control.recovery_decided`` 审计事实;
14
+ ``RecoveryReport`` 只用于审计与测试,不进入公网 projection。
15
+ """
16
+ from __future__ import annotations
17
+
18
+ import time
19
+ from collections.abc import Callable
20
+ from dataclasses import dataclass, field
21
+ from typing import TYPE_CHECKING, Literal
22
+
23
+ from ksadk.events.canonical import RuntimeEvent
24
+ from ksadk.events.canonical_store import RuntimeEventStore
25
+ from ksadk.events.cold_recovery import scan_open_runs, settle_finding
26
+ from ksadk.events.pipeline import CanonicalEventPipeline
27
+ from ksadk.events.session_event import SessionEventStore
28
+ from ksadk.kernel.contracts import (
29
+ ActivationLease,
30
+ ActivationWriteGuard,
31
+ RuntimeCapabilityMatrix,
32
+ WriteContext,
33
+ )
34
+ from ksadk.kernel.state import RunState, is_terminal_run
35
+ from ksadk.kernel.store import AgentKernelStore, RunRecord, control_event
36
+
37
+ if TYPE_CHECKING: # pragma: no cover - import cycle guard
38
+ from ksadk.runtime.executor import RuntimeExecutor
39
+ from ksadk.runtime.launch import RuntimeLaunchContext
40
+
41
+ RecoveryOutcome = Literal["no_op", "attached", "resumed", "interrupted", "failed"]
42
+
43
+ CapabilityProvider = Callable[[], RuntimeCapabilityMatrix]
44
+
45
+
46
+ @dataclass
47
+ class RecoveryReport:
48
+ """一次 recover 决策的审计结果(不进入公网 projection)。"""
49
+
50
+ agent_instance_id: str
51
+ activation_id: str
52
+ run_id: str | None = None
53
+ outcome: RecoveryOutcome = "no_op"
54
+ reason: str | None = None
55
+ last_seq: int | None = None
56
+ written_events: list[RuntimeEvent] = field(default_factory=list)
57
+
58
+
59
+ def _durable_handle_digest(handle_dump: dict) -> str | None:
60
+ """durable handle 行携带的 digest;缺失/形状不符返回 None。"""
61
+
62
+ try:
63
+ from ksadk.runtime.adapter import RunHandle
64
+ from ksadk.runtime.executor import handle_digest
65
+
66
+ return handle_digest(RunHandle.model_validate(handle_dump))
67
+ except Exception:
68
+ return None
69
+
70
+
71
+ class RecoveryCoordinator:
72
+ """对 open run 做确定性收口或接管的协调器。"""
73
+
74
+ def __init__(
75
+ self,
76
+ store: AgentKernelStore,
77
+ session_events: SessionEventStore,
78
+ capabilities: CapabilityProvider,
79
+ *,
80
+ executor: "RuntimeExecutor | None" = None,
81
+ launch_context: "RuntimeLaunchContext | None" = None,
82
+ adapter_factory: Callable[[], object] | None = None,
83
+ clock: Callable[[], float] = time.time,
84
+ execution_sink: Callable[..., None] | None = None,
85
+ ) -> None:
86
+ self._store = store
87
+ self._session_events = session_events
88
+ self._capabilities = capabilities
89
+ self._executor = executor
90
+ self._launch_context = launch_context
91
+ self._adapter_factory = adapter_factory
92
+ self._clock = clock
93
+ # Task 6:takeover 重建的 ActiveExecution 只在 lease 获取 +
94
+ # provider 支持的 attach/resume 成功后回调注册(worker.adopt_execution)。
95
+ self._execution_sink = execution_sink
96
+
97
+ async def recover(
98
+ self,
99
+ agent_instance_id: str,
100
+ activation: ActivationLease,
101
+ *,
102
+ run_id: str | None = None,
103
+ ) -> RecoveryReport:
104
+ fence = activation.fencing_token
105
+ guard: WriteContext = ActivationWriteGuard(
106
+ activation_id=activation.activation_id, fencing_token=fence
107
+ )
108
+ run = await self._load_run(agent_instance_id, run_id)
109
+ if run is None or is_terminal_run(run.state):
110
+ return await self._decide(
111
+ agent_instance_id,
112
+ activation,
113
+ run,
114
+ outcome="no_op",
115
+ reason=(
116
+ "run_already_terminal"
117
+ if run is not None
118
+ else "no_open_run_for_agent_instance"
119
+ ),
120
+ guard=guard,
121
+ )
122
+
123
+ capabilities = self._capabilities()
124
+ handle_dump = run.metadata.get("handle")
125
+ handle_digest_valid = (
126
+ isinstance(handle_dump, dict)
127
+ and isinstance(run.metadata.get("handle_digest"), str)
128
+ and _durable_handle_digest(handle_dump) == run.metadata.get("handle_digest")
129
+ )
130
+ if (
131
+ capabilities.attach.supported
132
+ and capabilities.durable_restore.supported
133
+ and handle_digest_valid
134
+ and self._executor is not None
135
+ and self._launch_context is not None
136
+ ):
137
+ try:
138
+ handle = await self._executor.attach_record(run, self._launch_context)
139
+ except Exception as error:
140
+ return await self._decide(
141
+ agent_instance_id,
142
+ activation,
143
+ run,
144
+ outcome="failed",
145
+ reason=f"attach_failed:{type(error).__name__}",
146
+ guard=guard,
147
+ )
148
+ # attach 成功即把 live execution 交还 worker(lease 已在调用方获取,
149
+ # attach 已证明 runtime 支持接管),stream 消费失败时仍保留。
150
+ self._register_execution(
151
+ run.run_id,
152
+ handle.run_id,
153
+ getattr(self._executor, "adapter", None),
154
+ handle,
155
+ )
156
+ # attach 成功后重新消费剩余 stream:事实继续落库,自然结束收口。
157
+ try:
158
+ await self._consume_remaining_stream(
159
+ lambda: self._executor.stream(handle), # type: ignore[union-attr]
160
+ run,
161
+ guard,
162
+ )
163
+ except Exception as error:
164
+ return await self._decide(
165
+ agent_instance_id,
166
+ activation,
167
+ run,
168
+ outcome="failed",
169
+ reason=f"attach_stream_failed:{type(error).__name__}",
170
+ guard=guard,
171
+ )
172
+ return await self._decide(
173
+ agent_instance_id,
174
+ activation,
175
+ run,
176
+ outcome="attached",
177
+ reason="durable_handle_attached",
178
+ guard=guard,
179
+ )
180
+
181
+ if capabilities.resume.supported and run.metadata.get("continuation_ref"):
182
+ resumed_report = await self._try_real_resume(
183
+ agent_instance_id, activation, run, guard=guard
184
+ )
185
+ if resumed_report is not None:
186
+ return resumed_report
187
+ return await self._decide(
188
+ agent_instance_id,
189
+ activation,
190
+ run,
191
+ outcome="resumed",
192
+ reason="continuation_resume_delegated",
193
+ guard=guard,
194
+ )
195
+
196
+ return await self._interrupt_deterministically(
197
+ agent_instance_id, activation, run, guard=guard
198
+ )
199
+
200
+ async def settle_interrupted(
201
+ self,
202
+ agent_instance_id: str,
203
+ activation: ActivationLease,
204
+ *,
205
+ reason: str = "recover_error_settled_interrupted",
206
+ ) -> RecoveryReport:
207
+ """P0-1 兜底收口:``recover`` 抛错后的确定性 interrupted 决策。
208
+
209
+ 不依赖任何 runtime 能力:直接对 open run 写唯一
210
+ ``run.interrupted`` + open item close,并以当前 fencing 追加
211
+ ``control.recovery_decided`` 审计事实。没有 open run 时退化为
212
+ ``no_op``。持久化失败向上抛出,由调用方决定 degraded。
213
+ """
214
+
215
+ guard: WriteContext = ActivationWriteGuard(
216
+ activation_id=activation.activation_id,
217
+ fencing_token=activation.fencing_token,
218
+ )
219
+ run = await self._load_run(agent_instance_id, None)
220
+ if run is None or is_terminal_run(run.state):
221
+ return await self._decide(
222
+ agent_instance_id,
223
+ activation,
224
+ run,
225
+ outcome="no_op",
226
+ reason=(
227
+ "run_already_terminal"
228
+ if run is not None
229
+ else "no_open_run_for_agent_instance"
230
+ ),
231
+ guard=guard,
232
+ )
233
+ return await self._interrupt_deterministically(
234
+ agent_instance_id, activation, run, guard=guard, reason=reason
235
+ )
236
+
237
+ # ------------------------------------------------------------- internals
238
+
239
+ def _register_execution(
240
+ self,
241
+ durable_run_id: str,
242
+ runtime_run_id: str,
243
+ adapter: object | None,
244
+ handle: object,
245
+ ) -> None:
246
+ """把 takeover 重建的 live execution 交还 worker(best-effort)。"""
247
+
248
+ if self._execution_sink is None or adapter is None:
249
+ return
250
+ try:
251
+ self._execution_sink(
252
+ durable_run_id=durable_run_id,
253
+ runtime_run_id=runtime_run_id,
254
+ adapter=adapter,
255
+ handle=handle,
256
+ )
257
+ except Exception: # noqa: BLE001 - 审计/恢复路径绝不因 sink 失败中断
258
+ pass
259
+
260
+ async def _try_real_resume(
261
+ self,
262
+ agent_instance_id: str,
263
+ activation: ActivationLease,
264
+ run: RunRecord,
265
+ *,
266
+ guard: WriteContext,
267
+ ) -> RecoveryReport | None:
268
+ """用真实 adapter 从 continuation 恢复执行并继续消费 stream。
269
+
270
+ 返回 ``None`` 表示没有可用 adapter(委托 worker 重放的旧路径)。
271
+ adapter 不支持 resume 时保持确定性收口(interrupted)。
272
+ """
273
+
274
+ from ksadk.kernel.errors import UnsupportedControlError
275
+ from ksadk.runtime.adapter import ResumeTarget, RunHandle
276
+
277
+ if self._adapter_factory is None:
278
+ return None
279
+ handle_dump = run.metadata.get("handle")
280
+ continuation_ref = run.metadata.get("continuation_ref")
281
+ if not isinstance(handle_dump, dict) or not continuation_ref:
282
+ return None
283
+ adapter = self._adapter_factory()
284
+ try:
285
+ handle = RunHandle.model_validate(handle_dump)
286
+ resumed = await adapter.resume(
287
+ handle,
288
+ ResumeTarget(kind="invocation_id", id=str(continuation_ref)),
289
+ None,
290
+ )
291
+ except UnsupportedControlError:
292
+ # EchoAdapter 等不支持 resume 的 runtime:确定性收口,不重试。
293
+ return await self._interrupt_deterministically(
294
+ agent_instance_id, activation, run, guard=guard
295
+ )
296
+ except Exception as error:
297
+ return await self._decide(
298
+ agent_instance_id,
299
+ activation,
300
+ run,
301
+ outcome="failed",
302
+ reason=f"resume_failed:{type(error).__name__}",
303
+ guard=guard,
304
+ )
305
+ # lease 已获取 + provider 支持的 resume 已成功:takeover 重建
306
+ # ActiveExecution,后续控制命令/回包作用于同一 live execution。
307
+ self._register_execution(run.run_id, resumed.run_id, adapter, resumed)
308
+ try:
309
+ await self._consume_remaining_stream(
310
+ lambda: adapter.stream(resumed), run, guard
311
+ )
312
+ except Exception as error:
313
+ return await self._decide(
314
+ agent_instance_id,
315
+ activation,
316
+ run,
317
+ outcome="failed",
318
+ reason=f"resume_stream_failed:{type(error).__name__}",
319
+ guard=guard,
320
+ )
321
+ return await self._decide(
322
+ agent_instance_id,
323
+ activation,
324
+ run,
325
+ outcome="resumed",
326
+ reason="continuation_resumed",
327
+ guard=guard,
328
+ )
329
+
330
+ async def _consume_remaining_stream(
331
+ self, stream_factory, run: RunRecord, guard: WriteContext
332
+ ) -> None:
333
+ """消费剩余事件流(run_id 统一 durable id),自然结束收口 COMPLETED。"""
334
+
335
+ runtime_store = RuntimeEventStore(self._session_events, session_id=run.session_id)
336
+ async for event in stream_factory():
337
+ if event.run_id != run.run_id:
338
+ update: dict = {"run_id": run.run_id}
339
+ if getattr(event, "scope_id", None) == f"run:{event.run_id}":
340
+ update["scope_id"] = f"run:{run.run_id}"
341
+ event = event.model_copy(update=update)
342
+ await runtime_store.append(event, guard=guard) # type: ignore[arg-type]
343
+ await self._store.save_run_transition(
344
+ run.model_copy(update={"state": RunState.COMPLETED}),
345
+ expected_fence=guard.fencing_token, # type: ignore[attr-defined]
346
+ )
347
+
348
+ async def _load_run(
349
+ self, agent_instance_id: str, run_id: str | None
350
+ ) -> RunRecord | None:
351
+ if run_id is not None:
352
+ return await self._store.load_run(run_id)
353
+ finder = getattr(self._store, "find_active_run", None)
354
+ if finder is not None:
355
+ return await finder(agent_instance_id)
356
+ return None
357
+
358
+ async def _interrupt_deterministically(
359
+ self,
360
+ agent_instance_id: str,
361
+ activation: ActivationLease,
362
+ run: RunRecord,
363
+ *,
364
+ guard: WriteContext,
365
+ reason: str = "runtime_not_durably_attachable",
366
+ ) -> RecoveryReport:
367
+ fence = activation.fencing_token
368
+ runtime_store = RuntimeEventStore(self._session_events, session_id=run.session_id)
369
+ findings = await scan_open_runs(runtime_store, run.session_id)
370
+ finding = next((item for item in findings if item.run_id == run.run_id), None)
371
+ written: list[RuntimeEvent] = []
372
+ last_seq: int | None = None
373
+ if finding is not None:
374
+ events = settle_finding(
375
+ finding,
376
+ run.session_id,
377
+ allow_resume=False,
378
+ timestamp=self._clock(),
379
+ reason=reason,
380
+ )
381
+ pipeline = CanonicalEventPipeline(runtime_store, session_id=run.session_id)
382
+ for event in events:
383
+ persisted = await pipeline.emit(event, write_context=guard)
384
+ written.append(persisted)
385
+ last_seq = persisted.seq
386
+ await self._store.save_run_transition(
387
+ run.model_copy(update={"state": RunState.INTERRUPTED}),
388
+ expected_fence=fence,
389
+ )
390
+ return await self._decide(
391
+ agent_instance_id,
392
+ activation,
393
+ run,
394
+ outcome="interrupted",
395
+ reason=reason,
396
+ guard=guard,
397
+ written=written,
398
+ last_seq=last_seq,
399
+ )
400
+
401
+ async def _decide(
402
+ self,
403
+ agent_instance_id: str,
404
+ activation: ActivationLease,
405
+ run: RunRecord | None,
406
+ *,
407
+ outcome: RecoveryOutcome,
408
+ reason: str,
409
+ guard: WriteContext,
410
+ written: list[RuntimeEvent] | None = None,
411
+ last_seq: int | None = None,
412
+ ) -> RecoveryReport:
413
+ if run is not None:
414
+ await self._store.append_event(
415
+ control_event(
416
+ session_id=run.session_id,
417
+ event_type="control.recovery_decided",
418
+ payload={
419
+ "agent_instance_id": agent_instance_id,
420
+ "activation_id": activation.activation_id,
421
+ "fencing_token": activation.fencing_token,
422
+ "run_id": run.run_id,
423
+ "outcome": outcome,
424
+ "reason": reason,
425
+ },
426
+ run_id=run.run_id,
427
+ ),
428
+ expected_fence=activation.fencing_token,
429
+ agent_instance_id=agent_instance_id,
430
+ )
431
+ return RecoveryReport(
432
+ agent_instance_id=agent_instance_id,
433
+ activation_id=activation.activation_id,
434
+ run_id=run.run_id if run is not None else None,
435
+ outcome=outcome,
436
+ reason=reason,
437
+ last_seq=last_seq,
438
+ written_events=list(written or []),
439
+ )
440
+
441
+
442
+ def durable_handle_digest(handle_dump: dict) -> str | None:
443
+ """Public shim kept for callers that only need digest validation."""
444
+ return _durable_handle_digest(handle_dump)
445
+
446
+
447
+ __all__ = [
448
+ "RecoveryCoordinator",
449
+ "RecoveryReport",
450
+ "RecoveryOutcome",
451
+ "durable_handle_digest",
452
+ ]
@@ -0,0 +1,103 @@
1
+ """Non-secret provenance for the KsADK code that is actually imported.
2
+
3
+ The base runtime image may contain an older ``ksadk`` distribution while a
4
+ Code deployment shadows it from ``/app/code``. Health must therefore report
5
+ the source package identity, never the base image's distribution metadata.
6
+
7
+ ``_bundle_identity.py`` is generated into Code archives by :class:`CodeBuilder`.
8
+ It is package content, not a user environment variable, and is intentionally
9
+ optional so legacy images report an honest incomplete provenance record.
10
+
11
+ The managed-runtime image also attests the exact wheel it installs. That
12
+ image provenance is used only when Python is importing KsADK from the image's
13
+ ``site-packages`` directory. A Code archive that shadows KsADK must carry its
14
+ own bundle identity; an environment variable from the base image must never
15
+ claim provenance for user-supplied code.
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ import importlib
21
+ import os
22
+ import re
23
+ from functools import lru_cache
24
+ from pathlib import Path
25
+ from typing import Any
26
+
27
+ from ksadk.version import VERSION
28
+
29
+ _COMMIT_RE = re.compile(r"^[0-9a-f]{40,64}$")
30
+ _SHA256_RE = re.compile(r"^[0-9a-f]{64}$")
31
+
32
+
33
+ def _imports_image_installed_ksadk() -> bool:
34
+ """Whether ``ksadk`` is the distribution installed by the runtime image."""
35
+
36
+ try:
37
+ package = importlib.import_module("ksadk")
38
+ package_file = Path(str(package.__file__ or "")).resolve()
39
+ except (ImportError, OSError, RuntimeError):
40
+ return False
41
+ return "site-packages" in package_file.parts
42
+
43
+
44
+ def _image_identity() -> dict[str, str]:
45
+ """Read image-attested provenance without trusting it for shadowed code."""
46
+
47
+ if not _imports_image_installed_ksadk():
48
+ return {}
49
+ return {
50
+ "ksadk_commit": str(
51
+ os.environ.get("KSADK_RUNTIME_IMAGE_SOURCE_COMMIT") or ""
52
+ ).lower(),
53
+ "ksadk_wheel_sha256": str(
54
+ os.environ.get("KSADK_RUNTIME_IMAGE_WHEEL_SHA256") or ""
55
+ ).lower(),
56
+ }
57
+
58
+
59
+ @lru_cache(maxsize=1)
60
+ def runtime_identity() -> dict[str, str]:
61
+ """Return the provenance embedded beside the imported KsADK package.
62
+
63
+ Missing or malformed optional provenance is represented by an empty field.
64
+ Image provenance is accepted only for the image-installed distribution;
65
+ callers must not substitute a process environment value for Code-bundled
66
+ KsADK or infer identity from an image tag.
67
+ """
68
+
69
+ identity: dict[str, str] = {
70
+ "ksadk_version": VERSION,
71
+ "ksadk_commit": "",
72
+ "ksadk_source_digest": "",
73
+ "ksadk_wheel_sha256": "",
74
+ }
75
+ try:
76
+ bundled: Any = importlib.import_module("ksadk._bundle_identity")
77
+ candidate = getattr(bundled, "BUNDLE_IDENTITY", {})
78
+ except (ImportError, AttributeError):
79
+ candidate = {}
80
+ if isinstance(candidate, dict) and str(candidate.get("ksadk_version") or "") == VERSION:
81
+ # A Code bundle is the closest provenance of the code Python imported.
82
+ commit = str(candidate.get("ksadk_commit") or "").lower()
83
+ digest = str(candidate.get("ksadk_source_digest") or "").lower()
84
+ if _COMMIT_RE.fullmatch(commit):
85
+ identity["ksadk_commit"] = commit
86
+ if _SHA256_RE.fullmatch(digest):
87
+ identity["ksadk_source_digest"] = digest
88
+ if identity["ksadk_commit"] or identity["ksadk_source_digest"]:
89
+ return identity
90
+
91
+ # No valid bundle identity means the installed image distribution is the
92
+ # imported source only when it has not been shadowed by a Code archive.
93
+ image = _image_identity()
94
+ commit = image.get("ksadk_commit", "")
95
+ wheel_digest = image.get("ksadk_wheel_sha256", "")
96
+ if _COMMIT_RE.fullmatch(commit):
97
+ identity["ksadk_commit"] = commit
98
+ if _SHA256_RE.fullmatch(wheel_digest):
99
+ identity["ksadk_wheel_sha256"] = wheel_digest
100
+ return identity
101
+
102
+
103
+ __all__ = ["runtime_identity"]
@@ -0,0 +1,120 @@
1
+ -- Agent Kernel durable state (Phase 1 Task 4).
2
+ -- BIGINT fencing_token / TIMESTAMPTZ lease / JSONB payload.
3
+ -- Idempotency: (tenant_id, session_id, idempotency_key) unique.
4
+ -- Claim ordering: FOR UPDATE SKIP LOCKED ordered by accepted_seq (see postgres_store.py).
5
+
6
+ CREATE TABLE IF NOT EXISTS kernel_inbox (
7
+ message_id UUID PRIMARY KEY,
8
+ tenant_id TEXT NOT NULL DEFAULT 'default',
9
+ agent_instance_id TEXT NOT NULL,
10
+ session_id TEXT NOT NULL,
11
+ idempotency_key TEXT NOT NULL,
12
+ request_digest TEXT NOT NULL,
13
+ accepted_seq BIGINT NOT NULL,
14
+ status TEXT NOT NULL CHECK (status IN ('accepted','claimed','completed','discarded')),
15
+ claimed_fence BIGINT,
16
+ payload JSONB NOT NULL,
17
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
18
+ UNIQUE (tenant_id, session_id, idempotency_key)
19
+ );
20
+ CREATE INDEX IF NOT EXISTS idx_kernel_inbox_claim
21
+ ON kernel_inbox (agent_instance_id, session_id, status, accepted_seq);
22
+
23
+ CREATE TABLE IF NOT EXISTS kernel_runs (
24
+ run_id TEXT PRIMARY KEY,
25
+ tenant_id TEXT NOT NULL DEFAULT 'default',
26
+ agent_instance_id TEXT NOT NULL,
27
+ session_id TEXT NOT NULL,
28
+ state TEXT NOT NULL CHECK (state IN (
29
+ 'pending','running','paused','waiting','completed','failed','cancelled','interrupted'
30
+ )),
31
+ activation_fence BIGINT NOT NULL DEFAULT 0,
32
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
33
+ updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
34
+ metadata JSONB NOT NULL DEFAULT '{}'::jsonb
35
+ );
36
+ CREATE INDEX IF NOT EXISTS idx_kernel_runs_session_state
37
+ ON kernel_runs (session_id, state);
38
+
39
+ -- Activation lease: one row per (agent_instance_id, session_id). Takeover uses
40
+ -- INSERT .. ON CONFLICT .. DO UPDATE .. WHERE lease_expires_at <= now()
41
+ -- (or released / same activation) and atomically bumps fencing_token + 1.
42
+ CREATE TABLE IF NOT EXISTS kernel_activations (
43
+ agent_instance_id TEXT NOT NULL,
44
+ session_id TEXT NOT NULL,
45
+ activation_id TEXT NOT NULL,
46
+ fencing_token BIGINT NOT NULL,
47
+ lease_expires_at TIMESTAMPTZ NOT NULL,
48
+ released BOOLEAN NOT NULL DEFAULT FALSE,
49
+ runtime_type TEXT NOT NULL DEFAULT 'ksadk',
50
+ bundle_digest TEXT NOT NULL DEFAULT '',
51
+ capability_digest TEXT NOT NULL DEFAULT '',
52
+ PRIMARY KEY (agent_instance_id, session_id)
53
+ );
54
+ CREATE INDEX IF NOT EXISTS idx_kernel_activations_expiry
55
+ ON kernel_activations (lease_expires_at);
56
+
57
+ CREATE TABLE IF NOT EXISTS kernel_accepted_seq (
58
+ tenant_id TEXT NOT NULL DEFAULT 'default',
59
+ session_id TEXT NOT NULL,
60
+ last_seq BIGINT NOT NULL DEFAULT 0,
61
+ PRIMARY KEY (tenant_id, session_id)
62
+ );
63
+
64
+ -- Mutation permit nonce 单次使用(durable replay 防护,跨 Pod / 重启共享)。
65
+ -- register 语义见 postgres_store.PostgresNonceStore:INSERT .. ON CONFLICT DO
66
+ -- NOTHING,冲突时读回 (command_id, idempotency_key) 判定网络重试 vs 重放。
67
+ CREATE TABLE IF NOT EXISTS kernel_permit_nonces (
68
+ nonce TEXT PRIMARY KEY,
69
+ command_id TEXT NOT NULL,
70
+ idempotency_key TEXT NOT NULL,
71
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now()
72
+ );
73
+ CREATE INDEX IF NOT EXISTS idx_kernel_permit_nonces_created
74
+ ON kernel_permit_nonces (created_at);
75
+
76
+ -- Durable Interaction ledger (Phase 1 Task 5). First-wins terminal CAS on
77
+ -- (revision, status); terminal decision and its SessionEvent append happen in
78
+ -- the same writer transaction (see postgres_store interaction methods).
79
+ -- Row key: (tenant_id, interaction_id); idempotency submissions are unique on
80
+ -- (tenant_id, interaction_id, idempotency_key).
81
+ CREATE TABLE IF NOT EXISTS kernel_interactions (
82
+ interaction_id TEXT NOT NULL,
83
+ tenant_id TEXT NOT NULL DEFAULT 'default',
84
+ agent_instance_id TEXT NOT NULL,
85
+ session_id TEXT NOT NULL,
86
+ run_id TEXT NOT NULL,
87
+ kind TEXT NOT NULL CHECK (kind IN ('approval','structured_input','plan_review','custom')),
88
+ request_schema JSONB NOT NULL,
89
+ presentation JSONB,
90
+ revision BIGINT NOT NULL,
91
+ status TEXT NOT NULL CHECK (status IN (
92
+ 'pending','resolving','resolved','cancelled','expired'
93
+ )),
94
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
95
+ expires_at TIMESTAMPTZ,
96
+ provider_id TEXT NOT NULL DEFAULT '',
97
+ native_target JSONB,
98
+ continuation_metadata JSONB,
99
+ request_digest TEXT NOT NULL,
100
+ response JSONB,
101
+ outcome TEXT,
102
+ actor TEXT,
103
+ event_id UUID,
104
+ accepted_seq BIGINT,
105
+ fencing_token BIGINT,
106
+ updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
107
+ PRIMARY KEY (tenant_id, interaction_id)
108
+ );
109
+ CREATE INDEX IF NOT EXISTS idx_kernel_interactions_pending
110
+ ON kernel_interactions (tenant_id, session_id, status);
111
+
112
+ CREATE TABLE IF NOT EXISTS kernel_interaction_submissions (
113
+ tenant_id TEXT NOT NULL DEFAULT 'default',
114
+ interaction_id TEXT NOT NULL,
115
+ idempotency_key TEXT NOT NULL,
116
+ submission_digest TEXT NOT NULL,
117
+ receipt JSONB NOT NULL,
118
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
119
+ PRIMARY KEY (tenant_id, interaction_id, idempotency_key)
120
+ );