agentengine-sdk-python 0.7.0__py3-none-any.whl → 0.8.1__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 (450) hide show
  1. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.1.dist-info}/METADATA +52 -20
  2. agentengine_sdk_python-0.8.1.dist-info/RECORD +644 -0
  3. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.1.dist-info}/WHEEL +1 -1
  4. ksadk/a2a/__init__.py +180 -11
  5. ksadk/a2a/bootstrap.py +332 -0
  6. ksadk/a2a/card.py +15 -0
  7. ksadk/a2a/context_store.py +203 -0
  8. ksadk/a2a/control_plane.py +1056 -0
  9. ksadk/a2a/credential.py +99 -0
  10. ksadk/a2a/event_adapter.py +149 -0
  11. ksadk/a2a/executor.py +361 -137
  12. ksadk/a2a/external_transport.py +516 -0
  13. ksadk/a2a/identity.py +304 -0
  14. ksadk/a2a/ids.py +22 -0
  15. ksadk/a2a/langgraph.py +285 -0
  16. ksadk/a2a/resume_store.py +201 -0
  17. ksadk/a2a/routes.py +112 -0
  18. ksadk/a2a/server.py +102 -62
  19. ksadk/a2a/service_env.py +33 -0
  20. ksadk/a2a/space_client.py +1122 -0
  21. ksadk/a2a/task_adapter.py +423 -0
  22. ksadk/a2a/task_event_dispatcher.py +167 -0
  23. ksadk/a2a/task_event_outbox.py +326 -0
  24. ksadk/a2a/task_store.py +206 -0
  25. ksadk/a2a_card.py +101 -0
  26. ksadk/a2ui/__init__.py +27 -0
  27. ksadk/a2ui/core.py +186 -0
  28. ksadk/a2ui/models.py +166 -0
  29. ksadk/a2ui/renderer.py +198 -0
  30. ksadk/agui/__init__.py +9 -0
  31. ksadk/agui/a2ui_projection.py +92 -0
  32. ksadk/agui/agent.py +872 -0
  33. ksadk/agui/config.py +92 -0
  34. ksadk/agui/routes.py +47 -0
  35. ksadk/api/client.py +238 -204
  36. ksadk/api/environment.py +27 -0
  37. ksadk/builders/__init__.py +2 -0
  38. ksadk/builders/base.py +16 -14
  39. ksadk/builders/code_builder.py +375 -270
  40. ksadk/builders/container_builder.py +240 -200
  41. ksadk/builders/framework_requirements.py +31 -12
  42. ksadk/builders/ks3_uploader.py +60 -29
  43. ksadk/builders/managed_runtime_builder.py +173 -0
  44. ksadk/builders/mcp_builder.py +91 -92
  45. ksadk/builders/requirements_utils.py +1 -5
  46. ksadk/cli/__init__.py +97 -171
  47. ksadk/cli/cmd_a2a.py +255 -84
  48. ksadk/cli/cmd_agent.py +19 -5
  49. ksadk/cli/cmd_build.py +158 -29
  50. ksadk/cli/cmd_completion.py +47 -35
  51. ksadk/cli/cmd_config.py +267 -198
  52. ksadk/cli/cmd_create.py +507 -740
  53. ksadk/cli/cmd_dashboard.py +120 -45
  54. ksadk/cli/cmd_deploy.py +135 -59
  55. ksadk/cli/cmd_destroy.py +44 -14
  56. ksadk/cli/cmd_eval.py +386 -0
  57. ksadk/cli/cmd_files.py +63 -24
  58. ksadk/cli/cmd_hermes.py +313 -135
  59. ksadk/cli/cmd_invoke.py +184 -122
  60. ksadk/cli/cmd_launch.py +76 -28
  61. ksadk/cli/cmd_mcp.py +98 -64
  62. ksadk/cli/cmd_model.py +14 -5
  63. ksadk/cli/cmd_openclaw.py +564 -268
  64. ksadk/cli/cmd_replay.py +71 -0
  65. ksadk/cli/cmd_run.py +58 -73
  66. ksadk/cli/cmd_status.py +80 -31
  67. ksadk/cli/cmd_studio.py +110 -0
  68. ksadk/cli/cmd_version.py +20 -13
  69. ksadk/cli/cmd_web.py +95 -18
  70. ksadk/cli/deploy_utils.py +20 -20
  71. ksadk/cli/dry_run.py +7 -4
  72. ksadk/cli/env_options.py +83 -0
  73. ksadk/cli/error_utils.py +37 -12
  74. ksadk/cli/global_options.py +4 -3
  75. ksadk/cli/local_runtime.py +1 -2
  76. ksadk/cli/model_catalog.py +6 -2
  77. ksadk/cli/network_options.py +41 -19
  78. ksadk/cli/resource_common.py +6 -2
  79. ksadk/cli/runtime_bootstrap.py +51 -0
  80. ksadk/cli/storage.py +0 -1
  81. ksadk/cli/ui.py +11 -3
  82. ksadk/cli/workflow_common.py +52 -18
  83. ksadk/codex/__init__.py +12 -0
  84. ksadk/codex/client.py +1042 -0
  85. ksadk/codex/phase.py +143 -0
  86. ksadk/codex/runtime.py +940 -0
  87. ksadk/common/aicp_env.py +0 -1
  88. ksadk/common/auth.py +2 -2
  89. ksadk/common/constants.py +1 -3
  90. ksadk/common/kop_client.py +232 -0
  91. ksadk/common/llm_utils.py +17 -13
  92. ksadk/compat/__init__.py +5 -0
  93. ksadk/compat/adk_compat.py +200 -0
  94. ksadk/compat/copilotkit_a2ui.py +330 -0
  95. ksadk/configs/__init__.py +12 -14
  96. ksadk/configs/env_registry.py +661 -116
  97. ksadk/configs/global_config.py +3 -2
  98. ksadk/configs/settings.py +133 -209
  99. ksadk/conversations/__init__.py +85 -92
  100. ksadk/conversations/attachment_storage.py +16 -11
  101. ksadk/conversations/attachments.py +44 -36
  102. ksadk/conversations/compaction_pipeline.py +12 -12
  103. ksadk/conversations/compaction_prompt.py +9 -5
  104. ksadk/conversations/context.py +221 -6
  105. ksadk/conversations/message_projection.py +438 -51
  106. ksadk/conversations/model_context.py +12 -6
  107. ksadk/conversations/model_options.py +0 -1
  108. ksadk/conversations/normalize.py +20 -16
  109. ksadk/conversations/reasoning_markup.py +1 -1
  110. ksadk/conversations/runtime.py +339 -5255
  111. ksadk/conversations/runtime_compaction.py +333 -0
  112. ksadk/conversations/runtime_constants.py +27 -0
  113. ksadk/conversations/runtime_governance.py +185 -0
  114. ksadk/conversations/runtime_input.py +660 -0
  115. ksadk/conversations/runtime_invocation.py +395 -0
  116. ksadk/conversations/runtime_metadata.py +475 -0
  117. ksadk/conversations/runtime_observability.py +367 -0
  118. ksadk/conversations/runtime_payloads.py +272 -0
  119. ksadk/conversations/runtime_persistence.py +440 -0
  120. ksadk/conversations/runtime_preparation.py +426 -0
  121. ksadk/conversations/runtime_resume.py +836 -0
  122. ksadk/conversations/runtime_stream_events.py +902 -0
  123. ksadk/conversations/runtime_streaming.py +700 -0
  124. ksadk/conversations/semantic_summary.py +17 -5
  125. ksadk/conversations/session_title.py +6 -3
  126. ksadk/deployment/__init__.py +15 -16
  127. ksadk/deployment/agent_access.py +12 -23
  128. ksadk/deployment/base.py +51 -38
  129. ksadk/deployment/managed_runtime.py +33 -0
  130. ksadk/deployment/manager.py +85 -71
  131. ksadk/deployment/providers/serverless.py +379 -210
  132. ksadk/deployment/registry.py +38 -32
  133. ksadk/deployment/state.py +11 -11
  134. ksadk/deployment/ui_config.py +1 -1
  135. ksadk/detection/__init__.py +1 -1
  136. ksadk/detection/detector.py +146 -83
  137. ksadk/detection/mcp_detector.py +9 -6
  138. ksadk/evaluation/__init__.py +84 -0
  139. ksadk/evaluation/a2a_adapter.py +444 -0
  140. ksadk/evaluation/adapters.py +54 -0
  141. ksadk/evaluation/contracts.py +409 -0
  142. ksadk/evaluation/evalset.py +351 -0
  143. ksadk/evaluation/evaluators.py +461 -0
  144. ksadk/evaluation/executor.py +118 -0
  145. ksadk/evaluation/storage.py +68 -0
  146. ksadk/evaluation/target.py +73 -0
  147. ksadk/events/__init__.py +25 -0
  148. ksadk/events/parser.py +191 -0
  149. ksadk/events/replay.py +37 -0
  150. ksadk/events/runtime_event.py +273 -0
  151. ksadk/events/store.py +317 -0
  152. ksadk/harness/__init__.py +35 -0
  153. ksadk/harness/app.py +269 -0
  154. ksadk/harness/config.py +181 -0
  155. ksadk/harness/reasoner.py +105 -0
  156. ksadk/harness/runtime.py +364 -0
  157. ksadk/harness/sandbox.py +141 -0
  158. ksadk/harness/tools.py +222 -0
  159. ksadk/hermes_terminal.py +28 -12
  160. ksadk/identity/resolver.py +15 -9
  161. ksadk/ids.py +32 -0
  162. ksadk/knowledge_base/adk_tool.py +1 -1
  163. ksadk/knowledge_base/client.py +38 -33
  164. ksadk/managed_a2a_card.py +160 -0
  165. ksadk/managed_runtime.py +195 -0
  166. ksadk/markdown.py +5 -2
  167. ksadk/mcp_runtime/__init__.py +9 -6
  168. ksadk/memory/__init__.py +1 -1
  169. ksadk/memory/adk/__init__.py +2 -0
  170. ksadk/memory/adk/backends/base_ltm_backend.py +2 -6
  171. ksadk/memory/adk/backends/http_ltm_backend.py +13 -21
  172. ksadk/memory/adk/backends/inmemory_ltm_backend.py +7 -13
  173. ksadk/memory/adk/backends/sdk_ltm_backend.py +36 -36
  174. ksadk/memory/adk/long_term_memory.py +34 -37
  175. ksadk/memory/adk/resilient_session_service.py +4 -5
  176. ksadk/memory/adk/short_term_memory.py +12 -21
  177. ksadk/memory/adk_tool.py +3 -2
  178. ksadk/memory/backends/base.py +19 -19
  179. ksadk/memory/backends/memory.py +24 -25
  180. ksadk/memory/backends/redis.py +31 -30
  181. ksadk/memory/langchain_tool.py +2 -1
  182. ksadk/memory/manager.py +52 -47
  183. ksadk/memory/service.py +16 -6
  184. ksadk/memory/tool.py +4 -0
  185. ksadk/model_policy.py +15 -7
  186. ksadk/model_proxy/__init__.py +51 -0
  187. ksadk/model_proxy/bootstrap.py +80 -0
  188. ksadk/model_proxy/cache.py +165 -0
  189. ksadk/model_proxy/config.py +66 -0
  190. ksadk/model_proxy/demo_webui.py +115 -0
  191. ksadk/model_proxy/detect.py +145 -0
  192. ksadk/model_proxy/gate.py +68 -0
  193. ksadk/model_proxy/namespace.py +201 -0
  194. ksadk/model_proxy/protocol_proxy.py +22 -0
  195. ksadk/model_proxy/server.py +443 -0
  196. ksadk/model_proxy/transform.py +735 -0
  197. ksadk/openclaw_gateway.py +29 -14
  198. ksadk/runners/adk_runner.py +354 -146
  199. ksadk/runners/base_runner.py +71 -29
  200. ksadk/runners/deepagents_runner.py +0 -1
  201. ksadk/runners/factory.py +18 -5
  202. ksadk/runners/langchain_runner.py +29 -742
  203. ksadk/runners/langgraph_runner.py +417 -97
  204. ksadk/runners/patch_langchain.py +16 -16
  205. ksadk/runners/remote_runner.py +134 -33
  206. ksadk/runners/usage_accumulator.py +1 -0
  207. ksadk/runners/utils/__init__.py +0 -10
  208. ksadk/runners/utils/loader.py +23 -7
  209. ksadk/runtime/__init__.py +67 -0
  210. ksadk/runtime/adapter.py +412 -0
  211. ksadk/runtime/conversation_execution.py +553 -0
  212. ksadk/runtime/executor.py +251 -0
  213. ksadk/runtime/factory.py +156 -0
  214. ksadk/runtime/framework_adapters.py +118 -0
  215. ksadk/runtime/launch.py +48 -0
  216. ksadk/runtime/preprocessing.py +131 -0
  217. ksadk/runtime/runner_adapter.py +1032 -0
  218. ksadk/runtime/runner_loading.py +36 -0
  219. ksadk/runtime_context.py +18 -3
  220. ksadk/runtime_state.py +0 -1
  221. ksadk/sandbox/__init__.py +4 -1
  222. ksadk/sandbox/backends/__init__.py +4 -1
  223. ksadk/sandbox/backends/e2b.py +13 -5
  224. ksadk/sandbox/backends/local_process.py +11 -3
  225. ksadk/sandbox/base.py +10 -15
  226. ksadk/sandbox/factory.py +14 -4
  227. ksadk/sandbox/registry.py +57 -6
  228. ksadk/server/__init__.py +39 -4
  229. ksadk/server/api_models.py +15 -5
  230. ksadk/server/app.py +24 -3928
  231. ksadk/server/composition.py +47 -0
  232. ksadk/server/factory.py +622 -0
  233. ksadk/server/routes/__init__.py +1 -0
  234. ksadk/server/routes/checkpoint_resolution.py +116 -0
  235. ksadk/server/routes/common.py +682 -0
  236. ksadk/server/routes/control.py +331 -0
  237. ksadk/server/routes/dependencies.py +98 -0
  238. ksadk/server/routes/misc.py +425 -0
  239. ksadk/server/routes/models.py +451 -0
  240. ksadk/server/routes/openai_compat.py +229 -0
  241. ksadk/server/routes/projection.py +848 -0
  242. ksadk/server/routes/routers.py +52 -0
  243. ksadk/server/routes/run.py +519 -0
  244. ksadk/server/routes/sessions.py +644 -0
  245. ksadk/server/routes/streaming.py +265 -0
  246. ksadk/server/routes/workspace.py +414 -0
  247. ksadk/server/static/assets/{ArtifactsPanel-D-SSn2ee.js → ArtifactsPanel-CakCqxEN.js} +1 -1
  248. ksadk/server/static/assets/CodeBlock-CynLknyO.js +9 -0
  249. ksadk/server/static/assets/MathMessageMarkdown-3sQdOysS.js +8 -0
  250. ksadk/server/static/assets/MermaidBlock-NERD_ef7.js +303 -0
  251. ksadk/server/static/assets/NativeTerminalPanel-CiHWf82q.js +1 -0
  252. ksadk/server/static/assets/{arc-BA13sHc9.js → arc-DrgjcKhl.js} +1 -1
  253. ksadk/server/static/assets/architecture-7EHR7CIX-CpZLRCcY.js +1 -0
  254. ksadk/server/static/assets/{architectureDiagram-3BPJPVTR-DzJzgVoL.js → architectureDiagram-3BPJPVTR-BXoVRbQ6.js} +1 -1
  255. ksadk/server/static/assets/{blockDiagram-GPEHLZMM-UTdVcZhn.js → blockDiagram-GPEHLZMM-BnaB3Ywv.js} +1 -1
  256. ksadk/server/static/assets/{c4Diagram-AAUBKEIU-Dix0GD4m.js → c4Diagram-AAUBKEIU-Dw4weZcp.js} +1 -1
  257. ksadk/server/static/assets/channel-Dt3rQTFI.js +1 -0
  258. ksadk/server/static/assets/{chunk-2J33WTMH-C2JxuZ42.js → chunk-2J33WTMH-ChjpLK7j.js} +1 -1
  259. ksadk/server/static/assets/{chunk-4BX2VUAB-Be57QPgD.js → chunk-4BX2VUAB-B9drTgOW.js} +1 -1
  260. ksadk/server/static/assets/{chunk-55IACEB6-WjSuy4nv.js → chunk-55IACEB6-CK4ROATy.js} +1 -1
  261. ksadk/server/static/assets/{chunk-727SXJPM-BOovP-b5.js → chunk-727SXJPM-B9KtTTgw.js} +1 -1
  262. ksadk/server/static/assets/{chunk-AQP2D5EJ-DOmZNmWj.js → chunk-AQP2D5EJ-1O1mki3m.js} +1 -1
  263. ksadk/server/static/assets/{chunk-FMBD7UC4-DzwlodkU.js → chunk-FMBD7UC4-B_fH2YuH.js} +1 -1
  264. ksadk/server/static/assets/{chunk-ND2GUHAM-DMqAikEU.js → chunk-ND2GUHAM-D6rFLaVV.js} +1 -1
  265. ksadk/server/static/assets/chunk-QZHKN3VN-iXEZtKQc.js +1 -0
  266. ksadk/server/static/assets/classDiagram-4FO5ZUOK-DIveV17Q.js +1 -0
  267. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-DIveV17Q.js +1 -0
  268. ksadk/server/static/assets/{cose-bilkent-S5V4N54A-Zhy2GBnP.js → cose-bilkent-S5V4N54A-ChNs_Mdk.js} +1 -1
  269. ksadk/server/static/assets/{dagre-BM42HDAG-CbKrtIUz.js → dagre-BM42HDAG-D0QXg_MQ.js} +1 -1
  270. ksadk/server/static/assets/{diagram-2AECGRRQ-BRApgQRK.js → diagram-2AECGRRQ-DBDDKwBQ.js} +1 -1
  271. ksadk/server/static/assets/{diagram-5GNKFQAL-D0xbnDiK.js → diagram-5GNKFQAL-BkwDOxmO.js} +1 -1
  272. ksadk/server/static/assets/{diagram-KO2AKTUF-CVugVI9L.js → diagram-KO2AKTUF-Bv8waYvY.js} +1 -1
  273. ksadk/server/static/assets/{diagram-LMA3HP47-DozUGgee.js → diagram-LMA3HP47-e1VECDdu.js} +1 -1
  274. ksadk/server/static/assets/{diagram-OG6HWLK6-ZOYsKlru.js → diagram-OG6HWLK6-Ds9adfRl.js} +1 -1
  275. ksadk/server/static/assets/{dist-DpKtt4Bo.js → dist-4N2NMVYg.js} +1 -1
  276. ksadk/server/static/assets/{dist-CkEKJFtk.js → dist-B-jNR6Vn.js} +1 -1
  277. ksadk/server/static/assets/{dist-D57wnGWd.js → dist-B5J2uhNk.js} +1 -1
  278. ksadk/server/static/assets/{dist-8_SfK1IP.js → dist-B5oS1zcj.js} +1 -1
  279. ksadk/server/static/assets/{dist-DMezvBGJ.js → dist-BB3-OwTQ.js} +1 -1
  280. ksadk/server/static/assets/{dist-2hInLS_J.js → dist-BIlKoW0k.js} +1 -1
  281. ksadk/server/static/assets/{dist-BrCcQ47T.js → dist-BjOdlDjj.js} +1 -1
  282. ksadk/server/static/assets/{dist-BmlMPsCc.js → dist-C1sz5Eo3.js} +1 -1
  283. ksadk/server/static/assets/{dist-B0NP_Z0z.js → dist-CWV4lDr1.js} +1 -1
  284. ksadk/server/static/assets/{dist-D-xOD048.js → dist-CmZHzlwZ.js} +1 -1
  285. ksadk/server/static/assets/{dist-DL_NKc_z.js → dist-D6MpCZtz.js} +1 -1
  286. ksadk/server/static/assets/{dist-DyOkZmze.js → dist-DJN_6Y39.js} +1 -1
  287. ksadk/server/static/assets/{dist-DmFaq_Iy.js → dist-DQU9EWw-.js} +1 -1
  288. ksadk/server/static/assets/{dist-gX6GOLKq.js → dist-DWKByxWV.js} +1 -1
  289. ksadk/server/static/assets/{dist-DyWsb78Q.js → dist-Dli7qW-B.js} +1 -1
  290. ksadk/server/static/assets/{dist-BIJVDMuB.js → dist-DsHPdk3W.js} +1 -1
  291. ksadk/server/static/assets/{dist-Dp0k7bWI.js → dist-X4TnqwOK.js} +1 -1
  292. ksadk/server/static/assets/{dist-8EEyGgDx.js → dist-_pHPTyZ-.js} +1 -1
  293. ksadk/server/static/assets/{dist-CPBtqRTW.js → dist-fhOuWds5.js} +1 -1
  294. ksadk/server/static/assets/{dist-D-JMdWPQ.js → dist-gLnrGsoU.js} +1 -1
  295. ksadk/server/static/assets/{dist-BssVmjIo.js → dist-j6Dxmf_j.js} +1 -1
  296. ksadk/server/static/assets/{dist-C3HIIaN5.js → dist-o2OVmKvt.js} +1 -1
  297. ksadk/server/static/assets/{erDiagram-TEJ5UH35-Bk-9bgE5.js → erDiagram-TEJ5UH35-BPItFKH6.js} +1 -1
  298. ksadk/server/static/assets/eventmodeling-FCH6USID-DYFSxbqr.js +1 -0
  299. ksadk/server/static/assets/{flowDiagram-I6XJVG4X-Dn9kZVuZ.js → flowDiagram-I6XJVG4X-BbYB9w5Y.js} +1 -1
  300. ksadk/server/static/assets/{ganttDiagram-6RSMTGT7-BGxXlJqm.js → ganttDiagram-6RSMTGT7-TQXa0KXv.js} +1 -1
  301. ksadk/server/static/assets/gitGraph-WXDBUCRP-DyNYp6BN.js +1 -0
  302. ksadk/server/static/assets/{gitGraphDiagram-PVQCEYII-C7Q0X-wi.js → gitGraphDiagram-PVQCEYII-bKblCnpa.js} +1 -1
  303. ksadk/server/static/assets/index-R52pJJvg.js +177 -0
  304. ksadk/server/static/assets/index-jJr3_955.css +2 -0
  305. ksadk/server/static/assets/info-J43DQDTF-WUx7qTde.js +1 -0
  306. ksadk/server/static/assets/{infoDiagram-5YYISTIA-BO_CSqq5.js → infoDiagram-5YYISTIA-BGVT7J_i.js} +1 -1
  307. ksadk/server/static/assets/{ishikawaDiagram-YF4QCWOH-eYLPLd46.js → ishikawaDiagram-YF4QCWOH-K0OOfVna.js} +1 -1
  308. ksadk/server/static/assets/{journeyDiagram-JHISSGLW-De9geSb0.js → journeyDiagram-JHISSGLW-8LeOJaZp.js} +1 -1
  309. ksadk/server/static/assets/{kanban-definition-UN3LZRKU-Cs80kQto.js → kanban-definition-UN3LZRKU-C6uCgZrW.js} +1 -1
  310. ksadk/server/static/assets/{katex-DSrCFD8n.js → katex-CYWseY5E.js} +1 -1
  311. ksadk/server/static/assets/{linear-CN9sbKTF.js → linear-hdBcYzM8.js} +1 -1
  312. ksadk/server/static/assets/{mermaid-parser.core-DlgSBU8l.js → mermaid-parser.core-BWrDjSZM.js} +2 -2
  313. ksadk/server/static/assets/{mindmap-definition-RKZ34NQL-9afz7Oug.js → mindmap-definition-RKZ34NQL-Bjy_2v4_.js} +1 -1
  314. ksadk/server/static/assets/packet-YPE3B663-BN13y_xl.js +1 -0
  315. ksadk/server/static/assets/pie-LRSECV5Y-ftSLXhhc.js +1 -0
  316. ksadk/server/static/assets/{pieDiagram-4H26LBE5-DPv_VstN.js → pieDiagram-4H26LBE5-GmmqNiVH.js} +1 -1
  317. ksadk/server/static/assets/{quadrantDiagram-W4KKPZXB-o77wZ1XK.js → quadrantDiagram-W4KKPZXB-BmkRbwCg.js} +1 -1
  318. ksadk/server/static/assets/radar-GUYGQ44K-jaICkIeO.js +1 -0
  319. ksadk/server/static/assets/{requirementDiagram-4Y6WPE33-BYVw81VC.js → requirementDiagram-4Y6WPE33-DSWFqL7c.js} +1 -1
  320. ksadk/server/static/assets/{sankeyDiagram-5OEKKPKP-B7nZFMKT.js → sankeyDiagram-5OEKKPKP-l6iXmU65.js} +1 -1
  321. ksadk/server/static/assets/{sequenceDiagram-3UESZ5HK-BGRRrFw5.js → sequenceDiagram-3UESZ5HK-Cq6UBeQB.js} +1 -1
  322. ksadk/server/static/assets/{stateDiagram-AJRCARHV-BUfHCoPs.js → stateDiagram-AJRCARHV-qzTQpg3Y.js} +1 -1
  323. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-BYCoYGAN.js +1 -0
  324. ksadk/server/static/assets/{timeline-definition-PNZ67QCA-FbCTGrf9.js → timeline-definition-PNZ67QCA-DEz24vV0.js} +1 -1
  325. ksadk/server/static/assets/treeView-BLDUP644-Cpib_vlz.js +1 -0
  326. ksadk/server/static/assets/treemap-LRROVOQU-DQxfmVHK.js +1 -0
  327. ksadk/server/static/assets/{vennDiagram-CIIHVFJN-DWgwtPsJ.js → vennDiagram-CIIHVFJN-CMCixki2.js} +1 -1
  328. ksadk/server/static/assets/wardley-L42UT6IY-BQYHnnkU.js +1 -0
  329. ksadk/server/static/assets/{wardleyDiagram-YWT4CUSO-2x8G-tTM.js → wardleyDiagram-YWT4CUSO-CVzB8F9K.js} +1 -1
  330. ksadk/server/static/assets/{xychartDiagram-2RQKCTM6-Drma3AYl.js → xychartDiagram-2RQKCTM6-BFBqBLc1.js} +1 -1
  331. ksadk/server/static/index.html +2 -2
  332. ksadk/server/terminal_sessions.py +111 -58
  333. ksadk/sessions/__init__.py +69 -19
  334. ksadk/sessions/base.py +31 -11
  335. ksadk/sessions/continuity.py +2 -3
  336. ksadk/sessions/in_memory.py +46 -2
  337. ksadk/sessions/local_service.py +148 -17
  338. ksadk/sessions/postgres_service.py +143 -25
  339. ksadk/sessions/resilient.py +36 -8
  340. ksadk/skills/models.py +17 -5
  341. ksadk/skills/package_store.py +5 -2
  342. ksadk/skills/runtime/agent.py +20 -5
  343. ksadk/skills/runtime/artifacts.py +1 -5
  344. ksadk/skills/runtime/backends/e2b.py +10 -4
  345. ksadk/skills/runtime/backends/local.py +15 -3
  346. ksadk/skills/runtime/base.py +1 -2
  347. ksadk/skills/runtime/executor.py +10 -3
  348. ksadk/skills/runtime/factory.py +4 -2
  349. ksadk/skills/runtime/loader.py +1 -2
  350. ksadk/skills/runtime/registry.py +15 -10
  351. ksadk/skills/runtime/request.py +3 -1
  352. ksadk/skills/service_client.py +47 -16
  353. ksadk/skills/tool_defs.py +15 -10
  354. ksadk/studio/__init__.py +5 -0
  355. ksadk/studio/agent_avatar_assets.py +120 -0
  356. ksadk/studio/agent_lifecycle.py +51 -0
  357. ksadk/studio/api.py +1046 -0
  358. ksadk/studio/api_catalog_routes.py +324 -0
  359. ksadk/studio/api_contracts.py +177 -0
  360. ksadk/studio/api_helpers.py +132 -0
  361. ksadk/studio/authoring.py +524 -0
  362. ksadk/studio/authoring_coordinator.py +285 -0
  363. ksadk/studio/builder.py +320 -0
  364. ksadk/studio/capabilities.py +351 -0
  365. ksadk/studio/cloud.py +278 -0
  366. ksadk/studio/codex_agent_service.py +583 -0
  367. ksadk/studio/codex_builder.py +324 -0
  368. ksadk/studio/codex_manifest.py +278 -0
  369. ksadk/studio/codex_run.py +352 -0
  370. ksadk/studio/compiler.py +189 -0
  371. ksadk/studio/contracts.py +644 -0
  372. ksadk/studio/errors.py +47 -0
  373. ksadk/studio/evaluation.py +192 -0
  374. ksadk/studio/event_store.py +284 -0
  375. ksadk/studio/framework_run.py +114 -0
  376. ksadk/studio/identifiers.py +33 -0
  377. ksadk/studio/mcp_runtime.py +229 -0
  378. ksadk/studio/model_client.py +543 -0
  379. ksadk/studio/model_profile_service.py +214 -0
  380. ksadk/studio/operations.py +243 -0
  381. ksadk/studio/otel_trace.py +754 -0
  382. ksadk/studio/pagination.py +182 -0
  383. ksadk/studio/python_tool_inspection.py +183 -0
  384. ksadk/studio/repository.py +306 -0
  385. ksadk/studio/resource_catalog.py +1217 -0
  386. ksadk/studio/run_service.py +707 -0
  387. ksadk/studio/runtime_catalog.py +74 -0
  388. ksadk/studio/runtime_source.py +339 -0
  389. ksadk/studio/service.py +1141 -0
  390. ksadk/studio/shared_web.py +994 -0
  391. ksadk/studio/skill_discovery.py +628 -0
  392. ksadk/studio/static/assets/PrismRenderer-IYN-ffww.js +3 -0
  393. ksadk/studio/static/assets/index-CaEN0eTR.css +1 -0
  394. ksadk/studio/static/assets/index-DI2eY_NH.js +252 -0
  395. ksadk/studio/static/assets/react-vendor-BNmTiJ-I.js +9 -0
  396. ksadk/studio/static/assets/rolldown-runtime-hePW80VL.js +1 -0
  397. ksadk/studio/static/index.html +15 -0
  398. ksadk/studio/templates.py +630 -0
  399. ksadk/studio/validator.py +246 -0
  400. ksadk/studio/workspace.py +137 -0
  401. ksadk/terminal_exec_policy.py +3 -4
  402. ksadk/tools/gateway.py +101 -15
  403. ksadk/tools/result_budget.py +12 -4
  404. ksadk/toolsets/__init__.py +161 -37
  405. ksadk/toolsets/a2a.py +426 -0
  406. ksadk/toolsets/platform.py +21 -5
  407. ksadk/toolsets/sandbox.py +82 -16
  408. ksadk/toolsets/skills.py +200 -39
  409. ksadk/toolsets/web.py +123 -26
  410. ksadk/toolsets/workspace.py +212 -101
  411. ksadk/tracing/__init__.py +19 -21
  412. ksadk/tracing/exporters/inmemory_exporter.py +62 -51
  413. ksadk/tracing/setup.py +135 -506
  414. ksadk/tracing/span_utils.py +0 -41
  415. ksadk/tui/loop.py +78 -30
  416. ksadk/tui/stream_render.py +1 -0
  417. ksadk/ui_config.py +5 -3
  418. ksadk/version.py +1 -1
  419. ksadk_runtime_common/memory_backend/registry.py +56 -56
  420. ksadk_runtime_common/schemas/runtime_event_v1.json +95 -0
  421. ksadk_runtime_common/workspace_files/router.py +8 -2
  422. agentengine_sdk_python-0.7.0.dist-info/RECORD +0 -482
  423. ksadk/a2a/card_builder.py +0 -64
  424. ksadk/a2a/client.py +0 -309
  425. ksadk/runners/utils/langfuse.py +0 -230
  426. ksadk/server/static/assets/CodeBlock-P16VOLYi.js +0 -9
  427. ksadk/server/static/assets/MathMessageMarkdown-CdGiQWHR.js +0 -8
  428. ksadk/server/static/assets/MermaidBlock-IOcal8cm.js +0 -303
  429. ksadk/server/static/assets/NativeTerminalPanel-DGSDWsei.js +0 -1
  430. ksadk/server/static/assets/architecture-7EHR7CIX-BvUlsA6l.js +0 -1
  431. ksadk/server/static/assets/channel-CTuydARX.js +0 -1
  432. ksadk/server/static/assets/chunk-QZHKN3VN-BnCydivS.js +0 -1
  433. ksadk/server/static/assets/classDiagram-4FO5ZUOK-BNHg45Be.js +0 -1
  434. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-BNHg45Be.js +0 -1
  435. ksadk/server/static/assets/eventmodeling-FCH6USID-DsAgWnlf.js +0 -1
  436. ksadk/server/static/assets/gitGraph-WXDBUCRP-BIao9Yjg.js +0 -1
  437. ksadk/server/static/assets/index-C00Lwg3L.js +0 -165
  438. ksadk/server/static/assets/index-DAURbCsP.css +0 -1
  439. ksadk/server/static/assets/info-J43DQDTF-CyipqGxU.js +0 -1
  440. ksadk/server/static/assets/packet-YPE3B663-CGkyRxlg.js +0 -1
  441. ksadk/server/static/assets/pie-LRSECV5Y-M0uWAf4n.js +0 -1
  442. ksadk/server/static/assets/radar-GUYGQ44K-Bdbm24-x.js +0 -1
  443. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-8xBN_gLM.js +0 -1
  444. ksadk/server/static/assets/treeView-BLDUP644-npMo0ak1.js +0 -1
  445. ksadk/server/static/assets/treemap-LRROVOQU-CHdzrrdo.js +0 -1
  446. ksadk/server/static/assets/wardley-L42UT6IY-BEQz7wyy.js +0 -1
  447. ksadk/tracing/exporters/langfuse_exporter.py +0 -445
  448. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.1.dist-info}/entry_points.txt +0 -0
  449. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.1.dist-info}/licenses/LICENSE +0 -0
  450. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.1.dist-info}/top_level.txt +0 -0
@@ -22,7 +22,7 @@ class SessionContinuityStatus:
22
22
  details: dict[str, Any] = field(default_factory=dict)
23
23
 
24
24
  def to_payload(self) -> dict[str, Any]:
25
- payload = {
25
+ payload: dict[str, Any] = {
26
26
  "Level": self.level.value,
27
27
  "Path": self.path,
28
28
  "Runner": self.runner,
@@ -320,8 +320,7 @@ class ADKSessionAdapter(RunnerSessionAdapter):
320
320
  stm_backend = getattr(_stm, "backend", None) if _stm is not None else None
321
321
  is_durable = stm_backend is not None and stm_backend != "local"
322
322
  level = (
323
- SessionContinuityLevel.RUNTIME if is_durable
324
- else SessionContinuityLevel.SEMANTIC
323
+ SessionContinuityLevel.RUNTIME if is_durable else SessionContinuityLevel.SEMANTIC
325
324
  )
326
325
  path = "adk_resume"
327
326
  elif has_native_session:
@@ -5,6 +5,7 @@ import copy
5
5
  import time
6
6
  from typing import Optional
7
7
 
8
+ from ksadk.ids import new_session_id
8
9
  from ksadk.sessions.base import BaseSessionService, Session, SessionEvent, SessionState, generate_id
9
10
 
10
11
 
@@ -25,7 +26,7 @@ class InMemorySessionService(BaseSessionService):
25
26
  return copy.deepcopy(self._sessions[session_id])
26
27
 
27
28
  session = Session(
28
- id=session_id or generate_id(),
29
+ id=session_id or new_session_id(),
29
30
  agent_id=agent_id,
30
31
  user_id=user_id,
31
32
  )
@@ -43,6 +44,15 @@ class InMemorySessionService(BaseSessionService):
43
44
  session = self._sessions.get(session_id)
44
45
  return copy.deepcopy(session) if session else None
45
46
 
47
+ async def get_session_metadata(self, session_id: str) -> Optional[Session]:
48
+ async with self._lock:
49
+ session = self._sessions.get(session_id)
50
+ if session is None:
51
+ return None
52
+ metadata = copy.deepcopy(session)
53
+ metadata.events = []
54
+ return metadata
55
+
46
56
  async def list_sessions(
47
57
  self,
48
58
  agent_id: str,
@@ -56,7 +66,10 @@ class InMemorySessionService(BaseSessionService):
56
66
  for session in self._sessions.values()
57
67
  if session.agent_id == agent_id and (user_id is None or session.user_id == user_id)
58
68
  ]
59
- sessions.sort(key=lambda item: (item.updated_at, item.created_at), reverse=True)
69
+ sessions.sort(
70
+ key=lambda item: (item.updated_at, item.created_at, item.id),
71
+ reverse=True,
72
+ )
60
73
  start = offset or 0
61
74
  end = None if limit is None else start + limit
62
75
  return sessions[start:end]
@@ -191,6 +204,37 @@ class InMemorySessionService(BaseSessionService):
191
204
  events = [event for event in events if event.seq_id < before_seq_id]
192
205
  return len(events)
193
206
 
207
+ async def get_events_for_agent(
208
+ self,
209
+ agent_id: str,
210
+ user_id: Optional[str] = None,
211
+ offset: Optional[int] = None,
212
+ limit: Optional[int] = None,
213
+ ) -> list[SessionEvent]:
214
+ async with self._lock:
215
+ merged = [
216
+ copy.deepcopy(event)
217
+ for session in self._sessions.values()
218
+ if session.agent_id == agent_id and (user_id is None or session.user_id == user_id)
219
+ for event in session.events
220
+ ]
221
+ merged.sort(key=lambda event: (event.timestamp, event.seq_id, event.id))
222
+ end = max(len(merged) - (offset or 0), 0)
223
+ start = 0 if limit is None else max(end - limit, 0)
224
+ return merged[start:end]
225
+
226
+ async def count_events_for_agent(
227
+ self,
228
+ agent_id: str,
229
+ user_id: Optional[str] = None,
230
+ ) -> int:
231
+ async with self._lock:
232
+ return sum(
233
+ len(session.events)
234
+ for session in self._sessions.values()
235
+ if session.agent_id == agent_id and (user_id is None or session.user_id == user_id)
236
+ )
237
+
194
238
  async def get_state(
195
239
  self,
196
240
  agent_id: str,
@@ -7,11 +7,12 @@ import json
7
7
  import os
8
8
  import sqlite3
9
9
  import time
10
+ from collections.abc import Iterator
10
11
  from contextlib import closing, contextmanager
11
12
  from pathlib import Path
12
- from collections.abc import Iterator
13
13
  from typing import Optional
14
14
 
15
+ from ksadk.ids import new_session_id
15
16
  from ksadk.sessions.base import (
16
17
  BaseSessionService,
17
18
  Session,
@@ -76,6 +77,14 @@ class LocalSessionService(BaseSessionService):
76
77
  async with self._lock:
77
78
  return await asyncio.to_thread(self._get_session_sync, session_id)
78
79
 
80
+ async def get_session_metadata(self, session_id: str) -> Optional[Session]:
81
+ async with self._lock:
82
+ return await asyncio.to_thread(
83
+ self._get_session_sync,
84
+ session_id,
85
+ include_events=False,
86
+ )
87
+
79
88
  async def list_sessions(
80
89
  self,
81
90
  agent_id: str,
@@ -161,6 +170,114 @@ class LocalSessionService(BaseSessionService):
161
170
  before_seq_id,
162
171
  )
163
172
 
173
+ async def get_events_for_agent(
174
+ self,
175
+ agent_id: str,
176
+ user_id: Optional[str] = None,
177
+ offset: Optional[int] = None,
178
+ limit: Optional[int] = None,
179
+ ) -> list[SessionEvent]:
180
+ async with self._lock:
181
+ return await asyncio.to_thread(
182
+ self._get_events_for_agent_sync,
183
+ agent_id,
184
+ user_id,
185
+ offset,
186
+ limit,
187
+ )
188
+
189
+ async def count_events_for_agent(
190
+ self,
191
+ agent_id: str,
192
+ user_id: Optional[str] = None,
193
+ ) -> int:
194
+ async with self._lock:
195
+ return await asyncio.to_thread(
196
+ self._count_events_for_agent_sync,
197
+ agent_id,
198
+ user_id,
199
+ )
200
+
201
+ def _get_events_for_agent_sync(
202
+ self,
203
+ agent_id: str,
204
+ user_id: Optional[str],
205
+ offset: Optional[int],
206
+ limit: Optional[int],
207
+ ) -> list[SessionEvent]:
208
+ columns = (
209
+ "e.id, e.session_id, e.author, e.event_type, e.content_json, e.timestamp, "
210
+ "e.state_delta_json, e.seq_id, e.invocation_id, e.metadata_json"
211
+ )
212
+ user_clause = "AND s.user_id = ?" if user_id is not None else ""
213
+ from_clause = (
214
+ f"FROM {KSADK_EVENTS_TABLE} e "
215
+ f"JOIN {KSADK_SESSIONS_TABLE} s ON s.id = e.session_id "
216
+ f"WHERE s.agent_id = ? {user_clause}"
217
+ )
218
+ base_params: list[object] = [agent_id]
219
+ if user_id is not None:
220
+ base_params.append(user_id)
221
+ with self._connection() as connection:
222
+ if limit is not None or offset is not None:
223
+ # 与 get_events 一致的"最新 N 条"尾部语义:先 DESC 取窗口再 ASC 重排
224
+ query = f"""
225
+ SELECT id, session_id, author, event_type, content_json, timestamp,
226
+ state_delta_json, seq_id, invocation_id, metadata_json
227
+ FROM (
228
+ SELECT {columns}
229
+ {from_clause}
230
+ ORDER BY e.timestamp DESC, e.seq_id DESC, e.id DESC
231
+ LIMIT ? OFFSET ?
232
+ )
233
+ ORDER BY timestamp ASC, seq_id ASC, id ASC
234
+ """
235
+ params = [*base_params, limit if limit is not None else -1, offset or 0]
236
+ else:
237
+ query = f"""
238
+ SELECT {columns}
239
+ {from_clause}
240
+ ORDER BY e.timestamp ASC, e.seq_id ASC, e.id ASC
241
+ """
242
+ params = base_params
243
+ rows = connection.execute(query, params).fetchall()
244
+ return [
245
+ SessionEvent(
246
+ id=row["id"],
247
+ session_id=row["session_id"],
248
+ author=row["author"],
249
+ event_type=row["event_type"],
250
+ content=json.loads(row["content_json"] or "{}"),
251
+ timestamp=row["timestamp"],
252
+ state_delta=json.loads(row["state_delta_json"] or "{}"),
253
+ seq_id=row["seq_id"],
254
+ invocation_id=row["invocation_id"],
255
+ metadata=json.loads(row["metadata_json"] or "{}"),
256
+ )
257
+ for row in rows
258
+ ]
259
+
260
+ def _count_events_for_agent_sync(
261
+ self,
262
+ agent_id: str,
263
+ user_id: Optional[str],
264
+ ) -> int:
265
+ user_clause = "AND s.user_id = ?" if user_id is not None else ""
266
+ params: list[object] = [agent_id]
267
+ if user_id is not None:
268
+ params.append(user_id)
269
+ with self._connection() as connection:
270
+ row = connection.execute(
271
+ f"""
272
+ SELECT COUNT(*) AS total
273
+ FROM {KSADK_EVENTS_TABLE} e
274
+ JOIN {KSADK_SESSIONS_TABLE} s ON s.id = e.session_id
275
+ WHERE s.agent_id = ? {user_clause}
276
+ """,
277
+ params,
278
+ ).fetchone()
279
+ return int(row["total"] if row else 0)
280
+
164
281
  async def get_state(
165
282
  self,
166
283
  agent_id: str,
@@ -258,9 +375,7 @@ class LocalSessionService(BaseSessionService):
258
375
  and not self._table_exists(connection, KSADK_EVENTS_TABLE)
259
376
  and {"session_id", "author", "event_type"}.issubset(legacy_event_columns)
260
377
  ):
261
- connection.execute(
262
- f"ALTER TABLE {LEGACY_EVENTS_TABLE} RENAME TO {KSADK_EVENTS_TABLE}"
263
- )
378
+ connection.execute(f"ALTER TABLE {LEGACY_EVENTS_TABLE} RENAME TO {KSADK_EVENTS_TABLE}")
264
379
 
265
380
  legacy_state_columns = self._table_columns(connection, LEGACY_STATES_TABLE)
266
381
  if (
@@ -268,15 +383,12 @@ class LocalSessionService(BaseSessionService):
268
383
  and not self._table_exists(connection, KSADK_STATES_TABLE)
269
384
  and {"scope", "agent_id", "state_json"}.issubset(legacy_state_columns)
270
385
  ):
271
- connection.execute(
272
- f"ALTER TABLE {LEGACY_STATES_TABLE} RENAME TO {KSADK_STATES_TABLE}"
273
- )
386
+ connection.execute(f"ALTER TABLE {LEGACY_STATES_TABLE} RENAME TO {KSADK_STATES_TABLE}")
274
387
 
275
388
  def _ensure_schema(self) -> None:
276
389
  with self._connection() as connection:
277
390
  self._migrate_legacy_schema(connection)
278
- connection.executescript(
279
- f"""
391
+ connection.executescript(f"""
280
392
  CREATE TABLE IF NOT EXISTS {KSADK_SESSIONS_TABLE} (
281
393
  id TEXT PRIMARY KEY,
282
394
  agent_id TEXT NOT NULL,
@@ -309,6 +421,16 @@ class LocalSessionService(BaseSessionService):
309
421
  CREATE INDEX IF NOT EXISTS idx_ksadk_events_session_seq
310
422
  ON {KSADK_EVENTS_TABLE} (session_id, seq_id);
311
423
 
424
+ -- 跨会话事件查询(get_events_for_agent)JOIN sessions 按
425
+ -- s.agent_id 过滤 + ORDER BY e.timestamp;覆盖索引服务 JOIN 键
426
+ -- s.id=e.session_id + 排序。
427
+ CREATE INDEX IF NOT EXISTS idx_ksadk_events_session_ts
428
+ ON {KSADK_EVENTS_TABLE} (session_id, timestamp, id);
429
+
430
+ -- ListSessions 按 agent_id 过滤 + updated_at DESC 排序。
431
+ CREATE INDEX IF NOT EXISTS idx_ksadk_sessions_agent_updated
432
+ ON {KSADK_SESSIONS_TABLE} (agent_id, updated_at DESC, id);
433
+
312
434
  CREATE TABLE IF NOT EXISTS {KSADK_STATES_TABLE} (
313
435
  scope TEXT NOT NULL,
314
436
  agent_id TEXT NOT NULL,
@@ -319,8 +441,7 @@ class LocalSessionService(BaseSessionService):
319
441
  updated_at REAL NOT NULL,
320
442
  PRIMARY KEY (scope, agent_id, user_id, session_id)
321
443
  );
322
- """
323
- )
444
+ """)
324
445
  self._ensure_columns(
325
446
  connection,
326
447
  KSADK_SESSIONS_TABLE,
@@ -367,7 +488,7 @@ class LocalSessionService(BaseSessionService):
367
488
 
368
489
  now = time.time()
369
490
  session = Session(
370
- id=session_id or generate_id(),
491
+ id=session_id or new_session_id(),
371
492
  agent_id=agent_id,
372
493
  user_id=user_id,
373
494
  created_at=now,
@@ -413,6 +534,7 @@ class LocalSessionService(BaseSessionService):
413
534
  session_id: str,
414
535
  *,
415
536
  connection: Optional[sqlite3.Connection] = None,
537
+ include_events: bool = True,
416
538
  ) -> Optional[Session]:
417
539
  owns_connection = connection is None
418
540
  connection = connection or self._connect()
@@ -439,7 +561,11 @@ class LocalSessionService(BaseSessionService):
439
561
  first_prompt=row["first_prompt"],
440
562
  last_prompt=row["last_prompt"],
441
563
  state=json.loads(row["state_json"] or "{}"),
442
- events=self._get_events_sync(session_id, connection=connection),
564
+ events=(
565
+ self._get_events_sync(session_id, connection=connection)
566
+ if include_events
567
+ else []
568
+ ),
443
569
  created_at=row["created_at"],
444
570
  updated_at=row["updated_at"],
445
571
  version=row["version"],
@@ -467,7 +593,7 @@ class LocalSessionService(BaseSessionService):
467
593
  if user_id is not None:
468
594
  query += " AND user_id = ?"
469
595
  params.append(user_id)
470
- query += " ORDER BY updated_at DESC, created_at DESC"
596
+ query += " ORDER BY updated_at DESC, created_at DESC, id DESC"
471
597
  if limit is not None:
472
598
  query += " LIMIT ?"
473
599
  params.append(limit)
@@ -520,8 +646,12 @@ class LocalSessionService(BaseSessionService):
520
646
  if row is None:
521
647
  return False
522
648
 
523
- connection.execute(f"DELETE FROM {KSADK_EVENTS_TABLE} WHERE session_id = ?", (session_id,))
524
- connection.execute(f"DELETE FROM {KSADK_STATES_TABLE} WHERE session_id = ?", (session_id,))
649
+ connection.execute(
650
+ f"DELETE FROM {KSADK_EVENTS_TABLE} WHERE session_id = ?", (session_id,)
651
+ )
652
+ connection.execute(
653
+ f"DELETE FROM {KSADK_STATES_TABLE} WHERE session_id = ?", (session_id,)
654
+ )
525
655
  connection.execute(f"DELETE FROM {KSADK_SESSIONS_TABLE} WHERE id = ?", (session_id,))
526
656
  connection.commit()
527
657
  return True
@@ -541,7 +671,8 @@ class LocalSessionService(BaseSessionService):
541
671
 
542
672
  next_seq = int(
543
673
  connection.execute(
544
- f"SELECT COALESCE(MAX(seq_id), 0) + 1 FROM {KSADK_EVENTS_TABLE} WHERE session_id = ?",
674
+ f"SELECT COALESCE(MAX(seq_id), 0) + 1 "
675
+ f"FROM {KSADK_EVENTS_TABLE} WHERE session_id = ?",
545
676
  (session_id,),
546
677
  ).fetchone()[0]
547
678
  )
@@ -9,6 +9,7 @@ import time
9
9
  from typing import Any, Optional
10
10
  from urllib.parse import urlsplit, urlunsplit
11
11
 
12
+ from ksadk.ids import new_session_id
12
13
  from ksadk.sessions.base import (
13
14
  BaseSessionService,
14
15
  Session,
@@ -59,7 +60,7 @@ class PostgresSessionService(BaseSessionService):
59
60
  session_id: Optional[str] = None,
60
61
  ) -> Session:
61
62
  await self._ensure_schema()
62
- session_key = session_id or generate_id()
63
+ session_key = session_id or new_session_id()
63
64
  async with self._pool.acquire() as connection:
64
65
  async with connection.transaction():
65
66
  existing = await self._get_session_with_connection(connection, session_key)
@@ -70,8 +71,9 @@ class PostgresSessionService(BaseSessionService):
70
71
  await connection.execute(
71
72
  f"""
72
73
  INSERT INTO {KSADK_PG_SESSIONS_TABLE} (
73
- namespace, tenant_id, workspace_id, id, agent_id, user_id, title, title_source, summary,
74
- first_prompt, last_prompt, state_json, created_at, updated_at, version
74
+ namespace, tenant_id, workspace_id, id, agent_id, user_id,
75
+ title, title_source, summary, first_prompt, last_prompt,
76
+ state_json, created_at, updated_at, version
75
77
  )
76
78
  VALUES ($1, $2, $3, $4, $5, $6, '', '', '', '', '', $7::jsonb, $8, $9, 0)
77
79
  ON CONFLICT (namespace, id) DO NOTHING
@@ -96,7 +98,8 @@ class PostgresSessionService(BaseSessionService):
96
98
  await connection.execute(
97
99
  f"""
98
100
  INSERT INTO {KSADK_PG_STATES_TABLE} (
99
- namespace, tenant_id, workspace_id, scope, agent_id, user_id, session_id, state_json, version, updated_at
101
+ namespace, tenant_id, workspace_id, scope, agent_id,
102
+ user_id, session_id, state_json, version, updated_at
100
103
  )
101
104
  VALUES ($1, $2, $3, 'session', $4, $5, $6, $7::jsonb, 0, $8)
102
105
  ON CONFLICT (namespace, scope, agent_id, user_id, session_id)
@@ -118,6 +121,15 @@ class PostgresSessionService(BaseSessionService):
118
121
  async with self._pool.acquire() as connection:
119
122
  return await self._get_session_with_connection(connection, session_id)
120
123
 
124
+ async def get_session_metadata(self, session_id: str) -> Optional[Session]:
125
+ await self._ensure_schema()
126
+ async with self._pool.acquire() as connection:
127
+ return await self._get_session_with_connection(
128
+ connection,
129
+ session_id,
130
+ include_events=False,
131
+ )
132
+
121
133
  async def list_sessions(
122
134
  self,
123
135
  agent_id: str,
@@ -128,7 +140,8 @@ class PostgresSessionService(BaseSessionService):
128
140
  await self._ensure_schema()
129
141
  async with self._pool.acquire() as connection:
130
142
  query = f"""
131
- SELECT id, agent_id, user_id, title, title_source, summary, first_prompt, last_prompt,
143
+ SELECT id, agent_id, user_id, title, title_source, summary,
144
+ first_prompt, last_prompt,
132
145
  state_json, created_at, updated_at, version
133
146
  FROM {KSADK_PG_SESSIONS_TABLE}
134
147
  WHERE namespace = $1 AND agent_id = $2
@@ -137,7 +150,7 @@ class PostgresSessionService(BaseSessionService):
137
150
  if user_id is not None:
138
151
  params.append(user_id)
139
152
  query += f" AND user_id = ${len(params)}"
140
- query += " ORDER BY updated_at DESC, created_at DESC"
153
+ query += " ORDER BY updated_at DESC, created_at DESC, id DESC"
141
154
  if limit is not None:
142
155
  params.append(limit)
143
156
  query += f" LIMIT ${len(params)}"
@@ -205,7 +218,8 @@ class PostgresSessionService(BaseSessionService):
205
218
  async with connection.transaction():
206
219
  row = await connection.fetchrow(
207
220
  f"""
208
- SELECT id, agent_id, user_id, title, title_source, summary, first_prompt, last_prompt,
221
+ SELECT id, agent_id, user_id, title, title_source, summary,
222
+ first_prompt, last_prompt,
209
223
  state_json, created_at, updated_at, version
210
224
  FROM {KSADK_PG_SESSIONS_TABLE}
211
225
  WHERE namespace = $1 AND id = $2
@@ -294,10 +308,14 @@ class PostgresSessionService(BaseSessionService):
294
308
  await connection.execute(
295
309
  f"""
296
310
  INSERT INTO {KSADK_PG_EVENTS_TABLE} (
297
- namespace, tenant_id, workspace_id, id, session_id, author, event_type, content_json, timestamp,
311
+ namespace, tenant_id, workspace_id, id, session_id, author,
312
+ event_type, content_json, timestamp,
298
313
  state_delta_json, seq_id, invocation_id, metadata_json
299
314
  )
300
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8::jsonb, $9, $10::jsonb, $11, $12, $13::jsonb)
315
+ VALUES (
316
+ $1, $2, $3, $4, $5, $6, $7, $8::jsonb, $9,
317
+ $10::jsonb, $11, $12, $13::jsonb
318
+ )
301
319
  """,
302
320
  self.namespace,
303
321
  self.tenant_id,
@@ -419,6 +437,85 @@ class PostgresSessionService(BaseSessionService):
419
437
  """
420
438
  return int(await connection.fetchval(query, *params) or 0)
421
439
 
440
+ def _agent_events_query_parts(
441
+ self,
442
+ agent_id: str,
443
+ user_id: Optional[str],
444
+ ) -> tuple[str, list[Any]]:
445
+ """跨会话事件查询的公共 JOIN/WHERE。events 表无 agent_id 列,需 join sessions。"""
446
+ conditions = [
447
+ "e.namespace = $1",
448
+ "s.namespace = e.namespace",
449
+ "s.id = e.session_id",
450
+ "s.agent_id = $2",
451
+ ]
452
+ params: list[Any] = [self.namespace, agent_id]
453
+ if user_id is not None:
454
+ params.append(user_id)
455
+ conditions.append(f"s.user_id = ${len(params)}")
456
+ where_clause = " AND ".join(conditions)
457
+ from_clause = (
458
+ f"FROM {KSADK_PG_EVENTS_TABLE} e "
459
+ f"JOIN {KSADK_PG_SESSIONS_TABLE} s "
460
+ "ON s.namespace = e.namespace AND s.id = e.session_id "
461
+ f"WHERE {where_clause}"
462
+ )
463
+ return from_clause, params
464
+
465
+ async def get_events_for_agent(
466
+ self,
467
+ agent_id: str,
468
+ user_id: Optional[str] = None,
469
+ offset: Optional[int] = None,
470
+ limit: Optional[int] = None,
471
+ ) -> list[SessionEvent]:
472
+ await self._ensure_schema()
473
+ from_clause, params = self._agent_events_query_parts(agent_id, user_id)
474
+ columns = (
475
+ "e.id, e.session_id, e.author, e.event_type, e.content_json, e.timestamp, "
476
+ "e.state_delta_json, e.seq_id, e.invocation_id, e.metadata_json"
477
+ )
478
+ async with self._pool.acquire() as connection:
479
+ if limit is not None or offset is not None:
480
+ # 与 get_events 一致的"最新 N 条"尾部语义:先 DESC 取窗口再 ASC 重排
481
+ if limit is not None:
482
+ params.append(limit)
483
+ limit_sql = f"LIMIT ${len(params)}"
484
+ else:
485
+ limit_sql = ""
486
+ params.append(offset or 0)
487
+ offset_sql = f"OFFSET ${len(params)}"
488
+ query = f"""
489
+ SELECT id, session_id, author, event_type, content_json, timestamp,
490
+ state_delta_json, seq_id, invocation_id, metadata_json
491
+ FROM (
492
+ SELECT {columns}
493
+ {from_clause}
494
+ ORDER BY e.timestamp DESC, e.seq_id DESC, e.id DESC
495
+ {limit_sql} {offset_sql}
496
+ ) AS latest_events
497
+ ORDER BY timestamp ASC, seq_id ASC, id ASC
498
+ """
499
+ else:
500
+ query = f"""
501
+ SELECT {columns}
502
+ {from_clause}
503
+ ORDER BY e.timestamp ASC, e.seq_id ASC, e.id ASC
504
+ """
505
+ rows = await connection.fetch(query, *params)
506
+ return [self._event_from_row(row) for row in rows]
507
+
508
+ async def count_events_for_agent(
509
+ self,
510
+ agent_id: str,
511
+ user_id: Optional[str] = None,
512
+ ) -> int:
513
+ await self._ensure_schema()
514
+ from_clause, params = self._agent_events_query_parts(agent_id, user_id)
515
+ async with self._pool.acquire() as connection:
516
+ query = f"SELECT COUNT(*) AS total {from_clause}"
517
+ return int(await connection.fetchval(query, *params) or 0)
518
+
422
519
  async def get_state(
423
520
  self,
424
521
  agent_id: str,
@@ -445,7 +542,8 @@ class PostgresSessionService(BaseSessionService):
445
542
  f"""
446
543
  SELECT scope, agent_id, user_id, session_id, state_json, version, updated_at
447
544
  FROM {KSADK_PG_STATES_TABLE}
448
- WHERE namespace = $1 AND scope = $2 AND agent_id = $3 AND user_id = $4 AND session_id = $5
545
+ WHERE namespace = $1 AND scope = $2 AND agent_id = $3
546
+ AND user_id = $4 AND session_id = $5
449
547
  """,
450
548
  self.namespace,
451
549
  scope,
@@ -506,7 +604,8 @@ class PostgresSessionService(BaseSessionService):
506
604
  f"""
507
605
  SELECT state_json, version
508
606
  FROM {KSADK_PG_STATES_TABLE}
509
- WHERE namespace = $1 AND scope = $2 AND agent_id = $3 AND user_id = $4 AND session_id = $5
607
+ WHERE namespace = $1 AND scope = $2 AND agent_id = $3
608
+ AND user_id = $4 AND session_id = $5
510
609
  FOR UPDATE
511
610
  """,
512
611
  self.namespace,
@@ -521,7 +620,8 @@ class PostgresSessionService(BaseSessionService):
521
620
  await connection.execute(
522
621
  f"""
523
622
  INSERT INTO {KSADK_PG_STATES_TABLE} (
524
- namespace, tenant_id, workspace_id, scope, agent_id, user_id, session_id, state_json, version, updated_at
623
+ namespace, tenant_id, workspace_id, scope, agent_id,
624
+ user_id, session_id, state_json, version, updated_at
525
625
  )
526
626
  VALUES ($1, $2, $3, $4, $5, $6, $7, $8::jsonb, $9, $10)
527
627
  ON CONFLICT (namespace, scope, agent_id, user_id, session_id)
@@ -568,7 +668,7 @@ class PostgresSessionService(BaseSessionService):
568
668
  if self._pool is not None:
569
669
  return
570
670
  try:
571
- import asyncpg
671
+ import asyncpg # type: ignore[import-untyped]
572
672
  except ImportError as exc:
573
673
  raise SessionBackendUnavailable(
574
674
  "asyncpg is required for KSADK_SESSION_BACKEND=postgres"
@@ -595,8 +695,7 @@ class PostgresSessionService(BaseSessionService):
595
695
  return
596
696
  await self._ensure_pool()
597
697
  async with self._pool.acquire() as connection:
598
- await connection.execute(
599
- f"""
698
+ await connection.execute(f"""
600
699
  CREATE TABLE IF NOT EXISTS {KSADK_PG_SESSIONS_TABLE} (
601
700
  namespace TEXT NOT NULL,
602
701
  tenant_id TEXT NOT NULL DEFAULT 'default',
@@ -640,6 +739,18 @@ class PostgresSessionService(BaseSessionService):
640
739
  CREATE INDEX IF NOT EXISTS idx_ksadk_pg_events_session_seq
641
740
  ON {KSADK_PG_EVENTS_TABLE} (namespace, session_id, seq_id);
642
741
 
742
+ -- 跨会话事件查询(get_events_for_agent)需 JOIN sessions 按
743
+ -- s.agent_id 过滤并按 e.timestamp 排序;events 表无 agent_id 列,
744
+ -- 覆盖索引 (namespace, session_id, timestamp, id) 服务 JOIN 键
745
+ -- s.id=e.session_id + ORDER BY e.timestamp DESC。
746
+ CREATE INDEX IF NOT EXISTS idx_ksadk_pg_events_session_ts
747
+ ON {KSADK_PG_EVENTS_TABLE} (namespace, session_id, timestamp, id);
748
+
749
+ -- ListSessions 归并按 agent_id 过滤 + updated_at DESC 排序;
750
+ -- sessions 表 PK 是 (namespace, id),缺 agent_id 前缀索引。
751
+ CREATE INDEX IF NOT EXISTS idx_ksadk_pg_sessions_agent_updated
752
+ ON {KSADK_PG_SESSIONS_TABLE} (namespace, agent_id, updated_at DESC, id);
753
+
643
754
  CREATE TABLE IF NOT EXISTS {KSADK_PG_STATES_TABLE} (
644
755
  namespace TEXT NOT NULL,
645
756
  tenant_id TEXT NOT NULL DEFAULT 'default',
@@ -666,11 +777,9 @@ class PostgresSessionService(BaseSessionService):
666
777
  ADD COLUMN IF NOT EXISTS tenant_id TEXT NOT NULL DEFAULT 'default';
667
778
  ALTER TABLE {KSADK_PG_STATES_TABLE}
668
779
  ADD COLUMN IF NOT EXISTS workspace_id TEXT NOT NULL DEFAULT 'default';
669
- """
670
- )
780
+ """)
671
781
  try:
672
- await connection.execute(
673
- f"""
782
+ await connection.execute(f"""
674
783
  CREATE OR REPLACE VIEW {PG_READABLE_EVENTS_VIEW} AS
675
784
  SELECT
676
785
  event_row.namespace,
@@ -715,8 +824,7 @@ class PostgresSessionService(BaseSessionService):
715
824
  JOIN {KSADK_PG_SESSIONS_TABLE} AS session_row
716
825
  ON session_row.namespace = event_row.namespace
717
826
  AND session_row.id = event_row.session_id;
718
- """
719
- )
827
+ """)
720
828
  except Exception as exc:
721
829
  logger.warning("Postgres readable session view unavailable: %s", exc)
722
830
  self._schema_ready = True
@@ -727,6 +835,7 @@ class PostgresSessionService(BaseSessionService):
727
835
  session_id: str,
728
836
  *,
729
837
  for_update: bool = False,
838
+ include_events: bool = True,
730
839
  ) -> Optional[Session]:
731
840
  lock_clause = " FOR UPDATE" if for_update else ""
732
841
  row = await connection.fetchrow(
@@ -742,10 +851,16 @@ class PostgresSessionService(BaseSessionService):
742
851
  )
743
852
  if row is None:
744
853
  return None
745
- events = [] if for_update else await self._get_events_with_connection(connection, session_id)
854
+ events = (
855
+ await self._get_events_with_connection(connection, session_id)
856
+ if include_events and not for_update
857
+ else []
858
+ )
746
859
  return self._session_from_row(row, events=events)
747
860
 
748
- async def _get_events_with_connection(self, connection: Any, session_id: str) -> list[SessionEvent]:
861
+ async def _get_events_with_connection(
862
+ self, connection: Any, session_id: str
863
+ ) -> list[SessionEvent]:
749
864
  rows = await connection.fetch(
750
865
  f"""
751
866
  SELECT id, session_id, author, event_type, content_json, timestamp,
@@ -785,7 +900,8 @@ class PostgresSessionService(BaseSessionService):
785
900
  await connection.execute(
786
901
  f"""
787
902
  INSERT INTO {KSADK_PG_STATES_TABLE} (
788
- namespace, tenant_id, workspace_id, scope, agent_id, user_id, session_id, state_json, version, updated_at
903
+ namespace, tenant_id, workspace_id, scope, agent_id,
904
+ user_id, session_id, state_json, version, updated_at
789
905
  )
790
906
  VALUES ($1, $2, $3, 'session', $4, $5, $6, $7::jsonb, $8, $9)
791
907
  ON CONFLICT (namespace, scope, agent_id, user_id, session_id)
@@ -888,7 +1004,9 @@ def mask_postgres_session_dsn(dsn: str) -> str:
888
1004
  host = parts.hostname or ""
889
1005
  port = f":{parts.port}" if parts.port else ""
890
1006
  auth = f"{username}:***@" if username else "***@"
891
- return urlunsplit((parts.scheme, f"{auth}{host}{port}", parts.path, parts.query, parts.fragment))
1007
+ return urlunsplit(
1008
+ (parts.scheme, f"{auth}{host}{port}", parts.path, parts.query, parts.fragment)
1009
+ )
892
1010
 
893
1011
 
894
1012
  __all__ = [