agentengine-sdk-python 0.8.3__py3-none-any.whl → 0.8.4__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 (509) hide show
  1. {agentengine_sdk_python-0.8.3.dist-info → agentengine_sdk_python-0.8.4.dist-info}/METADATA +9 -8
  2. {agentengine_sdk_python-0.8.3.dist-info → agentengine_sdk_python-0.8.4.dist-info}/RECORD +482 -245
  3. ksadk/_build_provenance.json +1 -1
  4. ksadk/api/client.py +105 -91
  5. ksadk/builders/code_builder.py +36 -9
  6. ksadk/builders/framework_requirements.py +2 -1
  7. ksadk/builders/ks3_uploader.py +36 -7
  8. ksadk/builders/managed_runtime_builder.py +1 -0
  9. ksadk/cli/__init__.py +32 -3
  10. ksadk/cli/cmd_managed_runtime.py +13 -1
  11. ksadk/cli/cmd_plugin.py +6 -1
  12. ksadk/cli/cmd_web.py +2 -5
  13. ksadk/cli/runtime_bootstrap.py +23 -1
  14. ksadk/codex/client.py +424 -96
  15. ksadk/codex/projection.py +24 -0
  16. ksadk/codex/runtime.py +56 -298
  17. ksadk/common/auth.py +16 -10
  18. ksadk/configs/env_registry.py +29 -1
  19. ksadk/conversations/message_projection.py +135 -14
  20. ksadk/conversations/projector.py +4 -6
  21. ksadk/conversations/runtime_invocation.py +5 -0
  22. ksadk/conversations/runtime_payloads.py +1 -0
  23. ksadk/conversations/runtime_preparation.py +30 -27
  24. ksadk/conversations/runtime_resume.py +50 -2
  25. ksadk/conversations/runtime_stream_events.py +5 -0
  26. ksadk/conversations/runtime_streaming.py +25 -7
  27. ksadk/deployment/env_forward.py +2 -2
  28. ksadk/deployment/providers/serverless.py +1 -1
  29. ksadk/events/adapters/_codex_validators.py +18 -7
  30. ksadk/events/adapters/langgraph.py +15 -1
  31. ksadk/events/canonical_store.py +3 -1
  32. ksadk/events/projections.py +1 -1
  33. ksadk/harness/config.py +2 -2
  34. ksadk/harness/runtime.py +27 -27
  35. ksadk/harness/tools.py +38 -13
  36. ksadk/interaction/provider.py +1 -0
  37. ksadk/interaction/providers/langgraph.py +1 -0
  38. ksadk/kernel/bootstrap.py +28 -4
  39. ksadk/kernel/ingress.py +15 -2
  40. ksadk/kernel/sqlite_store.py +27 -0
  41. ksadk/kernel/store.py +3 -0
  42. ksadk/kernel/worker.py +65 -10
  43. ksadk/knowledge_base/client.py +57 -27
  44. ksadk/mcp_runtime/__init__.py +12 -4
  45. ksadk/memory/adk/backends/sdk_ltm_backend.py +161 -41
  46. ksadk/memory/adk/resilient_session_service.py +25 -17
  47. ksadk/memory/adk/short_term_memory.py +26 -9
  48. ksadk/memory/models.py +7 -4
  49. ksadk/memory/provider_resolver.py +3 -0
  50. ksadk/model_proxy/server.py +10 -5
  51. ksadk/plugins/__init__.py +4 -0
  52. ksadk/plugins/artifacts.py +275 -0
  53. ksadk/plugins/bridges/__init__.py +4 -2
  54. ksadk/plugins/bridges/codex.py +120 -13
  55. ksadk/plugins/bridges/dsh.py +340 -156
  56. ksadk/plugins/builtins.py +35 -36
  57. ksadk/plugins/bundle_security.py +28 -4
  58. ksadk/plugins/codex_manifest.py +983 -0
  59. ksadk/plugins/composition.py +8 -0
  60. ksadk/plugins/contracts.py +118 -0
  61. ksadk/plugins/delivery.py +153 -0
  62. ksadk/plugins/dsh_installation_digest.py +71 -0
  63. ksadk/plugins/dsh_toolchain.py +110 -21
  64. ksadk/plugins/ecosystem_probe.py +6 -6
  65. ksadk/plugins/host.py +102 -39
  66. ksadk/plugins/kernel_adapter.py +205 -0
  67. ksadk/plugins/providers/__init__.py +23 -0
  68. ksadk/plugins/providers/bundles/dsh-knowledge/cordis.patch.yml +3 -0
  69. ksadk/plugins/providers/bundles/dsh-knowledge/index.mjs +53 -0
  70. ksadk/plugins/providers/bundles/dsh-knowledge/package.json +16 -0
  71. ksadk/plugins/providers/bundles/dsh-memory/cordis.patch.yml +3 -0
  72. ksadk/plugins/providers/bundles/dsh-memory/index.mjs +175 -0
  73. ksadk/plugins/providers/bundles/dsh-memory/package.json +16 -0
  74. ksadk/plugins/providers/bundles/dsh-platform-resources/client.mjs +166 -0
  75. ksadk/plugins/providers/bundles/dsh-platform-resources/cordis.patch.yml +3 -0
  76. ksadk/plugins/providers/bundles/dsh-platform-resources/index.mjs +9 -0
  77. ksadk/plugins/providers/bundles/dsh-platform-resources/package.json +12 -0
  78. ksadk/plugins/providers/bundles/dsh-skill-center/cordis.patch.yml +3 -0
  79. ksadk/plugins/providers/bundles/dsh-skill-center/index.mjs +125 -0
  80. ksadk/plugins/providers/bundles/dsh-skill-center/package.json +16 -0
  81. ksadk/plugins/providers/bundles/ksadk-dsh-capability-host/cordis.patch.yml +3 -0
  82. ksadk/plugins/providers/bundles/ksadk-dsh-capability-host/index.mjs +870 -0
  83. ksadk/plugins/providers/bundles/ksadk-dsh-capability-host/package.json +27 -0
  84. ksadk/plugins/providers/bundles/ksadk-dsh-studio/client.js +92 -0
  85. ksadk/plugins/providers/bundles/ksadk-dsh-studio/index.mjs +15 -0
  86. ksadk/plugins/providers/bundles/ksadk-dsh-studio/package.json +7 -0
  87. ksadk/plugins/providers/codex.py +335 -69
  88. ksadk/plugins/providers/codex_native.py +368 -0
  89. ksadk/plugins/providers/codex_turn.py +301 -0
  90. ksadk/plugins/providers/dsh_capabilities.py +1389 -0
  91. ksadk/plugins/providers/dsh_mcp.py +467 -0
  92. ksadk/plugins/providers/harness.py +118 -113
  93. ksadk/plugins/providers/mcp_projection.py +150 -0
  94. ksadk/plugins/providers/platform_resources.py +657 -0
  95. ksadk/plugins/resolver.py +8 -1
  96. ksadk/resource_runtime/__init__.py +4 -0
  97. ksadk/resource_runtime/broker.py +616 -0
  98. ksadk/resource_runtime/build_artifacts.py +165 -0
  99. ksadk/resource_runtime/contracts.py +138 -0
  100. ksadk/resource_runtime/discovery_receipts.py +100 -0
  101. ksadk/resource_runtime/discovery_skills.py +172 -0
  102. ksadk/resource_runtime/errors.py +6 -0
  103. ksadk/resource_runtime/ipc.py +142 -0
  104. ksadk/resource_runtime/kernel_approval.py +165 -0
  105. ksadk/resource_runtime/knowledge.py +114 -0
  106. ksadk/resource_runtime/langgraph.py +94 -0
  107. ksadk/resource_runtime/leases.py +191 -0
  108. ksadk/resource_runtime/managed_projection.py +186 -0
  109. ksadk/resource_runtime/mcp_server.py +138 -0
  110. ksadk/resource_runtime/memory_provider.py +318 -0
  111. ksadk/resource_runtime/memory_receipts.py +34 -0
  112. ksadk/resource_runtime/operation_ledger.py +211 -0
  113. ksadk/resource_runtime/plugin_config.py +48 -0
  114. ksadk/resource_runtime/policy_authorization.py +54 -0
  115. ksadk/resource_runtime/process.py +110 -0
  116. ksadk/resource_runtime/skill_artifacts.py +153 -0
  117. ksadk/resource_runtime/skill_runtime.py +42 -0
  118. ksadk/resource_runtime/skill_workspace.py +118 -0
  119. ksadk/resource_runtime/skills.py +215 -0
  120. ksadk/resource_runtime/snapshots.py +180 -0
  121. ksadk/resource_runtime/socket_server.py +103 -0
  122. ksadk/resource_runtime/supervisor.py +380 -0
  123. ksadk/resource_runtime/worker.py +504 -0
  124. ksadk/runners/_langgraph_runner_streams.py +74 -6
  125. ksadk/runners/adk_runner.py +149 -11
  126. ksadk/runners/base_runner.py +29 -1
  127. ksadk/runners/langgraph_runner.py +475 -145
  128. ksadk/runtime/_runner_adapter/stream_mapping.py +142 -18
  129. ksadk/runtime/adapter.py +2 -0
  130. ksadk/runtime/conversation_execution.py +92 -16
  131. ksadk/runtime/executor.py +78 -2
  132. ksadk/runtime/factory.py +29 -273
  133. ksadk/runtime/framework_adapters.py +23 -0
  134. ksadk/runtime/preprocessing.py +10 -2
  135. ksadk/runtime/runner_adapter.py +73 -14
  136. ksadk/runtime_context.py +40 -2
  137. ksadk/sandbox/backends/e2b.py +52 -11
  138. ksadk/sandbox/backends/local_process.py +9 -0
  139. ksadk/sandbox/base.py +2 -0
  140. ksadk/sandbox/e2b_connection.py +66 -0
  141. ksadk/scheduler/sqlite_store.py +18 -0
  142. ksadk/server/composition.py +2 -0
  143. ksadk/server/factory.py +5 -0
  144. ksadk/server/persistence_capability.py +516 -0
  145. ksadk/server/routes/control.py +210 -46
  146. ksadk/server/routes/dependencies.py +15 -0
  147. ksadk/server/routes/models.py +47 -4
  148. ksadk/server/routes/projection.py +252 -12
  149. ksadk/server/routes/sessions.py +284 -107
  150. ksadk/server/routes/streaming.py +43 -9
  151. ksadk/server/static/assets/{ArtifactsPanel-10GPXIJ6.js → ArtifactsPanel-CGbWlMNh.js} +1 -1
  152. ksadk/server/static/assets/{CodeBlock-BXk1l-G1.js → CodeBlock-b4C7upmO.js} +3 -3
  153. ksadk/server/static/assets/{MathMessageMarkdown-D9uB55Oh.js → MathMessageMarkdown-DbdW5A4_.js} +4 -4
  154. ksadk/server/static/assets/{MermaidBlock--OEYoXIJ.js → MermaidBlock-BEBN4Ksz.js} +6 -6
  155. ksadk/server/static/assets/{NativeTerminalPanel-DrEe1syq.js → NativeTerminalPanel-zvL-WpAn.js} +1 -1
  156. ksadk/server/static/assets/{abnfDiagram-VCTEODGH-eeTFJLvo.js → abnfDiagram-VCTEODGH-BYafW7Za.js} +1 -1
  157. ksadk/server/static/assets/{arc-S3ZNbIAd.js → arc-bTohInsS.js} +1 -1
  158. ksadk/server/static/assets/architecture-7GRP2DOG-BW5UtSnx.js +1 -0
  159. ksadk/server/static/assets/{architectureDiagram-5GKGNRK7-CRjgEJDX.js → architectureDiagram-5GKGNRK7-Ch5Lbzsi.js} +1 -1
  160. ksadk/server/static/assets/{blockDiagram-NRAW4CY4-C7bsBoNH.js → blockDiagram-NRAW4CY4-kqF4MDOG.js} +1 -1
  161. ksadk/server/static/assets/{c4Diagram-UCG6FXSJ-BX3c33Ob.js → c4Diagram-UCG6FXSJ-8uSRIODv.js} +1 -1
  162. ksadk/server/static/assets/channel-CF5Up3hQ.js +1 -0
  163. ksadk/server/static/assets/chunk-2Q5K7J3B-KkXX47WI.js +1 -0
  164. ksadk/server/static/assets/{chunk-5VM5RSS4-bZ7ws-8m.js → chunk-5VM5RSS4-DkhehZDr.js} +1 -1
  165. ksadk/server/static/assets/{chunk-F27PBJKO-D2r0pvhY.js → chunk-F27PBJKO-BdXhtPe9.js} +1 -1
  166. ksadk/server/static/assets/{chunk-G27WJ6UU-CZwF3oUP.js → chunk-G27WJ6UU-DPTpvpwi.js} +1 -1
  167. ksadk/server/static/assets/{chunk-JWPE2WC7-DigFYCML.js → chunk-JWPE2WC7-Pqoh38el.js} +1 -1
  168. ksadk/server/static/assets/{chunk-LCL6LL3I-CnorGV5q.js → chunk-LCL6LL3I-DeU00qC-.js} +1 -1
  169. ksadk/server/static/assets/{chunk-POPQ4Y6H-CexntQA-.js → chunk-POPQ4Y6H-CzxScFkr.js} +1 -1
  170. ksadk/server/static/assets/{chunk-RHFEMEQ7-CHTC7UxA.js → chunk-RHFEMEQ7-DpqMx-ux.js} +1 -1
  171. ksadk/server/static/assets/{chunk-SVP7TREG-BC1EWt_-.js → chunk-SVP7TREG-C6t0SypQ.js} +1 -1
  172. ksadk/server/static/assets/{chunk-XXDRQBXY-BTG24xN0.js → chunk-XXDRQBXY-DVaeafZk.js} +1 -1
  173. ksadk/server/static/assets/classDiagram-DTDB5LWJ-Cz81acRQ.js +1 -0
  174. ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-Cz81acRQ.js +1 -0
  175. ksadk/server/static/assets/{cose-bilkent-JH36ORCC-CkonRdAS.js → cose-bilkent-JH36ORCC-Bf9D3tzJ.js} +1 -1
  176. ksadk/server/static/assets/cynefin-OW5HDTMX-DVWs8a2t.js +1 -0
  177. ksadk/server/static/assets/{cynefinDiagram-5FMLGOSQ-DEOCBe15.js → cynefinDiagram-5FMLGOSQ-B9cY3iTz.js} +1 -1
  178. ksadk/server/static/assets/{dagre-3AP2YEHR-DBThPuLa.js → dagre-3AP2YEHR-CSwlx3CB.js} +1 -1
  179. ksadk/server/static/assets/{dagre-ClTPrTht.js → dagre-UBpgon5q.js} +1 -1
  180. ksadk/server/static/assets/{diagram-S7CK7UJ4-DsZHrnpJ.js → diagram-S7CK7UJ4-C9akhN9a.js} +1 -1
  181. ksadk/server/static/assets/{diagram-UQ7AKVKN-BJR4nhVr.js → diagram-UQ7AKVKN-CgedhTPI.js} +1 -1
  182. ksadk/server/static/assets/{diagram-VSXAHHWV-xzcERX0a.js → diagram-VSXAHHWV-Cjucz5BY.js} +1 -1
  183. ksadk/server/static/assets/{diagram-VX7I27RA-tn2xM1xu.js → diagram-VX7I27RA-Dd4Vleyn.js} +1 -1
  184. ksadk/server/static/assets/{diagram-Z3DM3KII-BZPGBkw5.js → diagram-Z3DM3KII-CZ2jGtYW.js} +1 -1
  185. ksadk/server/static/assets/{dist-DdRBIceA.js → dist-B2_CVgKv.js} +1 -1
  186. ksadk/server/static/assets/{dist-Cq4OL6nO.js → dist-B3FR1SKK.js} +1 -1
  187. ksadk/server/static/assets/{dist-M67Hwu0n.js → dist-BIr4DSRq.js} +1 -1
  188. ksadk/server/static/assets/{dist-B1oWRmrH.js → dist-BgV_owcB.js} +1 -1
  189. ksadk/server/static/assets/{dist-DyqV4fL4.js → dist-Bj730Ib4.js} +1 -1
  190. ksadk/server/static/assets/{dist-DfGFrb0v.js → dist-BnaTiyzN.js} +1 -1
  191. ksadk/server/static/assets/{dist-C71CsujO.js → dist-C1NMAY5a.js} +1 -1
  192. ksadk/server/static/assets/{dist-CXpH_Rdd.js → dist-C5_ZAZsG.js} +1 -1
  193. ksadk/server/static/assets/{dist-DJmCPRVB.js → dist-CB9iJrvg.js} +1 -1
  194. ksadk/server/static/assets/{dist-DjhwGUgZ.js → dist-CFzsn6BG.js} +1 -1
  195. ksadk/server/static/assets/{dist-BI1qQH4n.js → dist-Cf125P_m.js} +1 -1
  196. ksadk/server/static/assets/{dist-8VWI-2bZ.js → dist-ClYUxfeK.js} +1 -1
  197. ksadk/server/static/assets/{dist-DUwKa_l6.js → dist-DFD6Qa6T.js} +1 -1
  198. ksadk/server/static/assets/{dist-B-46q3Hk.js → dist-DVCOWtha.js} +1 -1
  199. ksadk/server/static/assets/{dist-BJLUwH6W.js → dist-D_ctSS2i.js} +1 -1
  200. ksadk/server/static/assets/{dist-4zN1_tq5.js → dist-DiixqL0J.js} +1 -1
  201. ksadk/server/static/assets/{dist-B0gdk4rl.js → dist-DoVSwoDb.js} +1 -1
  202. ksadk/server/static/assets/{dist-Bbwqa8TG.js → dist-DvFK7p5S.js} +1 -1
  203. ksadk/server/static/assets/{dist-D1V3f1B4.js → dist-QfkEHOlb.js} +1 -1
  204. ksadk/server/static/assets/{dist-Btyo4vX4.js → dist-btbmmX5O.js} +1 -1
  205. ksadk/server/static/assets/{dist-u8tVH5Ak.js → dist-fBO2v5Kt.js} +1 -1
  206. ksadk/server/static/assets/{dist-DQAB0qn_.js → dist-ufY3F5p6.js} +1 -1
  207. ksadk/server/static/assets/{ebnfDiagram-PWID7BFC-DVfMsLge.js → ebnfDiagram-PWID7BFC-Ci8NqqZu.js} +1 -1
  208. ksadk/server/static/assets/{erDiagram-SSCWMZ5O-CWEZSYaw.js → erDiagram-SSCWMZ5O-CCIOhLZG.js} +1 -1
  209. ksadk/server/static/assets/eventmodeling-NTZA5JFV-CQqR2hg3.js +1 -0
  210. ksadk/server/static/assets/flowDiagram-A5DVABFB-DDRRbGPm.js +1 -0
  211. ksadk/server/static/assets/{ganttDiagram-EL5Y4UJY-TWIxoyYL.js → ganttDiagram-EL5Y4UJY-Cp_r9Hb6.js} +1 -1
  212. ksadk/server/static/assets/gitGraph-4MIJSDKK-fgWEf7UD.js +1 -0
  213. ksadk/server/static/assets/{gitGraphDiagram-WWUBYQGX-DDh2hd2S.js → gitGraphDiagram-WWUBYQGX-Dlhc8Wr8.js} +1 -1
  214. ksadk/server/static/assets/index-DcTML1Up.css +2 -0
  215. ksadk/server/static/assets/index-Dh2XHqPK.js +244 -0
  216. ksadk/server/static/assets/info-A6RAGUB7-BUecLTdt.js +1 -0
  217. ksadk/server/static/assets/{infoDiagram-RXCK75RN-CgoyWiDR.js → infoDiagram-RXCK75RN-CO0rRTRA.js} +1 -1
  218. ksadk/server/static/assets/{ishikawaDiagram-5VMMS53U-CyRIu_om.js → ishikawaDiagram-5VMMS53U-CHiaedSS.js} +1 -1
  219. ksadk/server/static/assets/{journeyDiagram-EYS64GPL-DN5JXHzN.js → journeyDiagram-EYS64GPL-CHcCIB09.js} +1 -1
  220. ksadk/server/static/assets/{kanban-definition-3QL26DDD-CNP3ui66.js → kanban-definition-3QL26DDD-CJ_ebBZf.js} +1 -1
  221. ksadk/server/static/assets/{katex-DWEzQy1d.js → katex-B4weu383.js} +1 -1
  222. ksadk/server/static/assets/{linear-C-qHp7d2.js → linear-V-MgYHW1.js} +1 -1
  223. ksadk/server/static/assets/{mermaid-parser.core-Cl-K943T.js → mermaid-parser.core-CBijEX_c.js} +2 -2
  224. ksadk/server/static/assets/{mindmap-definition-FBJOCRG2-D5DB5mYm.js → mindmap-definition-FBJOCRG2-Bc-pQvpp.js} +1 -1
  225. ksadk/server/static/assets/packet-AYTQ26CC-BeW-btFv.js +1 -0
  226. ksadk/server/static/assets/{pegDiagram-XKGWAZYB-BQVc9ia_.js → pegDiagram-XKGWAZYB-D7genGLl.js} +1 -1
  227. ksadk/server/static/assets/pie-WAS4IAKB-X0xh4SaT.js +1 -0
  228. ksadk/server/static/assets/{pieDiagram-E7YTZNPT-B6UCAvtY.js → pieDiagram-E7YTZNPT-Bxj32zwD.js} +1 -1
  229. ksadk/server/static/assets/{quadrantDiagram-AXDQQJYC-mIr2d3eb.js → quadrantDiagram-AXDQQJYC-BURv2mGh.js} +1 -1
  230. ksadk/server/static/assets/radar-RG4KPBEZ-DzRMSqjd.js +1 -0
  231. ksadk/server/static/assets/railroad-74A4TZTK-Cc44icX-.js +1 -0
  232. ksadk/server/static/assets/railroad-abnf-HS5TGJTU-D6S4BdV-.js +1 -0
  233. ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-vD3aVE2o.js +1 -0
  234. ksadk/server/static/assets/railroad-peg-WCYAUIDC-CYbW_b4T.js +1 -0
  235. ksadk/server/static/assets/{railroadDiagram-O6MQD6OU-Dt3FFDmK.js → railroadDiagram-O6MQD6OU-CCsh3avW.js} +1 -1
  236. ksadk/server/static/assets/{requirementDiagram-EFPCY7ZU-Cz_vQtgF.js → requirementDiagram-EFPCY7ZU-_FRRBKEd.js} +1 -1
  237. ksadk/server/static/assets/{sankeyDiagram-P5KCCOFB-wlO1TsH5.js → sankeyDiagram-P5KCCOFB-C-gr2o9M.js} +1 -1
  238. ksadk/server/static/assets/{sequenceDiagram-WJ2MYXX4-CHRbElYq.js → sequenceDiagram-WJ2MYXX4-D97NmfKg.js} +1 -1
  239. ksadk/server/static/assets/{sizeCapture-X5ZJPWSS-DXX54iyO.js → sizeCapture-X5ZJPWSS-DjrPC5FX.js} +1 -1
  240. ksadk/server/static/assets/{stateDiagram-HBIQ2CUA-Dp_lw9II.js → stateDiagram-HBIQ2CUA-DzMNg1hh.js} +1 -1
  241. ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-BIcjKFhF.js +1 -0
  242. ksadk/server/static/assets/{swimlanes-XN3QIQJK-D8O5UlLG.js → swimlanes-XN3QIQJK-Cssf_CsU.js} +1 -1
  243. ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-tq3K3Ybl.js +8 -0
  244. ksadk/server/static/assets/{timeline-definition-24CTP7MA-8mfKcxvG.js → timeline-definition-24CTP7MA-BWTHzyS1.js} +1 -1
  245. ksadk/server/static/assets/treeView-Q6P3EWNA-DBXt3GdU.js +1 -0
  246. ksadk/server/static/assets/treemap-WGGIJYW6-DrCy4E_l.js +1 -0
  247. ksadk/server/static/assets/{vennDiagram-4TSXK5OY-EnNl0DE7.js → vennDiagram-4TSXK5OY-BSKgJsmR.js} +1 -1
  248. ksadk/server/static/assets/wardley-WFR3VGLG-CefhOliM.js +1 -0
  249. ksadk/server/static/assets/{wardleyDiagram-VM6X3IG4-DBu5fbYr.js → wardleyDiagram-VM6X3IG4-eflHNoaZ.js} +1 -1
  250. ksadk/server/static/assets/{xychartDiagram-S5SC5T6Z-BSVXs4IY.js → xychartDiagram-S5SC5T6Z-eYqrQ-v4.js} +1 -1
  251. ksadk/server/static/index.html +2 -2
  252. ksadk/session_context.py +66 -0
  253. ksadk/sessions/__init__.py +11 -21
  254. ksadk/sessions/_local_service_sync.py +263 -1
  255. ksadk/sessions/base.py +176 -0
  256. ksadk/sessions/errors.py +4 -0
  257. ksadk/sessions/in_memory.py +309 -19
  258. ksadk/sessions/local_service.py +83 -1
  259. ksadk/sessions/persistence.py +275 -0
  260. ksadk/sessions/postgres_service.py +358 -0
  261. ksadk/sessions/resilience.py +8 -0
  262. ksadk/sessions/resilient.py +362 -4
  263. ksadk/sessions/topology.py +135 -0
  264. ksadk/skills/models.py +26 -4
  265. ksadk/skills/package_store.py +186 -38
  266. ksadk/skills/runtime/agent.py +31 -6
  267. ksadk/skills/runtime/artifact_delivery.py +139 -0
  268. ksadk/skills/runtime/backends/e2b.py +98 -6
  269. ksadk/skills/runtime/backends/local.py +73 -8
  270. ksadk/skills/runtime/base.py +3 -0
  271. ksadk/skills/runtime/executor.py +2 -0
  272. ksadk/skills/runtime/loader.py +10 -2
  273. ksadk/skills/runtime/pinned.py +114 -0
  274. ksadk/skills/runtime/request.py +31 -0
  275. ksadk/skills/service_client.py +167 -28
  276. ksadk/studio/api.py +224 -42
  277. ksadk/studio/api_catalog_routes.py +18 -0
  278. ksadk/studio/api_plugin_routes.py +526 -95
  279. ksadk/studio/api_resource_connections.py +183 -0
  280. ksadk/studio/authoring_coordinator.py +19 -14
  281. ksadk/studio/builder.py +76 -0
  282. ksadk/studio/cloud.py +342 -104
  283. ksadk/studio/cloud_shared_web.py +565 -0
  284. ksadk/studio/codex_agent_service.py +128 -26
  285. ksadk/studio/codex_builder.py +241 -2
  286. ksadk/studio/codex_credentials.py +90 -0
  287. ksadk/studio/codex_manifest.py +31 -4
  288. ksadk/studio/codex_plugin_store.py +746 -0
  289. ksadk/studio/codex_provider_build.py +231 -0
  290. ksadk/studio/codex_run.py +184 -25
  291. ksadk/studio/compatibility_report.py +12 -1
  292. ksadk/studio/compiler.py +78 -14
  293. ksadk/studio/contracts.py +132 -6
  294. ksadk/studio/dsh_application.py +137 -0
  295. ksadk/studio/dsh_capability_service.py +1107 -0
  296. ksadk/studio/dsh_models.py +59 -0
  297. ksadk/studio/dsh_provider_registration.py +320 -13
  298. ksadk/studio/hosted_kernel.py +88 -13
  299. ksadk/studio/mcp_runtime.py +11 -3
  300. ksadk/studio/model_client.py +2 -2
  301. ksadk/studio/plugin_composition.py +190 -23
  302. ksadk/studio/plugin_kernel_adapter.py +12 -112
  303. ksadk/studio/plugin_runtime.py +224 -45
  304. ksadk/studio/resource_authority.py +637 -0
  305. ksadk/studio/resource_binding_validation.py +77 -0
  306. ksadk/studio/resource_build_admission.py +196 -0
  307. ksadk/studio/resource_build_materializer.py +149 -0
  308. ksadk/studio/resource_catalog.py +143 -2
  309. ksadk/studio/resource_connections.py +220 -0
  310. ksadk/studio/run_service.py +462 -52
  311. ksadk/studio/runtime_source.py +15 -7
  312. ksadk/studio/scheduler_assistant.py +317 -0
  313. ksadk/studio/scheduler_runtime.py +9 -0
  314. ksadk/studio/scheduler_service.py +3 -0
  315. ksadk/studio/service.py +490 -44
  316. ksadk/studio/shared_web.py +446 -62
  317. ksadk/studio/static/assets/CodeBlock-DCUUY0PL-BLjA7kbS.js +41 -0
  318. ksadk/studio/static/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  319. ksadk/studio/static/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  320. ksadk/studio/static/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  321. ksadk/studio/static/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  322. ksadk/studio/static/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  323. ksadk/studio/static/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  324. ksadk/studio/static/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  325. ksadk/studio/static/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  326. ksadk/studio/static/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  327. ksadk/studio/static/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  328. ksadk/studio/static/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  329. ksadk/studio/static/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  330. ksadk/studio/static/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  331. ksadk/studio/static/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  332. ksadk/studio/static/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  333. ksadk/studio/static/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  334. ksadk/studio/static/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  335. ksadk/studio/static/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  336. ksadk/studio/static/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  337. ksadk/studio/static/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  338. ksadk/studio/static/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  339. ksadk/studio/static/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  340. ksadk/studio/static/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  341. ksadk/studio/static/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  342. ksadk/studio/static/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  343. ksadk/studio/static/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  344. ksadk/studio/static/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  345. ksadk/studio/static/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  346. ksadk/studio/static/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  347. ksadk/studio/static/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  348. ksadk/studio/static/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  349. ksadk/studio/static/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  350. ksadk/studio/static/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  351. ksadk/studio/static/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  352. ksadk/studio/static/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  353. ksadk/studio/static/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  354. ksadk/studio/static/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  355. ksadk/studio/static/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  356. ksadk/studio/static/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  357. ksadk/studio/static/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  358. ksadk/studio/static/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  359. ksadk/studio/static/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  360. ksadk/studio/static/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  361. ksadk/studio/static/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  362. ksadk/studio/static/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  363. ksadk/studio/static/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  364. ksadk/studio/static/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  365. ksadk/studio/static/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  366. ksadk/studio/static/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  367. ksadk/studio/static/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  368. ksadk/studio/static/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  369. ksadk/studio/static/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  370. ksadk/studio/static/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  371. ksadk/studio/static/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  372. ksadk/studio/static/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  373. ksadk/studio/static/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  374. ksadk/studio/static/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  375. ksadk/studio/static/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  376. ksadk/studio/static/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  377. ksadk/studio/static/assets/MathMessageMarkdown-CBcDrAw--BEOyPC3w.css +1 -0
  378. ksadk/studio/static/assets/MathMessageMarkdown-CBcDrAw--CUYIXwgI.js +8 -0
  379. ksadk/studio/static/assets/MermaidBlock-DBFTztfQ-BTYKWEbD.js +44 -0
  380. ksadk/studio/static/assets/PrismRenderer-wiXRHURw.js +3 -0
  381. ksadk/studio/static/assets/abnfDiagram-VCTEODGH-CLETGjKq.js +1 -0
  382. ksadk/studio/static/assets/arc-Pry-7G1_.js +1 -0
  383. ksadk/studio/static/assets/architecture-7GRP2DOG-hXMiO_AU.js +1 -0
  384. ksadk/studio/static/assets/architectureDiagram-5GKGNRK7-B5EQysk6.js +36 -0
  385. ksadk/studio/static/assets/array-BifhSqXX.js +1 -0
  386. ksadk/studio/static/assets/blockDiagram-I7D4REHJ-CFmPl1de.js +129 -0
  387. ksadk/studio/static/assets/c4Diagram-7LVT6UL2-BRrGu8qt.js +38 -0
  388. ksadk/studio/static/assets/channel-BqO-gtEw.js +1 -0
  389. ksadk/studio/static/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
  390. ksadk/studio/static/assets/chunk-4HAMMTFA-D220vUtq.js +62 -0
  391. ksadk/studio/static/assets/chunk-5VM5RSS4-ZNzvKenW.js +15 -0
  392. ksadk/studio/static/assets/chunk-75Z2AOVW-C8lLv_qc.js +2 -0
  393. ksadk/studio/static/assets/chunk-DU6HZSFF-C4DtVpCu.js +128 -0
  394. ksadk/studio/static/assets/chunk-F27PBJKO-Cpw14SNG.js +1 -0
  395. ksadk/studio/static/assets/chunk-FOHPRMQF-DHwB1DNv.js +161 -0
  396. ksadk/studio/static/assets/chunk-GMAD6QVW-DiQA-u2N.js +72 -0
  397. ksadk/studio/static/assets/chunk-GVQU2GXP-DUdNBUCi.js +1 -0
  398. ksadk/studio/static/assets/chunk-IMKFNOWR-BSlbjT_b.js +231 -0
  399. ksadk/studio/static/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
  400. ksadk/studio/static/assets/chunk-L3NEJ4N5-Db8Ab22W.js +1 -0
  401. ksadk/studio/static/assets/chunk-OSK3NFVY-M2m6G3j4.js +10 -0
  402. ksadk/studio/static/assets/chunk-P2QGCYS3-DezaQxiK.js +1 -0
  403. ksadk/studio/static/assets/chunk-POPQ4Y6H-DOpufJ3t.js +1 -0
  404. ksadk/studio/static/assets/chunk-PWAF6VOD-CfLb1gSc.js +1 -0
  405. ksadk/studio/static/assets/chunk-SHT3W25Y-DAyIVp5H.js +168 -0
  406. ksadk/studio/static/assets/chunk-SVP7TREG-DulomOrS.js +88 -0
  407. ksadk/studio/static/assets/chunk-TICWLB2K-bHJYoflj.js +206 -0
  408. ksadk/studio/static/assets/chunk-XXDRQBXY-7PcdR2B1.js +1 -0
  409. ksadk/studio/static/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
  410. ksadk/studio/static/assets/classDiagram-ZZMXUADV-D_bW8JjA.js +1 -0
  411. ksadk/studio/static/assets/classDiagram-v2-VYDZK3BY-D_bW8JjA.js +1 -0
  412. ksadk/studio/static/assets/cose-bilkent-JH36ORCC-snL88wkX.js +1 -0
  413. ksadk/studio/static/assets/cynefin-OW5HDTMX-Bd1YhRo1.js +1 -0
  414. ksadk/studio/static/assets/cynefinDiagram-5FMLGOSQ-BBrIG_mI.js +62 -0
  415. ksadk/studio/static/assets/cytoscape.esm-CGd-uY3x.js +321 -0
  416. ksadk/studio/static/assets/dagre-GXQ25YYZ-DtF1nGdY.js +4 -0
  417. ksadk/studio/static/assets/dagre-PrKaheQc.js +1 -0
  418. ksadk/studio/static/assets/defaultLocale-BFoDCU3G.js +1 -0
  419. ksadk/studio/static/assets/diagram-S7CK7UJ4-0BZ98mya.js +30 -0
  420. ksadk/studio/static/assets/diagram-UQ7AKVKN-6mLKEo6L.js +41 -0
  421. ksadk/studio/static/assets/diagram-VSXAHHWV-CJBIaiZ2.js +3 -0
  422. ksadk/studio/static/assets/diagram-VX7I27RA-BohLEE1C.js +24 -0
  423. ksadk/studio/static/assets/diagram-Z3DM3KII-D8KIGonG.js +24 -0
  424. ksadk/studio/static/assets/dist-v5Q1xZ2K.js +1 -0
  425. ksadk/studio/static/assets/ebnfDiagram-PWID7BFC-C99HU61t.js +1 -0
  426. ksadk/studio/static/assets/erDiagram-RLTQ6QDP-DLGry2Ap.js +99 -0
  427. ksadk/studio/static/assets/eventmodeling-NTZA5JFV-B1_5Ac8j.js +1 -0
  428. ksadk/studio/static/assets/flowDiagram-HODETNUW-DD5hmicn.js +1 -0
  429. ksadk/studio/static/assets/ganttDiagram-EL5Y4UJY-BPJrVLSG.js +292 -0
  430. ksadk/studio/static/assets/gitGraph-4MIJSDKK-Cy_ZQBGi.js +1 -0
  431. ksadk/studio/static/assets/gitGraphDiagram-WWUBYQGX-CZCUz4MT.js +106 -0
  432. ksadk/studio/static/assets/graphlib-DS17s2tU.js +1 -0
  433. ksadk/studio/static/assets/index-CeHL9ARV.css +2 -0
  434. ksadk/studio/static/assets/index-D9QEcVpL.js +320 -0
  435. ksadk/studio/static/assets/info-A6RAGUB7-DBzDQB_I.js +1 -0
  436. ksadk/studio/static/assets/infoDiagram-27XIBGKW-B-sq07Hi.js +2 -0
  437. ksadk/studio/static/assets/init-C-OQMol4.js +1 -0
  438. ksadk/studio/static/assets/ishikawaDiagram-5VMMS53U-CljI2wyf.js +70 -0
  439. ksadk/studio/static/assets/journeyDiagram-3NMN7TZE-D50Fo2sL.js +139 -0
  440. ksadk/studio/static/assets/kanban-definition-UXKFOSKX-DimfOTam.js +89 -0
  441. ksadk/studio/static/assets/katex-DhON-x74.js +257 -0
  442. ksadk/studio/static/assets/line-CX5BOOUP.js +1 -0
  443. ksadk/studio/static/assets/linear-BCxN9JLv.js +1 -0
  444. ksadk/studio/static/assets/mermaid-parser.core-BdCz8fkS.js +7 -0
  445. ksadk/studio/static/assets/mindmap-definition-YA3MSWOX-Bizzqy5R.js +96 -0
  446. ksadk/studio/static/assets/ordinal-BDEzSJ7C.js +1 -0
  447. ksadk/studio/static/assets/packet-AYTQ26CC-gPln-_kG.js +1 -0
  448. ksadk/studio/static/assets/path-fybaL0A-.js +1 -0
  449. ksadk/studio/static/assets/pegDiagram-XKGWAZYB-Dy3fB-gW.js +1 -0
  450. ksadk/studio/static/assets/pie-WAS4IAKB-qZdHMr7B.js +1 -0
  451. ksadk/studio/static/assets/pieDiagram-E7YTZNPT-B9mrFSDF.js +39 -0
  452. ksadk/studio/static/assets/quadrantDiagram-AXDQQJYC-NzUfCbMR.js +7 -0
  453. ksadk/studio/static/assets/radar-RG4KPBEZ-BZlnaea9.js +1 -0
  454. ksadk/studio/static/assets/railroad-74A4TZTK-Ce3__H9c.js +1 -0
  455. ksadk/studio/static/assets/railroad-abnf-HS5TGJTU-DqQn7EzD.js +1 -0
  456. ksadk/studio/static/assets/railroad-ebnf-LZEXJU2U-B55kCA8F.js +1 -0
  457. ksadk/studio/static/assets/railroad-peg-WCYAUIDC-DfQnvkHd.js +1 -0
  458. ksadk/studio/static/assets/railroadDiagram-O6MQD6OU-DnhMjZCk.js +1 -0
  459. ksadk/studio/static/assets/requirementDiagram-BXWQKSXE-BF3d103U.js +84 -0
  460. ksadk/studio/static/assets/rolldown-runtime-Dy4uBu1J-DK3Fl9T5.js +1 -0
  461. ksadk/studio/static/assets/rough.esm-Dy-Kn_BL.js +1 -0
  462. ksadk/studio/static/assets/sankeyDiagram-P5KCCOFB-Bo-JTwt0.js +40 -0
  463. ksadk/studio/static/assets/sequenceDiagram-WJ2MYXX4-Dh4wZtUm.js +162 -0
  464. ksadk/studio/static/assets/sizeCapture-INFHLROL-B0uUizjq.js +1 -0
  465. ksadk/studio/static/assets/src-SFn9St9H.js +1 -0
  466. ksadk/studio/static/assets/stateDiagram-D77RDMKH-DH774G6d.js +1 -0
  467. ksadk/studio/static/assets/stateDiagram-v2-MP3YSRHH-DZvVWPBo.js +1 -0
  468. ksadk/studio/static/assets/swimlanes-42K2YHIH-Bl13OvTX.js +1 -0
  469. ksadk/studio/static/assets/swimlanesDiagram-VR7AAH4N-BnFOTALJ.js +8 -0
  470. ksadk/studio/static/assets/timeline-definition-24CTP7MA-DxmSSjRB.js +120 -0
  471. ksadk/studio/static/assets/treeView-Q6P3EWNA-D5Nn9Swz.js +1 -0
  472. ksadk/studio/static/assets/treemap-WGGIJYW6-CgHgnQhE.js +1 -0
  473. ksadk/studio/static/assets/vennDiagram-4TSXK5OY-B9QEXcJq.js +34 -0
  474. ksadk/studio/static/assets/wardley-WFR3VGLG-DXrK2RRY.js +1 -0
  475. ksadk/studio/static/assets/wardleyDiagram-VM6X3IG4-Ba1AOWoe.js +78 -0
  476. ksadk/studio/static/assets/xychartDiagram-S5SC5T6Z-Cr5pt5Y-.js +7 -0
  477. ksadk/studio/static/index.html +2 -2
  478. ksadk/version.py +1 -1
  479. ksadk/server/static/assets/architecture-7GRP2DOG-Dk9nRQ6-.js +0 -1
  480. ksadk/server/static/assets/channel-s354Yo6o.js +0 -1
  481. ksadk/server/static/assets/chunk-2Q5K7J3B-CDpPpKR5.js +0 -1
  482. ksadk/server/static/assets/classDiagram-DTDB5LWJ-Dd0nucl9.js +0 -1
  483. ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-Dd0nucl9.js +0 -1
  484. ksadk/server/static/assets/cynefin-OW5HDTMX-BBlT4uMf.js +0 -1
  485. ksadk/server/static/assets/eventmodeling-NTZA5JFV-Dr5okd8V.js +0 -1
  486. ksadk/server/static/assets/flowDiagram-A5DVABFB-VEO-cVcO.js +0 -1
  487. ksadk/server/static/assets/gitGraph-4MIJSDKK-CKiKY9Cf.js +0 -1
  488. ksadk/server/static/assets/index-B2k_urY8.js +0 -241
  489. ksadk/server/static/assets/index-ILPt6IWF.css +0 -2
  490. ksadk/server/static/assets/info-A6RAGUB7-ubA4Nm_p.js +0 -1
  491. ksadk/server/static/assets/packet-AYTQ26CC-C7R3NUlK.js +0 -1
  492. ksadk/server/static/assets/pie-WAS4IAKB-BIT6qjr3.js +0 -1
  493. ksadk/server/static/assets/radar-RG4KPBEZ-l5noef9X.js +0 -1
  494. ksadk/server/static/assets/railroad-74A4TZTK-Baea6ZvM.js +0 -1
  495. ksadk/server/static/assets/railroad-abnf-HS5TGJTU-OKn8zZnU.js +0 -1
  496. ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-DdKAKC4l.js +0 -1
  497. ksadk/server/static/assets/railroad-peg-WCYAUIDC-Bds8udlG.js +0 -1
  498. ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-5b-8o2iS.js +0 -1
  499. ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-uf6WPRA4.js +0 -8
  500. ksadk/server/static/assets/treeView-Q6P3EWNA-CK5CSrSO.js +0 -1
  501. ksadk/server/static/assets/treemap-WGGIJYW6-Ch2BKgAM.js +0 -1
  502. ksadk/server/static/assets/wardley-WFR3VGLG-YW3Q0ml_.js +0 -1
  503. ksadk/studio/static/assets/PrismRenderer-IYN-ffww.js +0 -3
  504. ksadk/studio/static/assets/index-DXs1Eq4M.css +0 -1
  505. ksadk/studio/static/assets/index-DeDqwTsD.js +0 -283
  506. {agentengine_sdk_python-0.8.3.dist-info → agentengine_sdk_python-0.8.4.dist-info}/WHEEL +0 -0
  507. {agentengine_sdk_python-0.8.3.dist-info → agentengine_sdk_python-0.8.4.dist-info}/entry_points.txt +0 -0
  508. {agentengine_sdk_python-0.8.3.dist-info → agentengine_sdk_python-0.8.4.dist-info}/licenses/LICENSE +0 -0
  509. {agentengine_sdk_python-0.8.3.dist-info → agentengine_sdk_python-0.8.4.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,275 @@
1
+ """Runtime-safe PostgreSQL persistence readiness diagnostics."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ import hashlib
7
+ import os
8
+ import time
9
+ from copy import deepcopy
10
+ from typing import Any, Awaitable, Callable, Mapping
11
+
12
+ from ksadk.sessions import resolve_persistence_topology
13
+ from ksadk.sessions.topology import StorageTarget
14
+
15
+ ConnectCallable = Callable[..., Awaitable[Any]]
16
+
17
+ _STATUS_CACHE: dict[str, tuple[float, dict[str, Any]]] = {}
18
+ _CACHE_LOCK = asyncio.Lock()
19
+
20
+
21
+ class _NoopAsyncLock:
22
+ async def __aenter__(self) -> None:
23
+ return None
24
+
25
+ async def __aexit__(self, *_args: Any) -> None:
26
+ return None
27
+
28
+
29
+ def _base_status(*, target: StorageTarget, configured: bool) -> dict[str, Any]:
30
+ return {
31
+ "Configured": configured,
32
+ "Status": "checking" if configured else "not_configured",
33
+ "Ready": False,
34
+ "Backend": target.backend,
35
+ "SharedAcrossPods": False,
36
+ "EffectiveFor": "new_runs_only",
37
+ "Source": target.source,
38
+ "ReasonCode": "",
39
+ "Reason": "",
40
+ }
41
+
42
+
43
+ def _not_configured_target_status(target: StorageTarget, *, store: str) -> dict[str, Any]:
44
+ status = _base_status(target=target, configured=False)
45
+ prefix = f"{store}_" if store else ""
46
+ label = f"{store.title()} storage" if store else "Storage"
47
+ status.update(
48
+ {
49
+ "ReasonCode": f"{prefix}STORE_NOT_CONFIGURED",
50
+ "Reason": f"{label} is not configured",
51
+ }
52
+ )
53
+ return status
54
+
55
+
56
+ def _error_status(target: StorageTarget, *, code: str, reason: str) -> dict[str, Any]:
57
+ status = _base_status(target=target, configured=True)
58
+ status.update({"Status": "error", "ReasonCode": code, "Reason": reason})
59
+ return status
60
+
61
+
62
+ def _classify_probe_error(exc: BaseException) -> tuple[str, str]:
63
+ name = type(exc).__name__.lower()
64
+ if isinstance(exc, (ModuleNotFoundError, ImportError)):
65
+ return "DEPENDENCY_MISSING", "asyncpg is required for PostgreSQL persistence"
66
+ if "password" in name or "authorization" in name or "authentication" in name:
67
+ return "AUTH_FAILED", "PostgreSQL authentication failed"
68
+ if "privilege" in name or "permission" in name:
69
+ return "SCHEMA_PERMISSION_DENIED", "PostgreSQL schema permissions are insufficient"
70
+ return "STORE_UNREACHABLE", "PostgreSQL persistence is unreachable"
71
+
72
+
73
+ def _cache_key(backend: str, dsn: str) -> str:
74
+ digest = hashlib.sha256(dsn.encode("utf-8")).hexdigest()
75
+ return f"{backend}:{digest}"
76
+
77
+
78
+ def _asyncpg_dsn(dsn: str) -> str:
79
+ """Translate ADK's SQLAlchemy asyncpg URL to asyncpg's native DSN."""
80
+ prefix = "postgresql+asyncpg://"
81
+ if dsn.lower().startswith(prefix):
82
+ return "postgresql://" + dsn[len(prefix) :]
83
+ return dsn
84
+
85
+
86
+ async def _default_connect(**kwargs: Any) -> Any:
87
+ import asyncpg
88
+
89
+ return await asyncpg.connect(**kwargs)
90
+
91
+
92
+ def _status_for_target(
93
+ status: Mapping[str, Any], target: StorageTarget, *, store: str = ""
94
+ ) -> dict[str, Any]:
95
+ result = deepcopy(dict(status))
96
+ result.update({"Backend": target.backend, "Source": target.source})
97
+ if result.get("ReasonCode") == "STORE_UNREACHABLE" and store:
98
+ result["ReasonCode"] = f"{store}_STORE_UNREACHABLE"
99
+ return result
100
+
101
+
102
+ async def probe_storage_target(
103
+ target: StorageTarget,
104
+ *,
105
+ connect: ConnectCallable | None = None,
106
+ use_cache: bool = True,
107
+ store: str = "",
108
+ ) -> dict[str, Any]:
109
+ """Probe one storage target without exposing its DSN in the result."""
110
+ if target.backend != "postgres" or not target.dsn:
111
+ return _not_configured_target_status(target, store=store)
112
+
113
+ result = await _probe_postgres_target(target, connect=connect, use_cache=use_cache)
114
+ return _status_for_target(result, target, store=store)
115
+
116
+
117
+ async def _probe_postgres_target(
118
+ target: StorageTarget,
119
+ *,
120
+ connect: ConnectCallable | None,
121
+ use_cache: bool,
122
+ ) -> dict[str, Any]:
123
+ dsn = _asyncpg_dsn(target.dsn)
124
+
125
+ timeout = max(0.1, float(os.getenv("KSADK_PERSISTENCE_PROBE_TIMEOUT") or "2"))
126
+ ttl = max(0.0, float(os.getenv("KSADK_PERSISTENCE_PROBE_CACHE_TTL") or "30"))
127
+ key = _cache_key(target.backend, dsn)
128
+ now = time.monotonic()
129
+ if use_cache:
130
+ cached = _STATUS_CACHE.get(key)
131
+ if cached and now - cached[0] < ttl:
132
+ return deepcopy(cached[1])
133
+
134
+ connector = connect or _default_connect
135
+ connection = None
136
+ try:
137
+ lock = _CACHE_LOCK if use_cache else _NoopAsyncLock()
138
+ async with lock:
139
+ if use_cache:
140
+ cached = _STATUS_CACHE.get(key)
141
+ if cached and time.monotonic() - cached[0] < ttl:
142
+ return deepcopy(cached[1])
143
+ connection = await asyncio.wait_for(
144
+ connector(dsn=dsn, timeout=timeout, command_timeout=timeout),
145
+ timeout=timeout,
146
+ )
147
+ await asyncio.wait_for(connection.fetchval("SELECT 1"), timeout=timeout)
148
+ can_create = await asyncio.wait_for(
149
+ connection.fetchval(
150
+ "SELECT has_schema_privilege(current_user, current_schema(), 'CREATE')"
151
+ ),
152
+ timeout=timeout,
153
+ )
154
+ if can_create is not True:
155
+ result = _error_status(
156
+ target,
157
+ code="SCHEMA_PERMISSION_DENIED",
158
+ reason=(
159
+ "PostgreSQL account cannot create persistence tables "
160
+ "in the current schema"
161
+ ),
162
+ )
163
+ else:
164
+ result = _base_status(target=target, configured=True)
165
+ result.update(
166
+ {
167
+ "Status": "ready",
168
+ "Ready": True,
169
+ "SharedAcrossPods": True,
170
+ "ReasonCode": "READY",
171
+ "Reason": "",
172
+ }
173
+ )
174
+ if use_cache:
175
+ _STATUS_CACHE[key] = (time.monotonic(), deepcopy(result))
176
+ return deepcopy(result)
177
+ except Exception as exc:
178
+ code, reason = _classify_probe_error(exc)
179
+ result = _error_status(target, code=code, reason=reason)
180
+ if use_cache:
181
+ _STATUS_CACHE[key] = (time.monotonic(), deepcopy(result))
182
+ return deepcopy(result)
183
+ finally:
184
+ if connection is not None:
185
+ try:
186
+ await asyncio.wait_for(connection.close(), timeout=timeout)
187
+ except Exception:
188
+ pass
189
+
190
+
191
+ async def get_persistence_status(
192
+ *,
193
+ framework: str | None = None,
194
+ connect: ConnectCallable | None = None,
195
+ use_cache: bool = True,
196
+ ) -> dict[str, Any]:
197
+ """Return independent credential-free Session and Checkpoint readiness."""
198
+ topology = resolve_persistence_topology(framework=framework)
199
+ probe_tasks: dict[str, asyncio.Task[dict[str, Any]]] = {}
200
+
201
+ async def probe(target: StorageTarget, *, store: str) -> dict[str, Any]:
202
+ if target.backend != "postgres" or not target.dsn:
203
+ return _not_configured_target_status(target, store=store)
204
+ key = _cache_key(target.backend, _asyncpg_dsn(target.dsn))
205
+ if key not in probe_tasks:
206
+ probe_tasks[key] = asyncio.create_task(
207
+ _probe_postgres_target(
208
+ target,
209
+ connect=connect,
210
+ use_cache=use_cache,
211
+ )
212
+ )
213
+ return _status_for_target(await probe_tasks[key], target, store=store)
214
+
215
+ session_status, checkpoint_status = await asyncio.gather(
216
+ probe(topology.session, store="SESSION"),
217
+ probe(topology.checkpoint, store="CHECKPOINT"),
218
+ )
219
+ return {"Session": session_status, "Checkpoint": checkpoint_status}
220
+
221
+
222
+ def gate_runtime_capabilities(
223
+ capabilities: Mapping[str, Any] | None,
224
+ session_persistence: Mapping[str, Any],
225
+ checkpoint_persistence: Mapping[str, Any] | None = None,
226
+ ) -> dict[str, Any]:
227
+ """Fail closed unless Session and Checkpoint persistence are both ready."""
228
+
229
+ gated = deepcopy(dict(capabilities or {}))
230
+ checkpoint_persistence = checkpoint_persistence or session_persistence
231
+ blocked_store = (
232
+ "session" if session_persistence.get("Ready") is not True else "checkpoint"
233
+ )
234
+ unavailable = (
235
+ session_persistence if blocked_store == "session" else checkpoint_persistence
236
+ )
237
+ if unavailable.get("Ready") is True:
238
+ return gated
239
+
240
+ reason = str(unavailable.get("Reason") or "PostgreSQL persistence is unavailable")
241
+ reason_code = str(
242
+ unavailable.get("ReasonCode") or "RUNTIME_CAPABILITY_UNAVAILABLE"
243
+ )
244
+ checkpoint = dict(gated.get("Checkpoint") or {})
245
+ native_backend = str(checkpoint.get("Backend") or "").strip()
246
+ checkpoint.update(
247
+ {
248
+ "Supported": False,
249
+ "Backend": "none",
250
+ "Durable": False,
251
+ "SharedAcrossPods": False,
252
+ "ResumeMode": "none",
253
+ "ReasonCode": reason_code,
254
+ "Reason": reason,
255
+ "PersistenceGate": {
256
+ "BlockedStore": blocked_store,
257
+ "Source": str(unavailable.get("Source") or "none"),
258
+ "ReasonCode": reason_code,
259
+ "Reason": reason,
260
+ },
261
+ }
262
+ )
263
+ if native_backend:
264
+ checkpoint["NativeBackend"] = native_backend
265
+ gated["Checkpoint"] = checkpoint
266
+ gated["ResumeRun"] = {
267
+ "Supported": False,
268
+ "ResumeMode": "none",
269
+ "ReasonCode": reason_code,
270
+ "Reason": reason,
271
+ }
272
+ return gated
273
+
274
+
275
+ __all__ = ["gate_runtime_capabilities", "get_persistence_status", "probe_storage_target"]
@@ -6,6 +6,8 @@ import asyncio
6
6
  import json
7
7
  import logging
8
8
  import time
9
+ from collections.abc import AsyncIterator
10
+ from contextvars import ContextVar
9
11
  from typing import Any, Optional
10
12
  from urllib.parse import urlsplit, urlunsplit
11
13
 
@@ -19,8 +21,10 @@ from ksadk.sessions._postgres_tables import (
19
21
  from ksadk.sessions.base import (
20
22
  CANONICAL_EVENT_STORAGE_CAPABILITIES,
21
23
  BaseSessionService,
24
+ CheckpointEventQuery,
22
25
  Session,
23
26
  SessionEvent,
27
+ SessionEventQuery,
24
28
  SessionState,
25
29
  generate_id,
26
30
  )
@@ -56,6 +60,9 @@ class PostgresSessionService(_PostgresSchemaMixin, BaseSessionService):
56
60
  self._pool_lock = asyncio.Lock()
57
61
  self._schema_ready = False
58
62
  self._schema_lock = asyncio.Lock()
63
+ self._checkpoint_snapshot_connection: ContextVar[Any | None] = ContextVar(
64
+ f"checkpoint_snapshot_connection_{id(self)}", default=None
65
+ )
59
66
 
60
67
  async def create_session(
61
68
  self,
@@ -489,6 +496,357 @@ class PostgresSessionService(_PostgresSchemaMixin, BaseSessionService):
489
496
  """
490
497
  return int(await connection.fetchval(query, *params) or 0)
491
498
 
499
+ async def get_sessions_by_ids(self, session_ids: list[str]) -> list[Session]:
500
+ if not session_ids:
501
+ return []
502
+ await self._ensure_schema()
503
+ async with self._pool.acquire() as connection:
504
+ rows = await connection.fetch(
505
+ f"SELECT id,agent_id,user_id,title,title_source,summary,first_prompt,"
506
+ f"last_prompt,state_json,created_at,updated_at,version "
507
+ f"FROM {KSADK_PG_SESSIONS_TABLE} WHERE namespace=$1 "
508
+ "AND id=ANY($2::text[])",
509
+ self.namespace,
510
+ session_ids,
511
+ )
512
+ by_id = {row["id"]: self._session_from_row(row, events=[]) for row in rows}
513
+ return [by_id[item] for item in session_ids if item in by_id]
514
+
515
+ async def list_session_metadata(
516
+ self, agent_id: Optional[str] = None, user_id: Optional[str] = None
517
+ ) -> list[Session]:
518
+ await self._ensure_schema()
519
+ clauses = ["namespace=$1"]
520
+ params: list[Any] = [self.namespace]
521
+ if agent_id is not None:
522
+ params.append(agent_id)
523
+ clauses.append(f"agent_id=${len(params)}")
524
+ if user_id is not None:
525
+ params.append(user_id)
526
+ clauses.append(f"user_id=${len(params)}")
527
+ async with self._pool.acquire() as connection:
528
+ rows = await connection.fetch(
529
+ f"SELECT id,agent_id,user_id,title,title_source,summary,first_prompt,"
530
+ f"last_prompt,state_json,created_at,updated_at,version "
531
+ f"FROM {KSADK_PG_SESSIONS_TABLE} WHERE {' AND '.join(clauses)} "
532
+ "ORDER BY updated_at DESC,created_at DESC,id DESC",
533
+ *params,
534
+ )
535
+ return [self._session_from_row(row, events=[]) for row in rows]
536
+
537
+ def _batch_event_where(self, query: SessionEventQuery) -> tuple[list[str], list[Any]]:
538
+ clauses = ["event_row.namespace=$1"]
539
+ params: list[Any] = [self.namespace]
540
+ if query.session_ids is not None:
541
+ if not query.session_ids:
542
+ return ["FALSE"], []
543
+ params.append(query.session_ids)
544
+ clauses.append(f"event_row.session_id=ANY(${len(params)}::text[])")
545
+ for value, clause in (
546
+ (query.agent_id, "session_row.agent_id"),
547
+ (query.after_seq_id, "event_row.seq_id >"),
548
+ (query.before_seq_id, "event_row.seq_id <"),
549
+ (query.invocation_id, "event_row.invocation_id"),
550
+ ):
551
+ if value is not None:
552
+ params.append(value)
553
+ operator = "" if clause.endswith((">", "<")) else "="
554
+ clauses.append(f"{clause}{operator}${len(params)}")
555
+ if query.event_types:
556
+ params.append(query.event_types)
557
+ clauses.append(f"event_row.event_type=ANY(${len(params)}::text[])")
558
+ if query.run_id is not None:
559
+ params.append(query.run_id)
560
+ clauses.append(
561
+ "(event_row.metadata_json->>'run_id'="
562
+ f"${len(params)}"
563
+ " OR (event_row.event_type='continuation.created'"
564
+ f" AND event_row.content_json->'runtime_event'->>'run_id'=${len(params)}))"
565
+ )
566
+ if query.checkpoint_id is not None:
567
+ params.append(query.checkpoint_id)
568
+ clauses.append(
569
+ "(event_row.metadata_json->>'checkpoint_id'="
570
+ f"${len(params)}"
571
+ " OR (event_row.event_type='continuation.created'"
572
+ f" AND event_row.content_json->'runtime_event'->>'continuation_id'=${len(params)}))"
573
+ )
574
+ if query.checkpoint_ids:
575
+ params.append(query.checkpoint_ids)
576
+ clauses.append(
577
+ "(event_row.metadata_json->>'checkpoint_id'=ANY("
578
+ f"${len(params)}::text[])"
579
+ " OR (event_row.event_type='continuation.created'"
580
+ " AND event_row.content_json->'runtime_event'->>'continuation_id'=ANY("
581
+ f"${len(params)}::text[])))"
582
+ )
583
+ return clauses, params
584
+
585
+ async def query_events(self, query: SessionEventQuery) -> list[SessionEvent]:
586
+ await self._ensure_schema()
587
+ clauses, params = self._batch_event_where(query)
588
+ direction = "ASC" if query.from_start else "DESC"
589
+ order = (
590
+ f"event_row.session_id {direction},event_row.seq_id {direction},"
591
+ f"event_row.id {direction}"
592
+ if query.order_by_seq
593
+ else f"event_row.timestamp {direction},event_row.session_id {direction},"
594
+ f"event_row.seq_id {direction},event_row.id {direction}"
595
+ )
596
+ params.extend([query.limit, query.offset])
597
+ async with self._pool.acquire() as connection:
598
+ rows = await connection.fetch(
599
+ f"SELECT event_row.id,event_row.session_id,event_row.author,event_row.event_type,"
600
+ f"event_row.content_json,event_row.timestamp,event_row.state_delta_json,"
601
+ f"event_row.seq_id,event_row.invocation_id,event_row.metadata_json "
602
+ f"FROM {KSADK_PG_EVENTS_TABLE} event_row "
603
+ f"JOIN {KSADK_PG_SESSIONS_TABLE} session_row "
604
+ "ON session_row.namespace=event_row.namespace "
605
+ "AND session_row.id=event_row.session_id "
606
+ f"WHERE {' AND '.join(clauses)} ORDER BY {order} "
607
+ f"LIMIT ${len(params)-1} OFFSET ${len(params)}",
608
+ *params,
609
+ )
610
+ events = [self._event_from_row(row) for row in rows]
611
+ if not query.from_start:
612
+ events.reverse()
613
+ return events
614
+
615
+ async def count_event_query(self, query: SessionEventQuery) -> int:
616
+ await self._ensure_schema()
617
+ clauses, params = self._batch_event_where(query)
618
+ async with self._pool.acquire() as connection:
619
+ return int(
620
+ await connection.fetchval(
621
+ f"SELECT COUNT(*) FROM {KSADK_PG_EVENTS_TABLE} event_row "
622
+ f"JOIN {KSADK_PG_SESSIONS_TABLE} session_row "
623
+ "ON session_row.namespace=event_row.namespace "
624
+ "AND session_row.id=event_row.session_id "
625
+ f"WHERE {' AND '.join(clauses)}",
626
+ *params,
627
+ )
628
+ or 0
629
+ )
630
+
631
+ async def scan_checkpoint_events(
632
+ self, query: CheckpointEventQuery
633
+ ) -> list[SessionEvent]:
634
+ if query.limit < 1 or query.limit > 50:
635
+ raise ValueError("checkpoint scan limit must be between 1 and 50")
636
+ return await self._scan_checkpoint_events_with_connection(None, query)
637
+
638
+ async def _scan_checkpoint_events_with_connection(
639
+ self,
640
+ connection: Any | None,
641
+ query: CheckpointEventQuery,
642
+ cursor: tuple[float, str, int, str] | None = None,
643
+ ) -> list[SessionEvent]:
644
+ event_query = SessionEventQuery(
645
+ session_ids=query.session_ids,
646
+ agent_id=query.agent_id,
647
+ event_types=["run_checkpoint", "continuation.created"],
648
+ offset=query.offset,
649
+ limit=query.limit,
650
+ from_start=True,
651
+ )
652
+ if query.framework is None and connection is None:
653
+ return await self.query_events(event_query)
654
+ await self._ensure_schema()
655
+ clauses, params = self._batch_event_where(event_query)
656
+ if query.checkpoint_ids:
657
+ params.append(query.checkpoint_ids)
658
+ clauses.append(
659
+ "(event_row.metadata_json->>'checkpoint_id'=ANY("
660
+ f"${len(params)}::text[])"
661
+ " OR (event_row.event_type='continuation.created'"
662
+ " AND event_row.content_json->'runtime_event'->>'continuation_id'=ANY("
663
+ f"${len(params)}::text[])))"
664
+ )
665
+ if query.run_id is not None:
666
+ params.append(query.run_id)
667
+ clauses.append(
668
+ "(event_row.metadata_json->>'run_id'="
669
+ f"${len(params)}"
670
+ " OR (event_row.event_type='continuation.created'"
671
+ f" AND event_row.content_json->'runtime_event'->>'run_id'=${len(params)}))"
672
+ )
673
+ if query.framework is not None:
674
+ params.append(query.framework.lower())
675
+ clauses.append(
676
+ "(lower(event_row.metadata_json->>'framework')="
677
+ f"${len(params)}"
678
+ " OR (event_row.event_type='continuation.created'"
679
+ " AND lower(event_row.content_json->'runtime_event'->'source'->>'framework')="
680
+ f"${len(params)}))"
681
+ )
682
+ if cursor is not None:
683
+ placeholders = []
684
+ for value in cursor:
685
+ params.append(value)
686
+ placeholders.append(f"${len(params)}")
687
+ clauses.append(
688
+ "(event_row.timestamp,event_row.session_id,event_row.seq_id,event_row.id) > "
689
+ f"({','.join(placeholders)})"
690
+ )
691
+ params.extend([query.limit, query.offset])
692
+ owns_connection = connection is None
693
+ if owns_connection:
694
+ connection = await self._pool.acquire()
695
+ try:
696
+ rows = await connection.fetch(
697
+ f"SELECT event_row.id,event_row.session_id,event_row.author,event_row.event_type,"
698
+ f"event_row.content_json,event_row.timestamp,event_row.state_delta_json,"
699
+ f"event_row.seq_id,event_row.invocation_id,event_row.metadata_json "
700
+ f"FROM {KSADK_PG_EVENTS_TABLE} event_row "
701
+ f"JOIN {KSADK_PG_SESSIONS_TABLE} session_row "
702
+ "ON session_row.namespace=event_row.namespace "
703
+ "AND session_row.id=event_row.session_id "
704
+ f"WHERE {' AND '.join(clauses)} ORDER BY event_row.timestamp,event_row.session_id,"
705
+ f"event_row.seq_id,event_row.id LIMIT ${len(params)-1} OFFSET ${len(params)}",
706
+ *params,
707
+ )
708
+ return [self._event_from_row(row) for row in rows]
709
+ finally:
710
+ if owns_connection:
711
+ await self._pool.release(connection)
712
+
713
+ async def iter_checkpoint_event_chunks(
714
+ self, query: CheckpointEventQuery
715
+ ) -> AsyncIterator[list[SessionEvent]]:
716
+ if query.limit < 1 or query.limit > 50:
717
+ raise ValueError("checkpoint scan limit must be between 1 and 50")
718
+ await self._ensure_schema()
719
+ async with self._pool.acquire() as connection:
720
+ async with connection.transaction(isolation="repeatable_read", readonly=True):
721
+ token = self._checkpoint_snapshot_connection.set(connection)
722
+ try:
723
+ cursor: tuple[float, str, int, str] | None = None
724
+ first_page = True
725
+ while True:
726
+ batch = await self._scan_checkpoint_events_with_connection(
727
+ connection,
728
+ CheckpointEventQuery(
729
+ **{
730
+ **query.__dict__,
731
+ "offset": query.offset if first_page else 0,
732
+ }
733
+ ),
734
+ cursor,
735
+ )
736
+ if not batch:
737
+ break
738
+ yield batch
739
+ if len(batch) < query.limit:
740
+ break
741
+ last = batch[-1]
742
+ cursor = (
743
+ last.timestamp,
744
+ last.session_id,
745
+ last.seq_id,
746
+ last.id,
747
+ )
748
+ first_page = False
749
+ finally:
750
+ self._checkpoint_snapshot_connection.reset(token)
751
+
752
+ async def get_checkpoint_lookup_stats(
753
+ self, session_id: str, run_id: str, checkpoint_id: str
754
+ ) -> dict[str, object]:
755
+ events = await self.query_events(
756
+ SessionEventQuery(
757
+ session_ids=[session_id], run_id=run_id, limit=2**31 - 1, from_start=True
758
+ )
759
+ )
760
+ candidate = None
761
+ max_seq_id = 0
762
+ resume_count = 0
763
+ last_resumed_at = None
764
+ for event in events:
765
+ metadata = event.metadata or {}
766
+ if event.event_type == "run_checkpoint":
767
+ max_seq_id = max(max_seq_id, event.seq_id)
768
+ if str(metadata.get("checkpoint_id") or "") == checkpoint_id:
769
+ candidate = event
770
+ elif event.event_type == "run_resume" and str(
771
+ metadata.get("checkpoint_id") or ""
772
+ ) == checkpoint_id:
773
+ resume_count += 1
774
+ last_resumed_at = max(last_resumed_at or event.timestamp, event.timestamp)
775
+ return {"candidate": candidate, "max_seq_id": max_seq_id, "resume_count": resume_count,
776
+ "last_resumed_at": last_resumed_at}
777
+
778
+ async def get_checkpoint_stats(
779
+ self, keys: list[tuple[str, str, str]]
780
+ ) -> dict[str, object]:
781
+ if len(keys) > 50:
782
+ raise ValueError("checkpoint stats batch cannot exceed 50 keys")
783
+ unique_keys = list(dict.fromkeys(keys))
784
+ audits = {
785
+ key: {"resume_count": 0, "last_resumed_at": None} for key in unique_keys
786
+ }
787
+ run_keys = list(
788
+ dict.fromkeys((session_id, run_id) for session_id, run_id, _ in unique_keys)
789
+ )
790
+ latest = {key: 0 for key in run_keys}
791
+ if not unique_keys:
792
+ return {"audits": audits, "latest_seq_ids": latest}
793
+ await self._ensure_schema()
794
+ connection = self._checkpoint_snapshot_connection.get()
795
+ owns_connection = connection is None
796
+ if owns_connection:
797
+ connection = await self._pool.acquire()
798
+ try:
799
+ audit_rows = await connection.fetch(
800
+ f"""WITH requested(session_id,run_id,checkpoint_id) AS (
801
+ SELECT * FROM unnest($2::text[],$3::text[],$4::text[])
802
+ )
803
+ SELECT requested.session_id,requested.run_id,requested.checkpoint_id,
804
+ COUNT(event_row.id) AS resume_count,
805
+ MAX(event_row.timestamp) AS last_resumed_at
806
+ FROM requested
807
+ LEFT JOIN {KSADK_PG_EVENTS_TABLE} event_row
808
+ ON event_row.namespace=$1
809
+ AND event_row.session_id=requested.session_id
810
+ AND event_row.event_type='run_resume'
811
+ AND event_row.metadata_json->>'run_id'=requested.run_id
812
+ AND event_row.metadata_json->>'checkpoint_id'=requested.checkpoint_id
813
+ GROUP BY requested.session_id,requested.run_id,requested.checkpoint_id""",
814
+ self.namespace,
815
+ [key[0] for key in unique_keys],
816
+ [key[1] for key in unique_keys],
817
+ [key[2] for key in unique_keys],
818
+ )
819
+ latest_rows = await connection.fetch(
820
+ f"""WITH requested(session_id,run_id) AS (
821
+ SELECT * FROM unnest($2::text[],$3::text[])
822
+ )
823
+ SELECT requested.session_id,requested.run_id,
824
+ COALESCE(MAX(event_row.seq_id),0) AS latest_seq_id
825
+ FROM requested
826
+ LEFT JOIN {KSADK_PG_EVENTS_TABLE} event_row
827
+ ON event_row.namespace=$1
828
+ AND event_row.session_id=requested.session_id
829
+ AND event_row.event_type='run_checkpoint'
830
+ AND event_row.metadata_json->>'run_id'=requested.run_id
831
+ GROUP BY requested.session_id,requested.run_id""",
832
+ self.namespace,
833
+ [key[0] for key in run_keys],
834
+ [key[1] for key in run_keys],
835
+ )
836
+ finally:
837
+ if owns_connection:
838
+ await self._pool.release(connection)
839
+ for row in audit_rows:
840
+ audits[(row["session_id"], row["run_id"], row["checkpoint_id"])] = {
841
+ "resume_count": int(row["resume_count"] or 0),
842
+ "last_resumed_at": row["last_resumed_at"],
843
+ }
844
+ for row in latest_rows:
845
+ latest[(row["session_id"], row["run_id"])] = int(
846
+ row["latest_seq_id"] or 0
847
+ )
848
+ return {"audits": audits, "latest_seq_ids": latest}
849
+
492
850
  def _agent_events_query_parts(
493
851
  self,
494
852
  agent_id: str,
@@ -45,8 +45,16 @@ def is_session_backend_failure(exc: BaseException) -> bool:
45
45
  current,
46
46
  (SessionBackendUnavailable, TimeoutError, OSError, ConnectionError),
47
47
  ):
48
+ logger.warning(
49
+ "Session backend error; assuming backend failure: %s",
50
+ current
51
+ )
48
52
  return True
49
53
  module = type(current).__module__
50
54
  if module.startswith("asyncpg.") or module.startswith("sqlalchemy."):
55
+ logger.warning(
56
+ "SQLAlchemy error; assuming backend failure: %s",
57
+ current
58
+ )
51
59
  return True
52
60
  return False