agentengine-sdk-python 0.7.0__py3-none-any.whl → 0.8.0__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 (371) hide show
  1. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/METADATA +36 -20
  2. agentengine_sdk_python-0.8.0.dist-info/RECORD +578 -0
  3. ksadk/a2a/__init__.py +178 -11
  4. ksadk/a2a/bootstrap.py +334 -0
  5. ksadk/a2a/card.py +120 -0
  6. ksadk/a2a/context_store.py +203 -0
  7. ksadk/a2a/control_plane.py +818 -0
  8. ksadk/a2a/credential.py +99 -0
  9. ksadk/a2a/event_adapter.py +149 -0
  10. ksadk/a2a/executor.py +406 -89
  11. ksadk/a2a/external_transport.py +516 -0
  12. ksadk/a2a/identity.py +304 -0
  13. ksadk/a2a/ids.py +22 -0
  14. ksadk/a2a/langgraph.py +285 -0
  15. ksadk/a2a/resume_store.py +201 -0
  16. ksadk/a2a/routes.py +105 -0
  17. ksadk/a2a/server.py +107 -60
  18. ksadk/a2a/space_client.py +1101 -0
  19. ksadk/a2a/task_adapter.py +423 -0
  20. ksadk/a2a/task_event_dispatcher.py +167 -0
  21. ksadk/a2a/task_event_outbox.py +326 -0
  22. ksadk/a2a/task_store.py +206 -0
  23. ksadk/a2ui/__init__.py +27 -0
  24. ksadk/a2ui/core.py +186 -0
  25. ksadk/a2ui/models.py +166 -0
  26. ksadk/a2ui/renderer.py +198 -0
  27. ksadk/agui/__init__.py +9 -0
  28. ksadk/agui/a2ui_projection.py +92 -0
  29. ksadk/agui/agent.py +857 -0
  30. ksadk/agui/config.py +86 -0
  31. ksadk/agui/routes.py +55 -0
  32. ksadk/api/client.py +233 -191
  33. ksadk/builders/__init__.py +2 -0
  34. ksadk/builders/base.py +16 -14
  35. ksadk/builders/code_builder.py +318 -236
  36. ksadk/builders/container_builder.py +187 -167
  37. ksadk/builders/framework_requirements.py +29 -11
  38. ksadk/builders/ks3_uploader.py +58 -27
  39. ksadk/builders/managed_runtime_builder.py +145 -0
  40. ksadk/builders/mcp_builder.py +91 -92
  41. ksadk/builders/requirements_utils.py +1 -5
  42. ksadk/cli/__init__.py +89 -171
  43. ksadk/cli/cmd_a2a.py +254 -70
  44. ksadk/cli/cmd_agent.py +19 -5
  45. ksadk/cli/cmd_build.py +158 -29
  46. ksadk/cli/cmd_completion.py +47 -35
  47. ksadk/cli/cmd_config.py +267 -198
  48. ksadk/cli/cmd_create.py +500 -720
  49. ksadk/cli/cmd_dashboard.py +120 -45
  50. ksadk/cli/cmd_deploy.py +117 -58
  51. ksadk/cli/cmd_destroy.py +44 -14
  52. ksadk/cli/cmd_files.py +63 -24
  53. ksadk/cli/cmd_hermes.py +168 -89
  54. ksadk/cli/cmd_invoke.py +184 -122
  55. ksadk/cli/cmd_launch.py +64 -28
  56. ksadk/cli/cmd_mcp.py +98 -64
  57. ksadk/cli/cmd_model.py +14 -5
  58. ksadk/cli/cmd_openclaw.py +483 -227
  59. ksadk/cli/cmd_replay.py +71 -0
  60. ksadk/cli/cmd_run.py +33 -10
  61. ksadk/cli/cmd_status.py +80 -31
  62. ksadk/cli/cmd_version.py +20 -13
  63. ksadk/cli/cmd_web.py +89 -13
  64. ksadk/cli/deploy_utils.py +20 -20
  65. ksadk/cli/dry_run.py +5 -3
  66. ksadk/cli/error_utils.py +37 -12
  67. ksadk/cli/global_options.py +1 -2
  68. ksadk/cli/local_runtime.py +1 -2
  69. ksadk/cli/model_catalog.py +6 -2
  70. ksadk/cli/network_options.py +34 -14
  71. ksadk/cli/resource_common.py +6 -2
  72. ksadk/cli/storage.py +0 -1
  73. ksadk/cli/ui.py +5 -3
  74. ksadk/cli/workflow_common.py +51 -17
  75. ksadk/codex/__init__.py +12 -0
  76. ksadk/codex/client.py +408 -0
  77. ksadk/codex/phase.py +143 -0
  78. ksadk/codex/runtime.py +449 -0
  79. ksadk/common/aicp_env.py +0 -1
  80. ksadk/common/auth.py +2 -2
  81. ksadk/common/constants.py +1 -3
  82. ksadk/common/llm_utils.py +17 -13
  83. ksadk/compat/__init__.py +5 -0
  84. ksadk/compat/adk_compat.py +200 -0
  85. ksadk/compat/copilotkit_a2ui.py +330 -0
  86. ksadk/configs/__init__.py +12 -12
  87. ksadk/configs/env_registry.py +500 -100
  88. ksadk/configs/global_config.py +2 -1
  89. ksadk/configs/settings.py +151 -124
  90. ksadk/conversations/__init__.py +7 -5
  91. ksadk/conversations/attachment_storage.py +16 -11
  92. ksadk/conversations/attachments.py +44 -36
  93. ksadk/conversations/compaction_pipeline.py +12 -12
  94. ksadk/conversations/compaction_prompt.py +9 -5
  95. ksadk/conversations/context.py +221 -6
  96. ksadk/conversations/message_projection.py +438 -51
  97. ksadk/conversations/model_context.py +12 -6
  98. ksadk/conversations/model_options.py +0 -1
  99. ksadk/conversations/normalize.py +20 -16
  100. ksadk/conversations/reasoning_markup.py +1 -1
  101. ksadk/conversations/runtime.py +339 -5255
  102. ksadk/conversations/runtime_compaction.py +333 -0
  103. ksadk/conversations/runtime_constants.py +27 -0
  104. ksadk/conversations/runtime_governance.py +185 -0
  105. ksadk/conversations/runtime_input.py +652 -0
  106. ksadk/conversations/runtime_invocation.py +395 -0
  107. ksadk/conversations/runtime_metadata.py +475 -0
  108. ksadk/conversations/runtime_observability.py +355 -0
  109. ksadk/conversations/runtime_payloads.py +272 -0
  110. ksadk/conversations/runtime_persistence.py +440 -0
  111. ksadk/conversations/runtime_preparation.py +418 -0
  112. ksadk/conversations/runtime_resume.py +816 -0
  113. ksadk/conversations/runtime_stream_events.py +902 -0
  114. ksadk/conversations/runtime_streaming.py +547 -0
  115. ksadk/conversations/semantic_summary.py +17 -5
  116. ksadk/conversations/session_title.py +6 -3
  117. ksadk/deployment/__init__.py +15 -16
  118. ksadk/deployment/agent_access.py +12 -23
  119. ksadk/deployment/base.py +51 -38
  120. ksadk/deployment/manager.py +63 -65
  121. ksadk/deployment/providers/serverless.py +309 -202
  122. ksadk/deployment/registry.py +38 -32
  123. ksadk/deployment/state.py +11 -11
  124. ksadk/deployment/ui_config.py +1 -1
  125. ksadk/detection/__init__.py +1 -1
  126. ksadk/detection/detector.py +146 -83
  127. ksadk/detection/mcp_detector.py +9 -6
  128. ksadk/events/__init__.py +25 -0
  129. ksadk/events/parser.py +191 -0
  130. ksadk/events/replay.py +37 -0
  131. ksadk/events/runtime_event.py +264 -0
  132. ksadk/events/store.py +317 -0
  133. ksadk/harness/__init__.py +34 -0
  134. ksadk/harness/app.py +278 -0
  135. ksadk/harness/config.py +181 -0
  136. ksadk/harness/reasoner.py +105 -0
  137. ksadk/harness/runner.py +211 -0
  138. ksadk/harness/sandbox.py +141 -0
  139. ksadk/harness/tools.py +222 -0
  140. ksadk/hermes_terminal.py +23 -12
  141. ksadk/identity/resolver.py +15 -9
  142. ksadk/ids.py +32 -0
  143. ksadk/knowledge_base/adk_tool.py +1 -1
  144. ksadk/knowledge_base/client.py +23 -29
  145. ksadk/managed_runtime.py +188 -0
  146. ksadk/markdown.py +5 -2
  147. ksadk/mcp_runtime/__init__.py +9 -6
  148. ksadk/memory/__init__.py +1 -1
  149. ksadk/memory/adk/__init__.py +2 -0
  150. ksadk/memory/adk/backends/base_ltm_backend.py +2 -6
  151. ksadk/memory/adk/backends/http_ltm_backend.py +13 -21
  152. ksadk/memory/adk/backends/inmemory_ltm_backend.py +7 -13
  153. ksadk/memory/adk/backends/sdk_ltm_backend.py +26 -33
  154. ksadk/memory/adk/long_term_memory.py +31 -35
  155. ksadk/memory/adk/resilient_session_service.py +4 -5
  156. ksadk/memory/adk/short_term_memory.py +12 -21
  157. ksadk/memory/adk_tool.py +3 -2
  158. ksadk/memory/backends/base.py +19 -19
  159. ksadk/memory/backends/memory.py +24 -25
  160. ksadk/memory/backends/redis.py +31 -30
  161. ksadk/memory/langchain_tool.py +2 -1
  162. ksadk/memory/manager.py +52 -47
  163. ksadk/memory/service.py +10 -8
  164. ksadk/model_policy.py +15 -7
  165. ksadk/model_proxy/__init__.py +51 -0
  166. ksadk/model_proxy/bootstrap.py +80 -0
  167. ksadk/model_proxy/cache.py +165 -0
  168. ksadk/model_proxy/config.py +45 -0
  169. ksadk/model_proxy/demo_webui.py +115 -0
  170. ksadk/model_proxy/detect.py +145 -0
  171. ksadk/model_proxy/gate.py +68 -0
  172. ksadk/model_proxy/namespace.py +173 -0
  173. ksadk/model_proxy/protocol_proxy.py +22 -0
  174. ksadk/model_proxy/server.py +300 -0
  175. ksadk/model_proxy/transform.py +691 -0
  176. ksadk/openclaw_gateway.py +29 -14
  177. ksadk/runners/adk_runner.py +345 -120
  178. ksadk/runners/base_runner.py +46 -29
  179. ksadk/runners/codex_runner.py +132 -0
  180. ksadk/runners/deepagents_runner.py +0 -1
  181. ksadk/runners/factory.py +17 -5
  182. ksadk/runners/langchain_runner.py +29 -742
  183. ksadk/runners/langgraph_runner.py +352 -90
  184. ksadk/runners/patch_langchain.py +16 -16
  185. ksadk/runners/remote_runner.py +134 -33
  186. ksadk/runners/usage_accumulator.py +1 -0
  187. ksadk/runners/utils/langfuse.py +3 -3
  188. ksadk/runners/utils/loader.py +7 -7
  189. ksadk/runtime/__init__.py +41 -0
  190. ksadk/runtime/adapter.py +345 -0
  191. ksadk/runtime/framework_adapters.py +124 -0
  192. ksadk/runtime/preprocessing.py +118 -0
  193. ksadk/runtime/runner_adapter.py +873 -0
  194. ksadk/runtime_context.py +18 -3
  195. ksadk/runtime_state.py +0 -1
  196. ksadk/sandbox/__init__.py +4 -1
  197. ksadk/sandbox/backends/__init__.py +4 -1
  198. ksadk/sandbox/backends/e2b.py +13 -5
  199. ksadk/sandbox/backends/local_process.py +11 -3
  200. ksadk/sandbox/base.py +10 -15
  201. ksadk/sandbox/factory.py +14 -4
  202. ksadk/sandbox/registry.py +57 -6
  203. ksadk/server/api_models.py +15 -5
  204. ksadk/server/app.py +455 -3885
  205. ksadk/server/composition.py +21 -0
  206. ksadk/server/factory.py +624 -0
  207. ksadk/server/routes/__init__.py +1 -0
  208. ksadk/server/routes/checkpoint_resolution.py +116 -0
  209. ksadk/server/routes/common.py +713 -0
  210. ksadk/server/routes/control.py +327 -0
  211. ksadk/server/routes/dependencies.py +98 -0
  212. ksadk/server/routes/misc.py +448 -0
  213. ksadk/server/routes/models.py +443 -0
  214. ksadk/server/routes/openai_compat.py +207 -0
  215. ksadk/server/routes/projection.py +795 -0
  216. ksadk/server/routes/routers.py +52 -0
  217. ksadk/server/routes/run.py +726 -0
  218. ksadk/server/routes/sessions.py +649 -0
  219. ksadk/server/routes/streaming.py +223 -0
  220. ksadk/server/routes/workspace.py +381 -0
  221. ksadk/server/static/assets/{ArtifactsPanel-D-SSn2ee.js → ArtifactsPanel-Cjnqt-8W.js} +1 -1
  222. ksadk/server/static/assets/CodeBlock-BqyqZfuB.js +9 -0
  223. ksadk/server/static/assets/MathMessageMarkdown-BpH7jiFM.js +8 -0
  224. ksadk/server/static/assets/MermaidBlock-DWuxETaJ.js +303 -0
  225. ksadk/server/static/assets/NativeTerminalPanel-MDTopWMO.js +1 -0
  226. ksadk/server/static/assets/{arc-BA13sHc9.js → arc-CFKwSk_B.js} +1 -1
  227. ksadk/server/static/assets/architecture-7EHR7CIX-CynqOWjZ.js +1 -0
  228. ksadk/server/static/assets/{architectureDiagram-3BPJPVTR-DzJzgVoL.js → architectureDiagram-3BPJPVTR-Dej8jX8c.js} +1 -1
  229. ksadk/server/static/assets/{blockDiagram-GPEHLZMM-UTdVcZhn.js → blockDiagram-GPEHLZMM-1F64jqvy.js} +1 -1
  230. ksadk/server/static/assets/{c4Diagram-AAUBKEIU-Dix0GD4m.js → c4Diagram-AAUBKEIU-9q7AUAKb.js} +1 -1
  231. ksadk/server/static/assets/channel-iUGv2N24.js +1 -0
  232. ksadk/server/static/assets/{chunk-2J33WTMH-C2JxuZ42.js → chunk-2J33WTMH-6qgwJm7Q.js} +1 -1
  233. ksadk/server/static/assets/{chunk-4BX2VUAB-Be57QPgD.js → chunk-4BX2VUAB-CsWIQRhc.js} +1 -1
  234. ksadk/server/static/assets/{chunk-55IACEB6-WjSuy4nv.js → chunk-55IACEB6-BK8paA20.js} +1 -1
  235. ksadk/server/static/assets/{chunk-727SXJPM-BOovP-b5.js → chunk-727SXJPM-B-JEhy7h.js} +1 -1
  236. ksadk/server/static/assets/{chunk-AQP2D5EJ-DOmZNmWj.js → chunk-AQP2D5EJ-DYBvMHAa.js} +1 -1
  237. ksadk/server/static/assets/{chunk-FMBD7UC4-DzwlodkU.js → chunk-FMBD7UC4-BGhvzDYt.js} +1 -1
  238. ksadk/server/static/assets/{chunk-ND2GUHAM-DMqAikEU.js → chunk-ND2GUHAM-D98vPd-E.js} +1 -1
  239. ksadk/server/static/assets/chunk-QZHKN3VN-YQIEXeF6.js +1 -0
  240. ksadk/server/static/assets/classDiagram-4FO5ZUOK-CDAUuoXK.js +1 -0
  241. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-CDAUuoXK.js +1 -0
  242. ksadk/server/static/assets/{cose-bilkent-S5V4N54A-Zhy2GBnP.js → cose-bilkent-S5V4N54A-CX3yotHq.js} +1 -1
  243. ksadk/server/static/assets/{dagre-BM42HDAG-CbKrtIUz.js → dagre-BM42HDAG-C7TguAWo.js} +1 -1
  244. ksadk/server/static/assets/{diagram-2AECGRRQ-BRApgQRK.js → diagram-2AECGRRQ-Dd17_kws.js} +1 -1
  245. ksadk/server/static/assets/{diagram-5GNKFQAL-D0xbnDiK.js → diagram-5GNKFQAL-DVIClIil.js} +1 -1
  246. ksadk/server/static/assets/{diagram-KO2AKTUF-CVugVI9L.js → diagram-KO2AKTUF-Df_3gYQa.js} +1 -1
  247. ksadk/server/static/assets/{diagram-LMA3HP47-DozUGgee.js → diagram-LMA3HP47-BhLk6ZtA.js} +1 -1
  248. ksadk/server/static/assets/{diagram-OG6HWLK6-ZOYsKlru.js → diagram-OG6HWLK6-D4GNGvuu.js} +1 -1
  249. ksadk/server/static/assets/{dist-DmFaq_Iy.js → dist-6CVKuTAe.js} +1 -1
  250. ksadk/server/static/assets/{dist-8EEyGgDx.js → dist-BUHRxvDG.js} +1 -1
  251. ksadk/server/static/assets/{dist-B0NP_Z0z.js → dist-BZ9n9AjO.js} +1 -1
  252. ksadk/server/static/assets/{dist-DMezvBGJ.js → dist-BibcG1V9.js} +1 -1
  253. ksadk/server/static/assets/{dist-C3HIIaN5.js → dist-Bs-jQcRX.js} +1 -1
  254. ksadk/server/static/assets/{dist-BrCcQ47T.js → dist-C2xjE7cO.js} +1 -1
  255. ksadk/server/static/assets/{dist-Dp0k7bWI.js → dist-C7-3jInC.js} +1 -1
  256. ksadk/server/static/assets/{dist-D-xOD048.js → dist-C99THtIA.js} +1 -1
  257. ksadk/server/static/assets/{dist-CkEKJFtk.js → dist-CGcp2ex8.js} +1 -1
  258. ksadk/server/static/assets/{dist-DyOkZmze.js → dist-CVQRZjPu.js} +1 -1
  259. ksadk/server/static/assets/{dist-BssVmjIo.js → dist-Cf23NY4L.js} +1 -1
  260. ksadk/server/static/assets/{dist-BIJVDMuB.js → dist-CgF3fj15.js} +1 -1
  261. ksadk/server/static/assets/{dist-2hInLS_J.js → dist-Cwt7koer.js} +1 -1
  262. ksadk/server/static/assets/{dist-DyWsb78Q.js → dist-D82mtD2s.js} +1 -1
  263. ksadk/server/static/assets/{dist-D-JMdWPQ.js → dist-DF06ORQo.js} +1 -1
  264. ksadk/server/static/assets/{dist-BmlMPsCc.js → dist-DHn6nBzr.js} +1 -1
  265. ksadk/server/static/assets/{dist-gX6GOLKq.js → dist-Djgl2wVZ.js} +1 -1
  266. ksadk/server/static/assets/{dist-DpKtt4Bo.js → dist-DlzCRy0S.js} +1 -1
  267. ksadk/server/static/assets/{dist-8_SfK1IP.js → dist-DqNnNFrw.js} +1 -1
  268. ksadk/server/static/assets/{dist-D57wnGWd.js → dist-DyvYLMW9.js} +1 -1
  269. ksadk/server/static/assets/{dist-CPBtqRTW.js → dist-eoW6tZXA.js} +1 -1
  270. ksadk/server/static/assets/{dist-DL_NKc_z.js → dist-ivOya1LD.js} +1 -1
  271. ksadk/server/static/assets/{erDiagram-TEJ5UH35-Bk-9bgE5.js → erDiagram-TEJ5UH35-CnfRcY2M.js} +1 -1
  272. ksadk/server/static/assets/eventmodeling-FCH6USID-ChYO-ijM.js +1 -0
  273. ksadk/server/static/assets/{flowDiagram-I6XJVG4X-Dn9kZVuZ.js → flowDiagram-I6XJVG4X-DGaJjGNJ.js} +1 -1
  274. ksadk/server/static/assets/{ganttDiagram-6RSMTGT7-BGxXlJqm.js → ganttDiagram-6RSMTGT7-DpCoB2g9.js} +1 -1
  275. ksadk/server/static/assets/gitGraph-WXDBUCRP-BN_0Fk-j.js +1 -0
  276. ksadk/server/static/assets/{gitGraphDiagram-PVQCEYII-C7Q0X-wi.js → gitGraphDiagram-PVQCEYII-9IKVFBVT.js} +1 -1
  277. ksadk/server/static/assets/index-QSwCHuB8.js +177 -0
  278. ksadk/server/static/assets/index-jOPmTOZH.css +2 -0
  279. ksadk/server/static/assets/info-J43DQDTF-Cp6o3vId.js +1 -0
  280. ksadk/server/static/assets/{infoDiagram-5YYISTIA-BO_CSqq5.js → infoDiagram-5YYISTIA-CYIIsb8y.js} +1 -1
  281. ksadk/server/static/assets/{ishikawaDiagram-YF4QCWOH-eYLPLd46.js → ishikawaDiagram-YF4QCWOH-DLOHGvWw.js} +1 -1
  282. ksadk/server/static/assets/{journeyDiagram-JHISSGLW-De9geSb0.js → journeyDiagram-JHISSGLW-BIzKeejT.js} +1 -1
  283. ksadk/server/static/assets/{kanban-definition-UN3LZRKU-Cs80kQto.js → kanban-definition-UN3LZRKU-BWHoFSw2.js} +1 -1
  284. ksadk/server/static/assets/{katex-DSrCFD8n.js → katex-DATssjp1.js} +1 -1
  285. ksadk/server/static/assets/{linear-CN9sbKTF.js → linear-CvMBw9cA.js} +1 -1
  286. ksadk/server/static/assets/{mermaid-parser.core-DlgSBU8l.js → mermaid-parser.core-mGAcEwcq.js} +2 -2
  287. ksadk/server/static/assets/{mindmap-definition-RKZ34NQL-9afz7Oug.js → mindmap-definition-RKZ34NQL-CSAQxEAe.js} +1 -1
  288. ksadk/server/static/assets/packet-YPE3B663-wQzct3cT.js +1 -0
  289. ksadk/server/static/assets/pie-LRSECV5Y-BgTQiv-9.js +1 -0
  290. ksadk/server/static/assets/{pieDiagram-4H26LBE5-DPv_VstN.js → pieDiagram-4H26LBE5-By-ra07M.js} +1 -1
  291. ksadk/server/static/assets/{quadrantDiagram-W4KKPZXB-o77wZ1XK.js → quadrantDiagram-W4KKPZXB-CxIR4JXI.js} +1 -1
  292. ksadk/server/static/assets/radar-GUYGQ44K-BIq5fXsn.js +1 -0
  293. ksadk/server/static/assets/{requirementDiagram-4Y6WPE33-BYVw81VC.js → requirementDiagram-4Y6WPE33-DpW90iu3.js} +1 -1
  294. ksadk/server/static/assets/{sankeyDiagram-5OEKKPKP-B7nZFMKT.js → sankeyDiagram-5OEKKPKP-DpGa6EAV.js} +1 -1
  295. ksadk/server/static/assets/{sequenceDiagram-3UESZ5HK-BGRRrFw5.js → sequenceDiagram-3UESZ5HK-NTKNGGe5.js} +1 -1
  296. ksadk/server/static/assets/{stateDiagram-AJRCARHV-BUfHCoPs.js → stateDiagram-AJRCARHV-DGpd9yFG.js} +1 -1
  297. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-B3o579IQ.js +1 -0
  298. ksadk/server/static/assets/{timeline-definition-PNZ67QCA-FbCTGrf9.js → timeline-definition-PNZ67QCA-jqoYs3jQ.js} +1 -1
  299. ksadk/server/static/assets/treeView-BLDUP644-Dqi-E0EM.js +1 -0
  300. ksadk/server/static/assets/treemap-LRROVOQU-ClQP9CJ9.js +1 -0
  301. ksadk/server/static/assets/{vennDiagram-CIIHVFJN-DWgwtPsJ.js → vennDiagram-CIIHVFJN-l3Z7-wbP.js} +1 -1
  302. ksadk/server/static/assets/wardley-L42UT6IY-8XLvnNIs.js +1 -0
  303. ksadk/server/static/assets/{wardleyDiagram-YWT4CUSO-2x8G-tTM.js → wardleyDiagram-YWT4CUSO-BR54GPmr.js} +1 -1
  304. ksadk/server/static/assets/{xychartDiagram-2RQKCTM6-Drma3AYl.js → xychartDiagram-2RQKCTM6-SkiH8GsK.js} +1 -1
  305. ksadk/server/static/index.html +2 -2
  306. ksadk/server/terminal_sessions.py +111 -58
  307. ksadk/sessions/__init__.py +69 -19
  308. ksadk/sessions/base.py +31 -11
  309. ksadk/sessions/continuity.py +2 -3
  310. ksadk/sessions/in_memory.py +46 -2
  311. ksadk/sessions/local_service.py +148 -17
  312. ksadk/sessions/postgres_service.py +143 -25
  313. ksadk/sessions/resilient.py +36 -8
  314. ksadk/skills/models.py +17 -5
  315. ksadk/skills/package_store.py +5 -2
  316. ksadk/skills/runtime/agent.py +20 -5
  317. ksadk/skills/runtime/artifacts.py +1 -5
  318. ksadk/skills/runtime/backends/e2b.py +10 -4
  319. ksadk/skills/runtime/backends/local.py +15 -3
  320. ksadk/skills/runtime/base.py +1 -2
  321. ksadk/skills/runtime/executor.py +10 -3
  322. ksadk/skills/runtime/factory.py +4 -2
  323. ksadk/skills/runtime/loader.py +1 -2
  324. ksadk/skills/runtime/registry.py +15 -10
  325. ksadk/skills/runtime/request.py +3 -1
  326. ksadk/skills/service_client.py +38 -17
  327. ksadk/skills/tool_defs.py +15 -10
  328. ksadk/terminal_exec_policy.py +3 -4
  329. ksadk/tools/gateway.py +92 -15
  330. ksadk/tools/result_budget.py +12 -4
  331. ksadk/toolsets/__init__.py +134 -36
  332. ksadk/toolsets/platform.py +21 -5
  333. ksadk/toolsets/sandbox.py +82 -16
  334. ksadk/toolsets/skills.py +200 -39
  335. ksadk/toolsets/web.py +123 -26
  336. ksadk/toolsets/workspace.py +212 -101
  337. ksadk/tracing/exporters/inmemory_exporter.py +62 -51
  338. ksadk/tracing/exporters/langfuse_exporter.py +91 -76
  339. ksadk/tracing/setup.py +69 -53
  340. ksadk/tracing/span_utils.py +5 -2
  341. ksadk/tui/loop.py +78 -30
  342. ksadk/tui/stream_render.py +1 -0
  343. ksadk/ui_config.py +5 -3
  344. ksadk/version.py +1 -1
  345. ksadk_runtime_common/schemas/runtime_event_v1.json +95 -0
  346. agentengine_sdk_python-0.7.0.dist-info/RECORD +0 -482
  347. ksadk/server/static/assets/CodeBlock-P16VOLYi.js +0 -9
  348. ksadk/server/static/assets/MathMessageMarkdown-CdGiQWHR.js +0 -8
  349. ksadk/server/static/assets/MermaidBlock-IOcal8cm.js +0 -303
  350. ksadk/server/static/assets/NativeTerminalPanel-DGSDWsei.js +0 -1
  351. ksadk/server/static/assets/architecture-7EHR7CIX-BvUlsA6l.js +0 -1
  352. ksadk/server/static/assets/channel-CTuydARX.js +0 -1
  353. ksadk/server/static/assets/chunk-QZHKN3VN-BnCydivS.js +0 -1
  354. ksadk/server/static/assets/classDiagram-4FO5ZUOK-BNHg45Be.js +0 -1
  355. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-BNHg45Be.js +0 -1
  356. ksadk/server/static/assets/eventmodeling-FCH6USID-DsAgWnlf.js +0 -1
  357. ksadk/server/static/assets/gitGraph-WXDBUCRP-BIao9Yjg.js +0 -1
  358. ksadk/server/static/assets/index-C00Lwg3L.js +0 -165
  359. ksadk/server/static/assets/index-DAURbCsP.css +0 -1
  360. ksadk/server/static/assets/info-J43DQDTF-CyipqGxU.js +0 -1
  361. ksadk/server/static/assets/packet-YPE3B663-CGkyRxlg.js +0 -1
  362. ksadk/server/static/assets/pie-LRSECV5Y-M0uWAf4n.js +0 -1
  363. ksadk/server/static/assets/radar-GUYGQ44K-Bdbm24-x.js +0 -1
  364. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-8xBN_gLM.js +0 -1
  365. ksadk/server/static/assets/treeView-BLDUP644-npMo0ak1.js +0 -1
  366. ksadk/server/static/assets/treemap-LRROVOQU-CHdzrrdo.js +0 -1
  367. ksadk/server/static/assets/wardley-L42UT6IY-BEQz7wyy.js +0 -1
  368. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/WHEEL +0 -0
  369. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/entry_points.txt +0 -0
  370. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/licenses/LICENSE +0 -0
  371. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,649 @@
1
+ """Session, UI bootstrap, checkpoint-list, and tool-receipt routes."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Mapping
6
+ from typing import Any
7
+
8
+ from fastapi import HTTPException
9
+
10
+ from ksadk.server.factory import get_runner, get_state
11
+ from ksadk.sessions import SessionEvent
12
+ from ksadk.tools.gateway import tool_approval_capability
13
+ from ksadk.toolsets import describe_agentengine_tools
14
+ from ksadk_runtime_common.workspace_files import (
15
+ build_workspace_files_bootstrap,
16
+ workspace_files_enabled,
17
+ )
18
+
19
+ from . import dependencies as deps
20
+ from .common import (
21
+ _action_response,
22
+ _build_bootstrap_model_payload,
23
+ _build_native_terminal_capability,
24
+ _ensure_session,
25
+ _hydrate_session,
26
+ )
27
+ from .models import (
28
+ CreateSessionActionRequest,
29
+ ListSessionCheckpointsActionRequest,
30
+ ListSessionEventsActionRequest,
31
+ ListSessionMessagesActionRequest,
32
+ ListSessionsActionRequest,
33
+ ListToolReceiptsActionRequest,
34
+ SessionIdRequest,
35
+ UiBootstrapRequest,
36
+ _event_run_id,
37
+ _runtime_agent_id,
38
+ )
39
+ from .projection import (
40
+ _apply_checkpoint_resume_audit,
41
+ _apply_latest_checkpoint_policy,
42
+ _checkpoint_event_to_action_payload,
43
+ _event_invocation_id,
44
+ _event_to_action_payload,
45
+ _extend_invocation_after_window,
46
+ _extend_invocation_before_window,
47
+ _iter_scoped_event_pages,
48
+ _iter_session_event_pages,
49
+ _record_resume_audit,
50
+ _require_action_session,
51
+ _session_to_action_payload,
52
+ _tool_receipt_event_to_action_payload,
53
+ )
54
+ from .routers import sessions_router, tools_router, ui_bootstrap_router
55
+ from .streaming import _cancel_detached_streams_for_session
56
+
57
+
58
+ @ui_bootstrap_router.post("/agentengine/api/v1/GetAgentUiBootstrap")
59
+ async def get_agent_ui_bootstrap(request: UiBootstrapRequest):
60
+ state = get_state()
61
+ runner = state.runner
62
+ if runner is not None:
63
+ runner = get_runner()
64
+ agent_id = request.AgentId or (_runtime_agent_id(runner) if runner else "default-agent")
65
+ description = getattr(runner.detection_result, "description", "") if runner else ""
66
+ framework = ""
67
+ if runner:
68
+ detection_type = getattr(getattr(runner, "detection_result", None), "type", None)
69
+ framework = str(getattr(detection_type, "value", detection_type) or "").strip().lower()
70
+ workspace_enabled = workspace_files_enabled(default=True)
71
+ ui_spec = deps.resolve_agent_ui_spec()
72
+ runtime_capabilities = (
73
+ runner.get_runtime_capabilities()
74
+ if runner and callable(getattr(runner, "get_runtime_capabilities", None))
75
+ else {}
76
+ )
77
+ checkpoint_resume_capability = {
78
+ "Supported": bool(
79
+ (runtime_capabilities.get("ResumeRun") or {}).get("Supported")
80
+ if isinstance(runtime_capabilities, Mapping)
81
+ else False
82
+ ),
83
+ "Checkpoint": (
84
+ (runtime_capabilities.get("Checkpoint") or {})
85
+ if isinstance(runtime_capabilities, Mapping)
86
+ else {}
87
+ ),
88
+ "ResumeRun": (
89
+ (runtime_capabilities.get("ResumeRun") or {})
90
+ if isinstance(runtime_capabilities, Mapping)
91
+ else {}
92
+ ),
93
+ }
94
+ checkpoint_resume_supported = bool(checkpoint_resume_capability["Supported"])
95
+ cancel_run_supported = bool(
96
+ (runtime_capabilities.get("CancelRun") or {}).get("Supported")
97
+ if isinstance(runtime_capabilities, Mapping)
98
+ else False
99
+ )
100
+ responses_transport = {
101
+ "Protocol": "responses",
102
+ "Runtime": "ksadk",
103
+ "Endpoint": "/v1/responses",
104
+ "Version": "v1",
105
+ "Capabilities": {
106
+ "A2UI": False,
107
+ "Interrupt": checkpoint_resume_supported,
108
+ "Cancel": cancel_run_supported,
109
+ },
110
+ }
111
+ hosted_chat_transports = []
112
+ if state.agui_agent is not None and state.agui_config is not None:
113
+ from ksadk.agui.config import AGUI_PROTOCOL_VERSION
114
+
115
+ hosted_chat_transports.append(
116
+ {
117
+ "Protocol": "ag-ui",
118
+ "Runtime": "copilotkit",
119
+ "Endpoint": state.agui_config.path,
120
+ "Version": AGUI_PROTOCOL_VERSION,
121
+ "Capabilities": {
122
+ "A2UI": True,
123
+ "Interrupt": checkpoint_resume_supported,
124
+ "Cancel": True,
125
+ },
126
+ }
127
+ )
128
+ hosted_chat_transports.append(responses_transport)
129
+ preferred_transport = (
130
+ "ag-ui"
131
+ if hosted_chat_transports[0]["Protocol"] == "ag-ui"
132
+ and bool(getattr(state.agui_config, "preferred", False))
133
+ else "responses"
134
+ )
135
+ return _action_response(
136
+ "GetAgentUiBootstrap",
137
+ {
138
+ "Agent": {
139
+ "AgentId": agent_id,
140
+ "Name": runner.detection_result.name if runner else agent_id,
141
+ "Description": description or "",
142
+ "Framework": framework,
143
+ },
144
+ "Modules": ["Chat", "Build", "Deploy"],
145
+ "Capabilities": {
146
+ "Attachments": True,
147
+ "WorkspaceFiles": workspace_enabled,
148
+ "Approval": True,
149
+ "ApprovalPolicy": tool_approval_capability(),
150
+ "Thinking": True,
151
+ "StopRun": cancel_run_supported,
152
+ "ResumeRun": checkpoint_resume_supported,
153
+ "RuntimeCapabilities": runtime_capabilities,
154
+ "CheckpointResumeCapability": checkpoint_resume_capability,
155
+ "RunLifecycle": {
156
+ "Enabled": True,
157
+ "Resume": True,
158
+ "Abort": True,
159
+ "Checkpoints": checkpoint_resume_supported,
160
+ "CheckpointResume": checkpoint_resume_supported,
161
+ "CheckpointResumePreview": checkpoint_resume_supported,
162
+ },
163
+ "MCP": False,
164
+ "HostedRuntime": False,
165
+ "NativeTerminal": _build_native_terminal_capability(framework),
166
+ "BuiltinTools": describe_agentengine_tools(),
167
+ },
168
+ "WorkspaceFiles": build_workspace_files_bootstrap(enabled=workspace_enabled),
169
+ "AccessMode": "Owner",
170
+ "SharePermissions": {
171
+ "Interactive": True,
172
+ "DefaultPath": ui_spec.get("ui_path") or ui_spec.get("path") or "/chat",
173
+ "SharePath": ui_spec.get("ui_path") or ui_spec.get("path") or "/chat",
174
+ },
175
+ "CustomUI": {
176
+ "Enabled": bool(ui_spec.get("enabled")),
177
+ "Profile": ui_spec.get("ui_profile") or ui_spec.get("profile"),
178
+ "Path": ui_spec.get("ui_path") or ui_spec.get("path"),
179
+ "Url": ui_spec.get("ui_url") or ui_spec.get("url"),
180
+ "BundlePath": ui_spec.get("ui_bundle_path") or ui_spec.get("bundle_path"),
181
+ },
182
+ "ApiFormats": ["responses", "chat_completions"],
183
+ "HostedChat": {
184
+ "PreferredTransport": preferred_transport,
185
+ "Transports": hosted_chat_transports,
186
+ },
187
+ "Stream": True,
188
+ "SessionId": request.SessionId,
189
+ "SessionBackend": deps.describe_session_backend(),
190
+ "HostedRuntime": None,
191
+ "Model": _build_bootstrap_model_payload(),
192
+ },
193
+ )
194
+
195
+
196
+ @sessions_router.post("/agentengine/api/v1/CreateSession")
197
+ async def create_session_action(request: CreateSessionActionRequest):
198
+ session = await _ensure_session(request.AgentId, request.UserId or "user", request.SessionId)
199
+ return _action_response("CreateSession", {"Session": await _session_to_action_payload(session)})
200
+
201
+
202
+ @sessions_router.post("/agentengine/api/v1/ListSessions")
203
+ async def list_sessions_action(request: ListSessionsActionRequest):
204
+ service = deps.resolve_session_service()
205
+ offset = (request.Page - 1) * request.PageSize
206
+ sessions = await service.list_sessions(
207
+ request.AgentId,
208
+ request.UserId,
209
+ offset=offset,
210
+ limit=request.PageSize,
211
+ )
212
+ total = await service.count_sessions(request.AgentId, request.UserId)
213
+ session_payloads = [await _session_to_action_payload(session) for session in sessions]
214
+ return _action_response(
215
+ "ListSessions",
216
+ {
217
+ "Sessions": session_payloads,
218
+ "Total": total,
219
+ "Page": request.Page,
220
+ "PageSize": request.PageSize,
221
+ "DataSource": "runtime",
222
+ "Degraded": False,
223
+ "SessionContractVersion": 2,
224
+ },
225
+ )
226
+
227
+
228
+ @sessions_router.post("/agentengine/api/v1/GetSession")
229
+ async def get_session_action(request: SessionIdRequest):
230
+ service = deps.resolve_session_service()
231
+ session = await _require_action_session(
232
+ service,
233
+ session_id=request.SessionId,
234
+ agent_id=request.AgentId,
235
+ user_id=request.UserId,
236
+ )
237
+ hydrated = await _hydrate_session(session)
238
+ if hydrated is None:
239
+ raise HTTPException(status_code=404, detail="Session not found")
240
+ return _action_response("GetSession", {"Session": await _session_to_action_payload(hydrated)})
241
+
242
+
243
+ @sessions_router.post("/agentengine/api/v1/DeleteSession")
244
+ async def delete_session_action(request: SessionIdRequest):
245
+ service = deps.resolve_session_service()
246
+ await _require_action_session(
247
+ service,
248
+ session_id=request.SessionId,
249
+ agent_id=request.AgentId,
250
+ user_id=request.UserId,
251
+ )
252
+ await _cancel_detached_streams_for_session(request.SessionId)
253
+ deleted = await service.delete_session(request.SessionId)
254
+ if not deleted:
255
+ raise HTTPException(status_code=404, detail="Session not found")
256
+ return _action_response("DeleteSession", {"Deleted": True})
257
+
258
+
259
+ @sessions_router.post("/agentengine/api/v1/ListSessionEvents")
260
+ async def list_session_events_action(request: ListSessionEventsActionRequest):
261
+ runner = get_state().runner
262
+ service = deps.resolve_session_service()
263
+ session_id = str(request.SessionId or "").strip()
264
+ if not session_id:
265
+ # 未传 SessionId:返回该 agent 全部会话的事件(存储层跨会话查询,真分页无截断;
266
+ # seq 游标是会话内序号,跨会话模式下不适用,直接忽略)
267
+ agent_id = str(request.AgentId or "").strip() or (
268
+ _runtime_agent_id(runner) if runner else "default-agent"
269
+ )
270
+ events = await service.get_events_for_agent(
271
+ agent_id,
272
+ user_id=request.UserId,
273
+ offset=request.Offset,
274
+ limit=request.Limit,
275
+ )
276
+ total = await service.count_events_for_agent(agent_id, user_id=request.UserId)
277
+ return _action_response(
278
+ "ListSessionEvents",
279
+ {
280
+ "Events": [_event_to_action_payload(event) for event in events],
281
+ "Total": total,
282
+ "Offset": request.Offset or 0,
283
+ "Limit": request.Limit if request.Limit is not None else len(events),
284
+ "AfterSeqId": request.AfterSeqId,
285
+ "BeforeSeqId": request.BeforeSeqId,
286
+ "ScopedAllSessions": True,
287
+ },
288
+ )
289
+ await _require_action_session(
290
+ service,
291
+ session_id=session_id,
292
+ agent_id=request.AgentId,
293
+ user_id=request.UserId,
294
+ )
295
+ events = await service.get_events(
296
+ session_id,
297
+ offset=request.Offset,
298
+ limit=request.Limit,
299
+ after_seq_id=request.AfterSeqId,
300
+ before_seq_id=request.BeforeSeqId,
301
+ )
302
+ total = await service.count_events(
303
+ session_id,
304
+ after_seq_id=request.AfterSeqId,
305
+ before_seq_id=request.BeforeSeqId,
306
+ )
307
+ return _action_response(
308
+ "ListSessionEvents",
309
+ {
310
+ "Events": [_event_to_action_payload(event) for event in events],
311
+ "Total": total,
312
+ "Offset": request.Offset or 0,
313
+ "Limit": request.Limit if request.Limit is not None else len(events),
314
+ "AfterSeqId": request.AfterSeqId,
315
+ "BeforeSeqId": request.BeforeSeqId,
316
+ },
317
+ )
318
+
319
+
320
+ @sessions_router.post("/agentengine/api/v1/ListSessionMessages")
321
+ async def list_session_messages_action(request: ListSessionMessagesActionRequest):
322
+ from ksadk.conversations.message_projection import project_session_messages
323
+
324
+ service = deps.resolve_session_service()
325
+ await _require_action_session(
326
+ service,
327
+ session_id=request.SessionId,
328
+ agent_id=request.AgentId,
329
+ user_id=request.UserId,
330
+ )
331
+ total_events = await service.count_events(
332
+ request.SessionId,
333
+ after_seq_id=request.AfterSeqId,
334
+ before_seq_id=request.BeforeSeqId,
335
+ )
336
+ event_offset = 0
337
+ if request.AfterSeqId is not None and total_events > 2000:
338
+ # Storage pagination is tail-based. Offset past the newest surplus so
339
+ # reconnect starts with the oldest unseen window and cannot skip gaps.
340
+ event_offset = total_events - 2000
341
+ events = await service.get_events(
342
+ request.SessionId,
343
+ offset=event_offset,
344
+ limit=2000,
345
+ after_seq_id=request.AfterSeqId,
346
+ before_seq_id=request.BeforeSeqId,
347
+ )
348
+
349
+ def project(
350
+ events_to_project: list[SessionEvent],
351
+ ) -> tuple[list[dict[str, Any]], list[dict[str, Any]]]:
352
+ serialized = [_event_to_action_payload(event) for event in events_to_project]
353
+ return serialized, project_session_messages(
354
+ serialized,
355
+ include_reasoning=request.IncludeReasoning,
356
+ include_tool_events=request.IncludeToolEvents,
357
+ include_attachments=request.IncludeAttachments,
358
+ )
359
+
360
+ serialized_events, messages = project(events)
361
+ if request.AfterSeqId is not None:
362
+ if total_events > len(events):
363
+ events = await _extend_invocation_after_window(
364
+ service,
365
+ request.SessionId,
366
+ events,
367
+ before_seq_id=request.BeforeSeqId,
368
+ )
369
+ serialized_events, messages = project(events)
370
+ page = messages
371
+ has_more = total_events > len(serialized_events)
372
+ next_cursor = None
373
+ else:
374
+ page_start = len(messages)
375
+ while page_start > 0:
376
+ group_start_seq_id = int(messages[page_start - 1].get("StartSeqId") or 0)
377
+ group_start_index = next(
378
+ (
379
+ index
380
+ for index, message in enumerate(messages[:page_start])
381
+ if int(message.get("StartSeqId") or 0) == group_start_seq_id
382
+ ),
383
+ page_start - 1,
384
+ )
385
+ current_size = len(messages) - page_start
386
+ group_size = page_start - group_start_index
387
+ if current_size and current_size + group_size > request.Limit:
388
+ break
389
+ page_start = group_start_index
390
+ if len(messages) - page_start >= request.Limit:
391
+ break
392
+ page = messages[page_start:]
393
+ if (
394
+ page
395
+ and events
396
+ and total_events > len(events)
397
+ and _event_invocation_id(events[0])
398
+ and any(
399
+ str(message.get("InvocationId") or "") == _event_invocation_id(events[0])
400
+ for message in page
401
+ )
402
+ ):
403
+ events = await _extend_invocation_before_window(
404
+ service,
405
+ request.SessionId,
406
+ events,
407
+ after_seq_id=request.AfterSeqId,
408
+ )
409
+ serialized_events, messages = project(events)
410
+ page_start = len(messages)
411
+ while page_start > 0:
412
+ group_start_seq_id = int(messages[page_start - 1].get("StartSeqId") or 0)
413
+ group_start_index = next(
414
+ (
415
+ index
416
+ for index, message in enumerate(messages[:page_start])
417
+ if int(message.get("StartSeqId") or 0) == group_start_seq_id
418
+ ),
419
+ page_start - 1,
420
+ )
421
+ current_size = len(messages) - page_start
422
+ group_size = page_start - group_start_index
423
+ if current_size and current_size + group_size > request.Limit:
424
+ break
425
+ page_start = group_start_index
426
+ if len(messages) - page_start >= request.Limit:
427
+ break
428
+ page = messages[page_start:]
429
+ minimum_start_seq_id = int(page[0].get("StartSeqId") or 0) if page else 0
430
+ has_more = page_start > 0 or total_events > len(serialized_events)
431
+ # BeforeSeqId is exclusive. Use the invocation group boundary so the
432
+ # next page cannot duplicate reasoning/tools or skip its user message.
433
+ next_cursor = minimum_start_seq_id if has_more else None
434
+ latest_seq_id = (
435
+ int(page[-1].get("SeqId") or 0)
436
+ if page
437
+ else max(
438
+ (int(event.get("SeqId") or 0) for event in serialized_events),
439
+ default=int(request.AfterSeqId or 0),
440
+ )
441
+ )
442
+ return _action_response(
443
+ "ListSessionMessages",
444
+ {
445
+ "SessionId": request.SessionId,
446
+ "Messages": page,
447
+ "LatestSeqId": latest_seq_id,
448
+ "HasMore": has_more,
449
+ "NextCursor": next_cursor,
450
+ },
451
+ )
452
+
453
+
454
+ def _count_resumable_checkpoints(checkpoints: list[dict[str, Any]]) -> int:
455
+ """统计可恢复 checkpoint 数量。
456
+
457
+ 规则:IsResumable=True AND ReplayAllowed!=False AND IsTerminal!=True
458
+ AND CheckpointStatus not in {expired, disabled}。
459
+ 不排除 resumed(已恢复过的仍计入,符合存档点可反复读的回档语义)。
460
+ """
461
+ resumable = 0
462
+ for cp in checkpoints:
463
+ if cp.get("IsResumable") is not True:
464
+ continue
465
+ if cp.get("ReplayAllowed") is False:
466
+ continue
467
+ if cp.get("IsTerminal") is True:
468
+ continue
469
+ status = str(cp.get("CheckpointStatus") or "").strip().lower()
470
+ if status in {"expired", "disabled"}:
471
+ continue
472
+ resumable += 1
473
+ return resumable
474
+
475
+
476
+ async def _list_checkpoints_payload(request: ListSessionCheckpointsActionRequest) -> dict[str, Any]:
477
+ service = deps.resolve_session_service()
478
+ run_id_filter = str(request.RunId or "").strip()
479
+ framework_filter = str(request.Framework or "").strip().lower()
480
+
481
+ session_id = str(request.SessionId or "").strip()
482
+ if session_id:
483
+ await _require_action_session(
484
+ service,
485
+ session_id=session_id,
486
+ agent_id=request.AgentId,
487
+ user_id=request.UserId,
488
+ )
489
+
490
+ audit_by_session: dict[str, dict[tuple[str, str], dict[str, Any]]] = {}
491
+ latest_by_session_run: dict[tuple[str, str], int] = {}
492
+ run_seen = not run_id_filter
493
+ async for page in _iter_scoped_event_pages(
494
+ service,
495
+ session_id=session_id or None,
496
+ agent_id=request.AgentId,
497
+ user_id=request.UserId,
498
+ ):
499
+ for event in page:
500
+ if run_id_filter and _event_run_id(event) == run_id_filter:
501
+ run_seen = True
502
+ _record_resume_audit(audit_by_session, event)
503
+ checkpoint = _checkpoint_event_to_action_payload(event)
504
+ if checkpoint is None or not (checkpoint.get("Metadata") or {}).get(
505
+ "only_latest_resumable"
506
+ ):
507
+ continue
508
+ key = (event.session_id, str(checkpoint.get("RunId") or ""))
509
+ latest_by_session_run[key] = max(
510
+ latest_by_session_run.get(key, 0),
511
+ int(checkpoint.get("SeqId") or 0),
512
+ )
513
+ if session_id and not run_seen:
514
+ raise HTTPException(status_code=409, detail="RunId does not belong to SessionId")
515
+
516
+ def project_checkpoint(event: SessionEvent) -> dict[str, Any] | None:
517
+ checkpoint = _checkpoint_event_to_action_payload(event)
518
+ if checkpoint is None:
519
+ return None
520
+ checkpoint = _apply_checkpoint_resume_audit(
521
+ checkpoint,
522
+ audit_by_session.get(event.session_id, {}),
523
+ )
524
+ checkpoint = _apply_latest_checkpoint_policy(
525
+ checkpoint,
526
+ latest_by_session_run,
527
+ session_id=event.session_id,
528
+ )
529
+ if run_id_filter and checkpoint["RunId"] != run_id_filter:
530
+ return None
531
+ if framework_filter and str(checkpoint["Framework"]).lower() != framework_filter:
532
+ return None
533
+ return checkpoint
534
+
535
+ total = 0
536
+ resumable_total = 0
537
+ async for page in _iter_scoped_event_pages(
538
+ service,
539
+ session_id=session_id or None,
540
+ agent_id=request.AgentId,
541
+ user_id=request.UserId,
542
+ ):
543
+ for event in page:
544
+ checkpoint = project_checkpoint(event)
545
+ if checkpoint is None:
546
+ continue
547
+ if checkpoint.get("IsResumable") is True:
548
+ resumable_total += 1
549
+ if request.OnlyResumable and checkpoint.get("IsResumable") is not True:
550
+ continue
551
+ total += 1
552
+
553
+ offset = int(request.Offset or 0)
554
+ limit = int(request.Limit)
555
+ window_end = max(total - offset, 0)
556
+ window_start = max(window_end - limit, 0)
557
+ checkpoints: list[dict[str, Any]] = []
558
+ filtered_index = 0
559
+ async for page in _iter_scoped_event_pages(
560
+ service,
561
+ session_id=session_id or None,
562
+ agent_id=request.AgentId,
563
+ user_id=request.UserId,
564
+ ):
565
+ for event in page:
566
+ checkpoint = project_checkpoint(event)
567
+ if checkpoint is None:
568
+ continue
569
+ if request.OnlyResumable and checkpoint.get("IsResumable") is not True:
570
+ continue
571
+ if window_start <= filtered_index < window_end:
572
+ checkpoints.append(checkpoint)
573
+ filtered_index += 1
574
+ if filtered_index >= window_end:
575
+ break
576
+ if filtered_index >= window_end:
577
+ break
578
+
579
+ return {
580
+ "Checkpoints": checkpoints,
581
+ "Total": total,
582
+ "ResumableTotal": resumable_total,
583
+ "HasResumableCheckpoint": resumable_total > 0,
584
+ "Offset": offset,
585
+ "Limit": limit,
586
+ }
587
+
588
+
589
+ @sessions_router.post("/agentengine/api/v1/ListSessionCheckpoints")
590
+ async def list_session_checkpoints_action(request: ListSessionCheckpointsActionRequest):
591
+ return _action_response("ListSessionCheckpoints", await _list_checkpoints_payload(request))
592
+
593
+
594
+ @tools_router.post("/agentengine/api/v1/ListToolReceipts")
595
+ async def list_tool_receipts_action(request: ListToolReceiptsActionRequest):
596
+ service = deps.resolve_session_service()
597
+ await _require_action_session(
598
+ service,
599
+ session_id=request.SessionId,
600
+ agent_id=request.AgentId,
601
+ user_id=request.UserId,
602
+ )
603
+
604
+ run_id_filter = str(request.RunId or "").strip()
605
+ checkpoint_id_filter = str(request.CheckpointId or "").strip()
606
+ total = 0
607
+ async for page in _iter_session_event_pages(service, request.SessionId):
608
+ for event in page:
609
+ receipt = _tool_receipt_event_to_action_payload(event)
610
+ if receipt is None:
611
+ continue
612
+ if run_id_filter and receipt["RunId"] != run_id_filter:
613
+ continue
614
+ if checkpoint_id_filter and receipt["CheckpointId"] != checkpoint_id_filter:
615
+ continue
616
+ total += 1
617
+
618
+ offset = int(request.Offset)
619
+ limit = int(request.Limit)
620
+ window_end = max(total - offset, 0)
621
+ window_start = max(window_end - limit, 0)
622
+ receipts: list[dict[str, Any]] = []
623
+ filtered_index = 0
624
+ async for page in _iter_session_event_pages(service, request.SessionId):
625
+ for event in page:
626
+ receipt = _tool_receipt_event_to_action_payload(event)
627
+ if receipt is None:
628
+ continue
629
+ if run_id_filter and receipt["RunId"] != run_id_filter:
630
+ continue
631
+ if checkpoint_id_filter and receipt["CheckpointId"] != checkpoint_id_filter:
632
+ continue
633
+ if window_start <= filtered_index < window_end:
634
+ receipts.append(receipt)
635
+ filtered_index += 1
636
+ if filtered_index >= window_end:
637
+ break
638
+ if filtered_index >= window_end:
639
+ break
640
+
641
+ return _action_response(
642
+ "ListToolReceipts",
643
+ {
644
+ "ToolReceipts": receipts,
645
+ "Total": total,
646
+ "Offset": offset,
647
+ "Limit": limit,
648
+ },
649
+ )