agentengine-sdk-python 0.6.4__py3-none-any.whl → 0.7.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 (486) hide show
  1. agentengine_sdk_python-0.7.0.dist-info/METADATA +181 -0
  2. agentengine_sdk_python-0.7.0.dist-info/RECORD +482 -0
  3. {agentengine_sdk_python-0.6.4.dist-info → agentengine_sdk_python-0.7.0.dist-info}/WHEEL +1 -1
  4. agentengine_sdk_python-0.7.0.dist-info/entry_points.txt +3 -0
  5. agentengine_sdk_python-0.7.0.dist-info/licenses/LICENSE +175 -0
  6. agentengine_sdk_python-0.7.0.dist-info/top_level.txt +2 -0
  7. ksadk/__init__.py +13 -0
  8. ksadk/__main__.py +4 -0
  9. ksadk/a2a/__init__.py +15 -0
  10. ksadk/a2a/card_builder.py +64 -0
  11. ksadk/a2a/client.py +309 -0
  12. ksadk/a2a/executor.py +201 -0
  13. ksadk/a2a/server.py +79 -0
  14. ksadk/agents/__init__.py +20 -0
  15. ksadk/agents/base.py +370 -0
  16. ksadk/agents/context.py +38 -0
  17. ksadk/agents/event.py +35 -0
  18. ksadk/agents/loop_agent.py +71 -0
  19. ksadk/agents/parallel_agent.py +109 -0
  20. ksadk/agents/runner_adapter.py +24 -0
  21. ksadk/agents/sequential_agent.py +34 -0
  22. ksadk/api/__init__.py +3 -0
  23. ksadk/api/client.py +2246 -0
  24. ksadk/builders/__init__.py +20 -0
  25. ksadk/builders/base.py +66 -0
  26. ksadk/builders/code_builder.py +1990 -0
  27. ksadk/builders/container_builder.py +786 -0
  28. ksadk/builders/framework_requirements.py +59 -0
  29. ksadk/builders/ks3_uploader.py +389 -0
  30. ksadk/builders/mcp_builder.py +476 -0
  31. ksadk/builders/requirements_utils.py +75 -0
  32. ksadk/cli/__init__.py +531 -0
  33. ksadk/cli/__main__.py +4 -0
  34. ksadk/cli/agent_ref.py +204 -0
  35. ksadk/cli/cmd_a2a.py +167 -0
  36. ksadk/cli/cmd_agent.py +201 -0
  37. ksadk/cli/cmd_build.py +270 -0
  38. ksadk/cli/cmd_completion.py +304 -0
  39. ksadk/cli/cmd_config.py +758 -0
  40. ksadk/cli/cmd_create.py +2304 -0
  41. ksadk/cli/cmd_dashboard.py +900 -0
  42. ksadk/cli/cmd_deploy.py +704 -0
  43. ksadk/cli/cmd_destroy.py +345 -0
  44. ksadk/cli/cmd_files.py +1227 -0
  45. ksadk/cli/cmd_hermes.py +1263 -0
  46. ksadk/cli/cmd_invoke.py +1503 -0
  47. ksadk/cli/cmd_launch.py +564 -0
  48. ksadk/cli/cmd_mcp.py +1179 -0
  49. ksadk/cli/cmd_model.py +302 -0
  50. ksadk/cli/cmd_openclaw.py +3922 -0
  51. ksadk/cli/cmd_run.py +239 -0
  52. ksadk/cli/cmd_status.py +588 -0
  53. ksadk/cli/cmd_version.py +522 -0
  54. ksadk/cli/cmd_web.py +288 -0
  55. ksadk/cli/deploy_utils.py +87 -0
  56. ksadk/cli/dry_run.py +214 -0
  57. ksadk/cli/env_options.py +82 -0
  58. ksadk/cli/error_utils.py +525 -0
  59. ksadk/cli/global_options.py +31 -0
  60. ksadk/cli/local_runtime.py +97 -0
  61. ksadk/cli/model_catalog.py +136 -0
  62. ksadk/cli/network_options.py +412 -0
  63. ksadk/cli/resource_common.py +621 -0
  64. ksadk/cli/storage.py +84 -0
  65. ksadk/cli/ui.py +431 -0
  66. ksadk/cli/workflow_common.py +552 -0
  67. ksadk/common/__init__.py +14 -0
  68. ksadk/common/aicp_env.py +128 -0
  69. ksadk/common/auth.py +190 -0
  70. ksadk/common/constants.py +84 -0
  71. ksadk/common/llm_utils.py +61 -0
  72. ksadk/configs/__init__.py +61 -0
  73. ksadk/configs/env_registry.py +343 -0
  74. ksadk/configs/global_config.py +200 -0
  75. ksadk/configs/settings.py +706 -0
  76. ksadk/conversations/__init__.py +95 -0
  77. ksadk/conversations/attachment_storage.py +379 -0
  78. ksadk/conversations/attachments.py +774 -0
  79. ksadk/conversations/compaction_pipeline.py +387 -0
  80. ksadk/conversations/compaction_prompt.py +128 -0
  81. ksadk/conversations/context.py +303 -0
  82. ksadk/conversations/message_projection.py +269 -0
  83. ksadk/conversations/model_context.py +370 -0
  84. ksadk/conversations/model_options.py +136 -0
  85. ksadk/conversations/normalize.py +446 -0
  86. ksadk/conversations/reasoning_markup.py +91 -0
  87. ksadk/conversations/run_kinds.py +61 -0
  88. ksadk/conversations/run_status.py +53 -0
  89. ksadk/conversations/runtime.py +5276 -0
  90. ksadk/conversations/semantic_summary.py +359 -0
  91. ksadk/conversations/session_title.py +254 -0
  92. ksadk/deployment/__init__.py +83 -0
  93. ksadk/deployment/agent_access.py +226 -0
  94. ksadk/deployment/base.py +229 -0
  95. ksadk/deployment/manager.py +332 -0
  96. ksadk/deployment/providers/__init__.py +10 -0
  97. ksadk/deployment/providers/serverless.py +1115 -0
  98. ksadk/deployment/registry.py +120 -0
  99. ksadk/deployment/state.py +78 -0
  100. ksadk/deployment/ui_config.py +21 -0
  101. ksadk/detection/__init__.py +7 -0
  102. ksadk/detection/detector.py +431 -0
  103. ksadk/detection/mcp_detector.py +250 -0
  104. ksadk/hermes_terminal.py +467 -0
  105. ksadk/identity/__init__.py +17 -0
  106. ksadk/identity/resolver.py +385 -0
  107. ksadk/knowledge_base/__init__.py +62 -0
  108. ksadk/knowledge_base/adk_tool.py +47 -0
  109. ksadk/knowledge_base/client.py +297 -0
  110. ksadk/knowledge_base/langchain_tool.py +55 -0
  111. ksadk/knowledge_base/service.py +66 -0
  112. ksadk/knowledge_base/tool.py +50 -0
  113. ksadk/markdown.py +169 -0
  114. ksadk/mcp_runtime/__init__.py +231 -0
  115. ksadk/memory/__init__.py +57 -0
  116. ksadk/memory/adk/__init__.py +51 -0
  117. ksadk/memory/adk/backends/__init__.py +5 -0
  118. ksadk/memory/adk/backends/base_ltm_backend.py +52 -0
  119. ksadk/memory/adk/backends/http_ltm_backend.py +183 -0
  120. ksadk/memory/adk/backends/inmemory_ltm_backend.py +96 -0
  121. ksadk/memory/adk/backends/sdk_ltm_backend.py +456 -0
  122. ksadk/memory/adk/long_term_memory.py +273 -0
  123. ksadk/memory/adk/resilient_session_service.py +268 -0
  124. ksadk/memory/adk/short_term_memory.py +304 -0
  125. ksadk/memory/adk_tool.py +31 -0
  126. ksadk/memory/backends/__init__.py +6 -0
  127. ksadk/memory/backends/base.py +103 -0
  128. ksadk/memory/backends/memory.py +112 -0
  129. ksadk/memory/backends/redis.py +146 -0
  130. ksadk/memory/langchain_tool.py +39 -0
  131. ksadk/memory/ltm_backend_factory.py +24 -0
  132. ksadk/memory/manager.py +215 -0
  133. ksadk/memory/service.py +172 -0
  134. ksadk/memory/tool.py +96 -0
  135. ksadk/model_policy.py +223 -0
  136. ksadk/openclaw_gateway.py +378 -0
  137. ksadk/runners/__init__.py +8 -0
  138. ksadk/runners/adk_runner.py +1994 -0
  139. ksadk/runners/base_runner.py +305 -0
  140. ksadk/runners/deepagents_runner.py +13 -0
  141. ksadk/runners/factory.py +73 -0
  142. ksadk/runners/langchain_runner.py +751 -0
  143. ksadk/runners/langgraph_runner.py +985 -0
  144. ksadk/runners/patch_langchain.py +187 -0
  145. ksadk/runners/remote_runner.py +792 -0
  146. ksadk/runners/usage_accumulator.py +38 -0
  147. ksadk/runners/utils/__init__.py +19 -0
  148. ksadk/runners/utils/langfuse.py +230 -0
  149. ksadk/runners/utils/loader.py +62 -0
  150. ksadk/runtime_context.py +166 -0
  151. ksadk/runtime_state.py +25 -0
  152. ksadk/sandbox/__init__.py +28 -0
  153. ksadk/sandbox/backends/__init__.py +9 -0
  154. ksadk/sandbox/backends/e2b.py +154 -0
  155. ksadk/sandbox/backends/local_process.py +131 -0
  156. ksadk/sandbox/base.py +101 -0
  157. ksadk/sandbox/factory.py +53 -0
  158. ksadk/sandbox/registry.py +187 -0
  159. ksadk/server/__init__.py +7 -0
  160. ksadk/server/api_models.py +73 -0
  161. ksadk/server/app.py +3931 -0
  162. ksadk/server/static/assets/ArtifactsPanel-D-SSn2ee.js +1 -0
  163. ksadk/server/static/assets/CodeBlock-P16VOLYi.js +9 -0
  164. ksadk/server/static/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  165. ksadk/server/static/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  166. ksadk/server/static/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  167. ksadk/server/static/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  168. ksadk/server/static/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  169. ksadk/server/static/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  170. ksadk/server/static/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  171. ksadk/server/static/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  172. ksadk/server/static/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  173. ksadk/server/static/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  174. ksadk/server/static/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  175. ksadk/server/static/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  176. ksadk/server/static/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  177. ksadk/server/static/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  178. ksadk/server/static/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  179. ksadk/server/static/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  180. ksadk/server/static/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  181. ksadk/server/static/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  182. ksadk/server/static/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  183. ksadk/server/static/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  184. ksadk/server/static/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  185. ksadk/server/static/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  186. ksadk/server/static/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  187. ksadk/server/static/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  188. ksadk/server/static/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  189. ksadk/server/static/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  190. ksadk/server/static/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  191. ksadk/server/static/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  192. ksadk/server/static/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  193. ksadk/server/static/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  194. ksadk/server/static/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  195. ksadk/server/static/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  196. ksadk/server/static/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  197. ksadk/server/static/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  198. ksadk/server/static/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  199. ksadk/server/static/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  200. ksadk/server/static/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  201. ksadk/server/static/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  202. ksadk/server/static/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  203. ksadk/server/static/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  204. ksadk/server/static/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  205. ksadk/server/static/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  206. ksadk/server/static/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  207. ksadk/server/static/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  208. ksadk/server/static/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  209. ksadk/server/static/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  210. ksadk/server/static/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  211. ksadk/server/static/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  212. ksadk/server/static/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  213. ksadk/server/static/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  214. ksadk/server/static/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  215. ksadk/server/static/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  216. ksadk/server/static/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  217. ksadk/server/static/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  218. ksadk/server/static/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  219. ksadk/server/static/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  220. ksadk/server/static/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  221. ksadk/server/static/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  222. ksadk/server/static/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  223. ksadk/server/static/assets/MathMessageMarkdown-CdGiQWHR.js +8 -0
  224. ksadk/server/static/assets/MathMessageMarkdown-DeYh8QPr.css +1 -0
  225. ksadk/server/static/assets/MermaidBlock-IOcal8cm.js +303 -0
  226. ksadk/server/static/assets/NativeTerminalPanel-CHOd7Rch.css +1 -0
  227. ksadk/server/static/assets/NativeTerminalPanel-DGSDWsei.js +1 -0
  228. ksadk/server/static/assets/addon-fit-DthTIhi3.js +1 -0
  229. ksadk/server/static/assets/apl-CnwPGSsG.js +1 -0
  230. ksadk/server/static/assets/arc-BA13sHc9.js +1 -0
  231. ksadk/server/static/assets/architecture-7EHR7CIX-BvUlsA6l.js +1 -0
  232. ksadk/server/static/assets/architectureDiagram-3BPJPVTR-DzJzgVoL.js +36 -0
  233. ksadk/server/static/assets/asciiarmor-qTkVPQu6.js +1 -0
  234. ksadk/server/static/assets/asn1-Dr8qZg38.js +1 -0
  235. ksadk/server/static/assets/asterisk-Bja0s6e1.js +1 -0
  236. ksadk/server/static/assets/blockDiagram-GPEHLZMM-UTdVcZhn.js +132 -0
  237. ksadk/server/static/assets/brainfuck-D5EjA2JK.js +1 -0
  238. ksadk/server/static/assets/c4Diagram-AAUBKEIU-Dix0GD4m.js +10 -0
  239. ksadk/server/static/assets/channel-CTuydARX.js +1 -0
  240. ksadk/server/static/assets/chunk-2J33WTMH-C2JxuZ42.js +1 -0
  241. ksadk/server/static/assets/chunk-4BX2VUAB-Be57QPgD.js +1 -0
  242. ksadk/server/static/assets/chunk-55IACEB6-WjSuy4nv.js +1 -0
  243. ksadk/server/static/assets/chunk-727SXJPM-BOovP-b5.js +206 -0
  244. ksadk/server/static/assets/chunk-AQP2D5EJ-DOmZNmWj.js +231 -0
  245. ksadk/server/static/assets/chunk-FMBD7UC4-DzwlodkU.js +15 -0
  246. ksadk/server/static/assets/chunk-ND2GUHAM-DMqAikEU.js +1 -0
  247. ksadk/server/static/assets/chunk-QZHKN3VN-BnCydivS.js +1 -0
  248. ksadk/server/static/assets/classDiagram-4FO5ZUOK-BNHg45Be.js +1 -0
  249. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-BNHg45Be.js +1 -0
  250. ksadk/server/static/assets/clike-DHH8Ad3s.js +1 -0
  251. ksadk/server/static/assets/clojure-BflJGmDX.js +1 -0
  252. ksadk/server/static/assets/cmake-CyVbuzPu.js +1 -0
  253. ksadk/server/static/assets/cobol-B_OZ4V-R.js +1 -0
  254. ksadk/server/static/assets/coffeescript-B2pKbFk8.js +1 -0
  255. ksadk/server/static/assets/commonlisp-CcllspGY.js +1 -0
  256. ksadk/server/static/assets/cose-bilkent-S5V4N54A-Zhy2GBnP.js +1 -0
  257. ksadk/server/static/assets/crystal-M5-qzICs.js +1 -0
  258. ksadk/server/static/assets/css-CYpP4FRV.js +1 -0
  259. ksadk/server/static/assets/cypher-p9eYesGn.js +1 -0
  260. ksadk/server/static/assets/cytoscape.esm-DelgaX4f.js +321 -0
  261. ksadk/server/static/assets/d-BhMjBjQP.js +1 -0
  262. ksadk/server/static/assets/dagre-BM42HDAG-CbKrtIUz.js +4 -0
  263. ksadk/server/static/assets/dagre-Bx709z4p.js +1 -0
  264. ksadk/server/static/assets/defaultLocale-C8Fc0cco.js +1 -0
  265. ksadk/server/static/assets/diagram-2AECGRRQ-BRApgQRK.js +43 -0
  266. ksadk/server/static/assets/diagram-5GNKFQAL-D0xbnDiK.js +10 -0
  267. ksadk/server/static/assets/diagram-KO2AKTUF-CVugVI9L.js +3 -0
  268. ksadk/server/static/assets/diagram-LMA3HP47-DozUGgee.js +24 -0
  269. ksadk/server/static/assets/diagram-OG6HWLK6-ZOYsKlru.js +24 -0
  270. ksadk/server/static/assets/diff-ChtP43wD.js +1 -0
  271. ksadk/server/static/assets/dist-2hInLS_J.js +9 -0
  272. ksadk/server/static/assets/dist-8EEyGgDx.js +1 -0
  273. ksadk/server/static/assets/dist-8_SfK1IP.js +1 -0
  274. ksadk/server/static/assets/dist-B0NP_Z0z.js +23 -0
  275. ksadk/server/static/assets/dist-BIJVDMuB.js +1 -0
  276. ksadk/server/static/assets/dist-BmlMPsCc.js +2 -0
  277. ksadk/server/static/assets/dist-BrCcQ47T.js +1 -0
  278. ksadk/server/static/assets/dist-BssVmjIo.js +6 -0
  279. ksadk/server/static/assets/dist-C3HIIaN5.js +1 -0
  280. ksadk/server/static/assets/dist-CPBtqRTW.js +1 -0
  281. ksadk/server/static/assets/dist-CkEKJFtk.js +1 -0
  282. ksadk/server/static/assets/dist-D-JMdWPQ.js +1 -0
  283. ksadk/server/static/assets/dist-D-xOD048.js +1 -0
  284. ksadk/server/static/assets/dist-D57wnGWd.js +1 -0
  285. ksadk/server/static/assets/dist-DL_NKc_z.js +1 -0
  286. ksadk/server/static/assets/dist-DMezvBGJ.js +1 -0
  287. ksadk/server/static/assets/dist-DmFaq_Iy.js +1 -0
  288. ksadk/server/static/assets/dist-Dp0k7bWI.js +1 -0
  289. ksadk/server/static/assets/dist-DpKtt4Bo.js +1 -0
  290. ksadk/server/static/assets/dist-DyOkZmze.js +11 -0
  291. ksadk/server/static/assets/dist-DyWsb78Q.js +1 -0
  292. ksadk/server/static/assets/dist-gX6GOLKq.js +1 -0
  293. ksadk/server/static/assets/dockerfile-BLkNEvjs.js +1 -0
  294. ksadk/server/static/assets/dtd-DTF72YNO.js +1 -0
  295. ksadk/server/static/assets/dylan-C6jEEEk-.js +1 -0
  296. ksadk/server/static/assets/ebnf-D4c0_ac3.js +1 -0
  297. ksadk/server/static/assets/ecl-BSZaIHnp.js +1 -0
  298. ksadk/server/static/assets/eiffel-BEjRio4Q.js +1 -0
  299. ksadk/server/static/assets/elm-Cshzl8qu.js +1 -0
  300. ksadk/server/static/assets/erDiagram-TEJ5UH35-Bk-9bgE5.js +85 -0
  301. ksadk/server/static/assets/erlang-DaB2Rkuy.js +1 -0
  302. ksadk/server/static/assets/eventmodeling-FCH6USID-DsAgWnlf.js +1 -0
  303. ksadk/server/static/assets/factor-D7LVTn2l.js +1 -0
  304. ksadk/server/static/assets/fcl-ClOhbFR7.js +1 -0
  305. ksadk/server/static/assets/flowDiagram-I6XJVG4X-Dn9kZVuZ.js +162 -0
  306. ksadk/server/static/assets/forth-Cezjo90N.js +1 -0
  307. ksadk/server/static/assets/fortran-Bt6PBEDR.js +1 -0
  308. ksadk/server/static/assets/ganttDiagram-6RSMTGT7-BGxXlJqm.js +292 -0
  309. ksadk/server/static/assets/gas-BHEdbvp9.js +1 -0
  310. ksadk/server/static/assets/gherkin-oBAE_ms0.js +1 -0
  311. ksadk/server/static/assets/gitGraph-WXDBUCRP-BIao9Yjg.js +1 -0
  312. ksadk/server/static/assets/gitGraphDiagram-PVQCEYII-C7Q0X-wi.js +106 -0
  313. ksadk/server/static/assets/graphlib-B8gBHxth.js +1 -0
  314. ksadk/server/static/assets/groovy-BC3IOsC8.js +1 -0
  315. ksadk/server/static/assets/haskell-BRsoo5mP.js +1 -0
  316. ksadk/server/static/assets/haxe-DIz0ZZqd.js +1 -0
  317. ksadk/server/static/assets/http-CLVgA2GD.js +1 -0
  318. ksadk/server/static/assets/idl-BUZw3wgd.js +1 -0
  319. ksadk/server/static/assets/index-C00Lwg3L.js +165 -0
  320. ksadk/server/static/assets/index-DAURbCsP.css +1 -0
  321. ksadk/server/static/assets/info-J43DQDTF-CyipqGxU.js +1 -0
  322. ksadk/server/static/assets/infoDiagram-5YYISTIA-BO_CSqq5.js +2 -0
  323. ksadk/server/static/assets/init-D6jRqBbL.js +1 -0
  324. ksadk/server/static/assets/ishikawaDiagram-YF4QCWOH-eYLPLd46.js +70 -0
  325. ksadk/server/static/assets/javascript-9Tg8ixDm.js +1 -0
  326. ksadk/server/static/assets/journeyDiagram-JHISSGLW-De9geSb0.js +139 -0
  327. ksadk/server/static/assets/julia-CQfgDRfP.js +1 -0
  328. ksadk/server/static/assets/kanban-definition-UN3LZRKU-Cs80kQto.js +89 -0
  329. ksadk/server/static/assets/katex-DSrCFD8n.js +265 -0
  330. ksadk/server/static/assets/linear-CN9sbKTF.js +1 -0
  331. ksadk/server/static/assets/livescript-BXxG0Yva.js +1 -0
  332. ksadk/server/static/assets/lua-CiA1ziua.js +1 -0
  333. ksadk/server/static/assets/mathematica-u8YMmbU0.js +1 -0
  334. ksadk/server/static/assets/mbox-BEMVcqjs.js +1 -0
  335. ksadk/server/static/assets/mermaid-parser.core-DlgSBU8l.js +161 -0
  336. ksadk/server/static/assets/mindmap-definition-RKZ34NQL-9afz7Oug.js +96 -0
  337. ksadk/server/static/assets/mirc-C9zpzAZU.js +1 -0
  338. ksadk/server/static/assets/mllike-B45xgp2S.js +1 -0
  339. ksadk/server/static/assets/modelica-CqHI_q-D.js +1 -0
  340. ksadk/server/static/assets/mscgen-qgSLujhx.js +1 -0
  341. ksadk/server/static/assets/mumps-CW_TBmxz.js +1 -0
  342. ksadk/server/static/assets/nginx-BMaDbqW3.js +1 -0
  343. ksadk/server/static/assets/nsis-AQ_alPln.js +1 -0
  344. ksadk/server/static/assets/ntriples-d28e9m0E.js +1 -0
  345. ksadk/server/static/assets/octave-D2Q8cUp1.js +1 -0
  346. ksadk/server/static/assets/ordinal-hYBb2elL.js +1 -0
  347. ksadk/server/static/assets/oz-BwTct_5T.js +1 -0
  348. ksadk/server/static/assets/packet-YPE3B663-CGkyRxlg.js +1 -0
  349. ksadk/server/static/assets/pascal-Dp_KdFgX.js +1 -0
  350. ksadk/server/static/assets/perl-CdEHsPfU.js +1 -0
  351. ksadk/server/static/assets/pie-LRSECV5Y-M0uWAf4n.js +1 -0
  352. ksadk/server/static/assets/pieDiagram-4H26LBE5-DPv_VstN.js +30 -0
  353. ksadk/server/static/assets/pig-AF4Hwhju.js +1 -0
  354. ksadk/server/static/assets/powershell-CzG71I4L.js +1 -0
  355. ksadk/server/static/assets/properties-C357ku5U.js +1 -0
  356. ksadk/server/static/assets/protobuf-D1ij_kNL.js +1 -0
  357. ksadk/server/static/assets/pug-Bugr-47h.js +1 -0
  358. ksadk/server/static/assets/puppet-B4hC2X4m.js +1 -0
  359. ksadk/server/static/assets/python-BqYw9LYJ.js +1 -0
  360. ksadk/server/static/assets/q-B9NhS7L_.js +1 -0
  361. ksadk/server/static/assets/quadrantDiagram-W4KKPZXB-o77wZ1XK.js +7 -0
  362. ksadk/server/static/assets/r-DADKenSm.js +1 -0
  363. ksadk/server/static/assets/radar-GUYGQ44K-Bdbm24-x.js +1 -0
  364. ksadk/server/static/assets/requirementDiagram-4Y6WPE33-BYVw81VC.js +84 -0
  365. ksadk/server/static/assets/rpm-gpDK5sbt.js +1 -0
  366. ksadk/server/static/assets/ruby-DsYpTuWg.js +1 -0
  367. ksadk/server/static/assets/sankeyDiagram-5OEKKPKP-B7nZFMKT.js +40 -0
  368. ksadk/server/static/assets/sas-C2OyD2Y6.js +1 -0
  369. ksadk/server/static/assets/scheme-CyDdOh7e.js +1 -0
  370. ksadk/server/static/assets/sequenceDiagram-3UESZ5HK-BGRRrFw5.js +162 -0
  371. ksadk/server/static/assets/shell-Du5Qg9im.js +1 -0
  372. ksadk/server/static/assets/sieve-BAxa3IjF.js +1 -0
  373. ksadk/server/static/assets/simple-mode-DRpGK0lJ.js +1 -0
  374. ksadk/server/static/assets/smalltalk-BLp5-jwC.js +1 -0
  375. ksadk/server/static/assets/solr-BBopId9w.js +1 -0
  376. ksadk/server/static/assets/sparql-Dz-mlCAC.js +1 -0
  377. ksadk/server/static/assets/spreadsheet-CTIncYxj.js +1 -0
  378. ksadk/server/static/assets/sql-DcCJ9jop.js +1 -0
  379. ksadk/server/static/assets/stateDiagram-AJRCARHV-BUfHCoPs.js +1 -0
  380. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-8xBN_gLM.js +1 -0
  381. ksadk/server/static/assets/stex-sDrdk2BW.js +1 -0
  382. ksadk/server/static/assets/stylus-DLLZ8dgm.js +1 -0
  383. ksadk/server/static/assets/swift-DKB6_1j6.js +1 -0
  384. ksadk/server/static/assets/tcl-BGfruO1u.js +1 -0
  385. ksadk/server/static/assets/textile-DWBqthVk.js +1 -0
  386. ksadk/server/static/assets/tiddlywiki-VlUiK86J.js +1 -0
  387. ksadk/server/static/assets/tiki-CxVlf5KZ.js +1 -0
  388. ksadk/server/static/assets/timeline-definition-PNZ67QCA-FbCTGrf9.js +120 -0
  389. ksadk/server/static/assets/toml-LvoKBwCs.js +1 -0
  390. ksadk/server/static/assets/treeView-BLDUP644-npMo0ak1.js +1 -0
  391. ksadk/server/static/assets/treemap-LRROVOQU-CHdzrrdo.js +1 -0
  392. ksadk/server/static/assets/troff-C2dAgh7P.js +1 -0
  393. ksadk/server/static/assets/ttcn-BePYh-hG.js +1 -0
  394. ksadk/server/static/assets/ttcn-cfg-CY0aot7Q.js +1 -0
  395. ksadk/server/static/assets/turtle-BDLWE2cD.js +1 -0
  396. ksadk/server/static/assets/vb-BthdM_4N.js +1 -0
  397. ksadk/server/static/assets/vbscript-D9f6rSsU.js +1 -0
  398. ksadk/server/static/assets/velocity-CqftRsjg.js +1 -0
  399. ksadk/server/static/assets/vennDiagram-CIIHVFJN-DWgwtPsJ.js +34 -0
  400. ksadk/server/static/assets/verilog-D-x6ne0Z.js +1 -0
  401. ksadk/server/static/assets/vhdl-CMrOq2q1.js +1 -0
  402. ksadk/server/static/assets/wardley-L42UT6IY-BEQz7wyy.js +1 -0
  403. ksadk/server/static/assets/wardleyDiagram-YWT4CUSO-2x8G-tTM.js +78 -0
  404. ksadk/server/static/assets/webidl-D5jiJvOU.js +1 -0
  405. ksadk/server/static/assets/xquery-fj_R-kMw.js +1 -0
  406. ksadk/server/static/assets/xterm-DooSxjI5.js +36 -0
  407. ksadk/server/static/assets/xychartDiagram-2RQKCTM6-Drma3AYl.js +7 -0
  408. ksadk/server/static/assets/yacas-CXXgtw0p.js +1 -0
  409. ksadk/server/static/assets/z80-CL1naaMV.js +1 -0
  410. ksadk/server/static/favicon.svg +1 -0
  411. ksadk/server/static/icons.svg +24 -0
  412. ksadk/server/static/index.html +14 -0
  413. ksadk/server/terminal_sessions.py +551 -0
  414. ksadk/sessions/__init__.py +279 -0
  415. ksadk/sessions/base.py +354 -0
  416. ksadk/sessions/continuity.py +337 -0
  417. ksadk/sessions/errors.py +7 -0
  418. ksadk/sessions/in_memory.py +273 -0
  419. ksadk/sessions/local_service.py +949 -0
  420. ksadk/sessions/postgres_service.py +901 -0
  421. ksadk/sessions/resilience.py +52 -0
  422. ksadk/sessions/resilient.py +360 -0
  423. ksadk/sessions/sqlite_service.py +13 -0
  424. ksadk/skills/__init__.py +9 -0
  425. ksadk/skills/loader.py +46 -0
  426. ksadk/skills/models.py +120 -0
  427. ksadk/skills/package_store.py +104 -0
  428. ksadk/skills/runtime/__init__.py +17 -0
  429. ksadk/skills/runtime/agent.py +183 -0
  430. ksadk/skills/runtime/artifacts.py +39 -0
  431. ksadk/skills/runtime/backends/__init__.py +1 -0
  432. ksadk/skills/runtime/backends/disabled.py +8 -0
  433. ksadk/skills/runtime/backends/e2b.py +168 -0
  434. ksadk/skills/runtime/backends/local.py +95 -0
  435. ksadk/skills/runtime/base.py +103 -0
  436. ksadk/skills/runtime/executor.py +219 -0
  437. ksadk/skills/runtime/factory.py +37 -0
  438. ksadk/skills/runtime/loader.py +131 -0
  439. ksadk/skills/runtime/registry.py +150 -0
  440. ksadk/skills/runtime/request.py +67 -0
  441. ksadk/skills/service_client.py +239 -0
  442. ksadk/skills/service_env.py +58 -0
  443. ksadk/skills/tool_defs.py +221 -0
  444. ksadk/terminal_client.py +69 -0
  445. ksadk/terminal_exec_policy.py +229 -0
  446. ksadk/tools/__init__.py +17 -0
  447. ksadk/tools/gateway.py +230 -0
  448. ksadk/tools/result_budget.py +154 -0
  449. ksadk/toolsets/__init__.py +854 -0
  450. ksadk/toolsets/_langchain.py +11 -0
  451. ksadk/toolsets/platform.py +93 -0
  452. ksadk/toolsets/sandbox.py +310 -0
  453. ksadk/toolsets/skills.py +217 -0
  454. ksadk/toolsets/web.py +266 -0
  455. ksadk/toolsets/workspace.py +917 -0
  456. ksadk/toolsets/workspace_state.py +44 -0
  457. ksadk/tracing/__init__.py +37 -0
  458. ksadk/tracing/exporters/__init__.py +1 -0
  459. ksadk/tracing/exporters/inmemory_exporter.py +116 -0
  460. ksadk/tracing/exporters/langfuse_exporter.py +445 -0
  461. ksadk/tracing/setup.py +892 -0
  462. ksadk/tracing/span_utils.py +114 -0
  463. ksadk/tui/__init__.py +27 -0
  464. ksadk/tui/loop.py +1877 -0
  465. ksadk/tui/stream_render.py +68 -0
  466. ksadk/ui_config.py +168 -0
  467. ksadk/version.py +4 -0
  468. ksadk_runtime_common/__init__.py +20 -0
  469. ksadk_runtime_common/memory_backend/__init__.py +29 -0
  470. ksadk_runtime_common/memory_backend/manifest.py +79 -0
  471. ksadk_runtime_common/memory_backend/providers/__init__.py +6 -0
  472. ksadk_runtime_common/memory_backend/providers/lancedb.py +151 -0
  473. ksadk_runtime_common/memory_backend/providers/mem0.py +74 -0
  474. ksadk_runtime_common/memory_backend/registry.py +56 -0
  475. ksadk_runtime_common/memory_backend/render.py +71 -0
  476. ksadk_runtime_common/schemas/memory_backend_manifest.schema.json +148 -0
  477. ksadk_runtime_common/workspace_files/__init__.py +29 -0
  478. ksadk_runtime_common/workspace_files/bootstrap.py +56 -0
  479. ksadk_runtime_common/workspace_files/constants.py +9 -0
  480. ksadk_runtime_common/workspace_files/path_utils.py +71 -0
  481. ksadk_runtime_common/workspace_files/preview.py +96 -0
  482. ksadk_runtime_common/workspace_files/router.py +254 -0
  483. agentengine_sdk_python/__init__.py +0 -3
  484. agentengine_sdk_python-0.6.4.dist-info/METADATA +0 -48
  485. agentengine_sdk_python-0.6.4.dist-info/RECORD +0 -5
  486. agentengine_sdk_python-0.6.4.dist-info/top_level.txt +0 -1
@@ -0,0 +1,901 @@
1
+ """PostgreSQL shared session backend for production multi-pod runtimes."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ import json
7
+ import logging
8
+ import time
9
+ from typing import Any, Optional
10
+ from urllib.parse import urlsplit, urlunsplit
11
+
12
+ from ksadk.sessions.base import (
13
+ BaseSessionService,
14
+ Session,
15
+ SessionEvent,
16
+ SessionState,
17
+ generate_id,
18
+ )
19
+ from ksadk.sessions.errors import SessionBackendUnavailable
20
+
21
+ KSADK_PG_SESSIONS_TABLE = "ksadk_sessions"
22
+ KSADK_PG_EVENTS_TABLE = "ksadk_events"
23
+ KSADK_PG_STATES_TABLE = "ksadk_states"
24
+ PG_READABLE_EVENTS_VIEW = "ksadk_session_events_readable"
25
+
26
+ logger = logging.getLogger(__name__)
27
+
28
+
29
+ class PostgresSessionService(BaseSessionService):
30
+ def __init__(
31
+ self,
32
+ *,
33
+ dsn: str,
34
+ namespace: str = "default",
35
+ tenant_id: str = "default",
36
+ workspace_id: str = "default",
37
+ min_size: int = 1,
38
+ max_size: int = 10,
39
+ connect_timeout: float = 5.0,
40
+ ):
41
+ if not dsn.strip():
42
+ raise ValueError("KSADK_SESSION_DSN is required when KSADK_SESSION_BACKEND=postgres")
43
+ self.dsn = dsn.strip()
44
+ self.namespace = namespace.strip() or "default"
45
+ self.tenant_id = tenant_id.strip() or "default"
46
+ self.workspace_id = workspace_id.strip() or "default"
47
+ self.min_size = min_size
48
+ self.max_size = max_size
49
+ self.connect_timeout = connect_timeout
50
+ self._pool: Any = None
51
+ self._pool_lock = asyncio.Lock()
52
+ self._schema_ready = False
53
+ self._schema_lock = asyncio.Lock()
54
+
55
+ async def create_session(
56
+ self,
57
+ agent_id: str,
58
+ user_id: str,
59
+ session_id: Optional[str] = None,
60
+ ) -> Session:
61
+ await self._ensure_schema()
62
+ session_key = session_id or generate_id()
63
+ async with self._pool.acquire() as connection:
64
+ async with connection.transaction():
65
+ existing = await self._get_session_with_connection(connection, session_key)
66
+ if existing is not None:
67
+ return existing
68
+
69
+ now = time.time()
70
+ await connection.execute(
71
+ f"""
72
+ 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
75
+ )
76
+ VALUES ($1, $2, $3, $4, $5, $6, '', '', '', '', '', $7::jsonb, $8, $9, 0)
77
+ ON CONFLICT (namespace, id) DO NOTHING
78
+ """,
79
+ self.namespace,
80
+ self.tenant_id,
81
+ self.workspace_id,
82
+ session_key,
83
+ agent_id,
84
+ user_id,
85
+ "{}",
86
+ now,
87
+ now,
88
+ )
89
+ persisted = await self._get_session_with_connection(
90
+ connection,
91
+ session_key,
92
+ for_update=True,
93
+ )
94
+ if persisted is None:
95
+ raise RuntimeError(f"Failed to create Postgres session {session_key}")
96
+ await connection.execute(
97
+ f"""
98
+ INSERT INTO {KSADK_PG_STATES_TABLE} (
99
+ namespace, tenant_id, workspace_id, scope, agent_id, user_id, session_id, state_json, version, updated_at
100
+ )
101
+ VALUES ($1, $2, $3, 'session', $4, $5, $6, $7::jsonb, 0, $8)
102
+ ON CONFLICT (namespace, scope, agent_id, user_id, session_id)
103
+ DO NOTHING
104
+ """,
105
+ self.namespace,
106
+ self.tenant_id,
107
+ self.workspace_id,
108
+ persisted.agent_id,
109
+ persisted.user_id,
110
+ session_key,
111
+ "{}",
112
+ now,
113
+ )
114
+ return persisted
115
+
116
+ async def get_session(self, session_id: str) -> Optional[Session]:
117
+ await self._ensure_schema()
118
+ async with self._pool.acquire() as connection:
119
+ return await self._get_session_with_connection(connection, session_id)
120
+
121
+ async def list_sessions(
122
+ self,
123
+ agent_id: str,
124
+ user_id: Optional[str] = None,
125
+ offset: Optional[int] = None,
126
+ limit: Optional[int] = None,
127
+ ) -> list[Session]:
128
+ await self._ensure_schema()
129
+ async with self._pool.acquire() as connection:
130
+ query = f"""
131
+ SELECT id, agent_id, user_id, title, title_source, summary, first_prompt, last_prompt,
132
+ state_json, created_at, updated_at, version
133
+ FROM {KSADK_PG_SESSIONS_TABLE}
134
+ WHERE namespace = $1 AND agent_id = $2
135
+ """
136
+ params: list[Any] = [self.namespace, agent_id]
137
+ if user_id is not None:
138
+ params.append(user_id)
139
+ query += f" AND user_id = ${len(params)}"
140
+ query += " ORDER BY updated_at DESC, created_at DESC"
141
+ if limit is not None:
142
+ params.append(limit)
143
+ query += f" LIMIT ${len(params)}"
144
+ if offset is not None:
145
+ params.append(offset)
146
+ query += f" OFFSET ${len(params)}"
147
+ elif offset is not None:
148
+ params.append(offset)
149
+ query += f" OFFSET ${len(params)}"
150
+ rows = await connection.fetch(query, *params)
151
+ return [self._session_from_row(row, events=[]) for row in rows]
152
+
153
+ async def count_sessions(
154
+ self,
155
+ agent_id: str,
156
+ user_id: Optional[str] = None,
157
+ ) -> int:
158
+ await self._ensure_schema()
159
+ async with self._pool.acquire() as connection:
160
+ query = f"""
161
+ SELECT COUNT(*) AS total
162
+ FROM {KSADK_PG_SESSIONS_TABLE}
163
+ WHERE namespace = $1 AND agent_id = $2
164
+ """
165
+ params: list[Any] = [self.namespace, agent_id]
166
+ if user_id is not None:
167
+ params.append(user_id)
168
+ query += f" AND user_id = ${len(params)}"
169
+ return int(await connection.fetchval(query, *params) or 0)
170
+
171
+ async def delete_session(self, session_id: str) -> bool:
172
+ await self._ensure_schema()
173
+ async with self._pool.acquire() as connection:
174
+ async with connection.transaction():
175
+ await connection.execute(
176
+ f"""
177
+ DELETE FROM {KSADK_PG_STATES_TABLE}
178
+ WHERE namespace = $1 AND session_id = $2
179
+ """,
180
+ self.namespace,
181
+ session_id,
182
+ )
183
+ result = await connection.execute(
184
+ f"""
185
+ DELETE FROM {KSADK_PG_SESSIONS_TABLE}
186
+ WHERE namespace = $1 AND id = $2
187
+ """,
188
+ self.namespace,
189
+ session_id,
190
+ )
191
+ return not result.endswith(" 0")
192
+
193
+ async def update_session_metadata(
194
+ self,
195
+ session_id: str,
196
+ *,
197
+ title: Optional[str] = None,
198
+ title_source: Optional[str] = None,
199
+ summary: Optional[str] = None,
200
+ first_prompt: Optional[str] = None,
201
+ last_prompt: Optional[str] = None,
202
+ ) -> Session:
203
+ await self._ensure_schema()
204
+ async with self._pool.acquire() as connection:
205
+ async with connection.transaction():
206
+ row = await connection.fetchrow(
207
+ f"""
208
+ SELECT id, agent_id, user_id, title, title_source, summary, first_prompt, last_prompt,
209
+ state_json, created_at, updated_at, version
210
+ FROM {KSADK_PG_SESSIONS_TABLE}
211
+ WHERE namespace = $1 AND id = $2
212
+ FOR UPDATE
213
+ """,
214
+ self.namespace,
215
+ session_id,
216
+ )
217
+ if row is None:
218
+ raise ValueError(f"Session {session_id} not found")
219
+ updated_at = time.time()
220
+ next_title = row["title"] if title is None else title
221
+ next_title_source = row["title_source"] if title_source is None else title_source
222
+ next_summary = row["summary"] if summary is None else summary
223
+ next_first_prompt = row["first_prompt"] if first_prompt is None else first_prompt
224
+ next_last_prompt = row["last_prompt"] if last_prompt is None else last_prompt
225
+ await connection.execute(
226
+ f"""
227
+ UPDATE {KSADK_PG_SESSIONS_TABLE}
228
+ SET title = $1, title_source = $2, summary = $3, first_prompt = $4,
229
+ last_prompt = $5, updated_at = $6
230
+ WHERE namespace = $7 AND id = $8
231
+ """,
232
+ next_title,
233
+ next_title_source,
234
+ next_summary,
235
+ next_first_prompt,
236
+ next_last_prompt,
237
+ updated_at,
238
+ self.namespace,
239
+ session_id,
240
+ )
241
+ return Session(
242
+ id=row["id"],
243
+ agent_id=row["agent_id"],
244
+ user_id=row["user_id"],
245
+ title=next_title,
246
+ title_source=next_title_source,
247
+ summary=next_summary,
248
+ first_prompt=next_first_prompt,
249
+ last_prompt=next_last_prompt,
250
+ state=self._json_to_dict(row["state_json"]),
251
+ created_at=row["created_at"],
252
+ updated_at=updated_at,
253
+ version=row["version"],
254
+ )
255
+
256
+ async def append_event(self, session_id: str, event: SessionEvent) -> SessionEvent:
257
+ await self._ensure_schema()
258
+ async with self._pool.acquire() as connection:
259
+ async with connection.transaction():
260
+ session_row = await connection.fetchrow(
261
+ f"""
262
+ SELECT agent_id, user_id, state_json, version
263
+ FROM {KSADK_PG_SESSIONS_TABLE}
264
+ WHERE namespace = $1 AND id = $2
265
+ FOR UPDATE
266
+ """,
267
+ self.namespace,
268
+ session_id,
269
+ )
270
+ if session_row is None:
271
+ raise ValueError(f"Session {session_id} not found")
272
+
273
+ next_seq = await connection.fetchval(
274
+ f"""
275
+ SELECT COALESCE(MAX(seq_id), 0) + 1
276
+ FROM {KSADK_PG_EVENTS_TABLE}
277
+ WHERE namespace = $1 AND session_id = $2
278
+ """,
279
+ self.namespace,
280
+ session_id,
281
+ )
282
+ stored = SessionEvent(
283
+ id=event.id or generate_id(),
284
+ session_id=session_id,
285
+ author=event.author,
286
+ event_type=event.event_type,
287
+ content=dict(event.content),
288
+ timestamp=event.timestamp,
289
+ state_delta=dict(event.state_delta),
290
+ seq_id=int(next_seq or 1),
291
+ invocation_id=event.invocation_id,
292
+ metadata=dict(event.metadata),
293
+ )
294
+ await connection.execute(
295
+ f"""
296
+ INSERT INTO {KSADK_PG_EVENTS_TABLE} (
297
+ namespace, tenant_id, workspace_id, id, session_id, author, event_type, content_json, timestamp,
298
+ state_delta_json, seq_id, invocation_id, metadata_json
299
+ )
300
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8::jsonb, $9, $10::jsonb, $11, $12, $13::jsonb)
301
+ """,
302
+ self.namespace,
303
+ self.tenant_id,
304
+ self.workspace_id,
305
+ stored.id,
306
+ stored.session_id,
307
+ stored.author,
308
+ stored.event_type,
309
+ json.dumps(stored.content),
310
+ stored.timestamp,
311
+ json.dumps(stored.state_delta),
312
+ stored.seq_id,
313
+ stored.invocation_id,
314
+ json.dumps(stored.metadata),
315
+ )
316
+
317
+ updated_at = time.time()
318
+ state = self._json_to_dict(session_row["state_json"])
319
+ version = int(session_row["version"] or 0)
320
+ if stored.state_delta:
321
+ state.update(stored.state_delta)
322
+ version += 1
323
+ await self._write_session_state(
324
+ connection,
325
+ session_id=session_id,
326
+ agent_id=session_row["agent_id"],
327
+ user_id=session_row["user_id"],
328
+ state=state,
329
+ version=version,
330
+ updated_at=updated_at,
331
+ )
332
+ return stored
333
+
334
+ async def get_events(
335
+ self,
336
+ session_id: str,
337
+ offset: Optional[int] = None,
338
+ limit: Optional[int] = None,
339
+ after_seq_id: Optional[int] = None,
340
+ before_seq_id: Optional[int] = None,
341
+ ) -> list[SessionEvent]:
342
+ await self._ensure_schema()
343
+ # seq 过滤先应用,再对结果集应用"最新 N 条" offset/limit 语义。
344
+ conditions = ["namespace = $1", "session_id = $2"]
345
+ params: list[Any] = [self.namespace, session_id]
346
+ if after_seq_id is not None:
347
+ params.append(after_seq_id)
348
+ conditions.append(f"seq_id > ${len(params)}")
349
+ if before_seq_id is not None:
350
+ params.append(before_seq_id)
351
+ conditions.append(f"seq_id < ${len(params)}")
352
+ where_clause = " AND ".join(conditions)
353
+ async with self._pool.acquire() as connection:
354
+ if limit is not None:
355
+ params.extend([limit, offset or 0])
356
+ limit_param = len(params) - 1
357
+ offset_param = len(params)
358
+ query = f"""
359
+ SELECT id, session_id, author, event_type, content_json, timestamp,
360
+ state_delta_json, seq_id, invocation_id, metadata_json
361
+ FROM (
362
+ SELECT id, session_id, author, event_type, content_json, timestamp,
363
+ state_delta_json, seq_id, invocation_id, metadata_json
364
+ FROM {KSADK_PG_EVENTS_TABLE}
365
+ WHERE {where_clause}
366
+ ORDER BY seq_id DESC
367
+ LIMIT ${limit_param} OFFSET ${offset_param}
368
+ ) AS latest_events
369
+ ORDER BY seq_id ASC
370
+ """
371
+ elif offset is not None:
372
+ params.append(offset)
373
+ offset_param = len(params)
374
+ query = f"""
375
+ SELECT id, session_id, author, event_type, content_json, timestamp,
376
+ state_delta_json, seq_id, invocation_id, metadata_json
377
+ FROM (
378
+ SELECT id, session_id, author, event_type, content_json, timestamp,
379
+ state_delta_json, seq_id, invocation_id, metadata_json
380
+ FROM {KSADK_PG_EVENTS_TABLE}
381
+ WHERE {where_clause}
382
+ ORDER BY seq_id DESC
383
+ OFFSET ${offset_param}
384
+ ) AS latest_events
385
+ ORDER BY seq_id ASC
386
+ """
387
+ else:
388
+ query = f"""
389
+ SELECT id, session_id, author, event_type, content_json, timestamp,
390
+ state_delta_json, seq_id, invocation_id, metadata_json
391
+ FROM {KSADK_PG_EVENTS_TABLE}
392
+ WHERE {where_clause}
393
+ ORDER BY seq_id ASC
394
+ """
395
+ rows = await connection.fetch(query, *params)
396
+ return [self._event_from_row(row) for row in rows]
397
+
398
+ async def count_events(
399
+ self,
400
+ session_id: str,
401
+ after_seq_id: Optional[int] = None,
402
+ before_seq_id: Optional[int] = None,
403
+ ) -> int:
404
+ await self._ensure_schema()
405
+ conditions = ["namespace = $1", "session_id = $2"]
406
+ params: list[Any] = [self.namespace, session_id]
407
+ if after_seq_id is not None:
408
+ params.append(after_seq_id)
409
+ conditions.append(f"seq_id > ${len(params)}")
410
+ if before_seq_id is not None:
411
+ params.append(before_seq_id)
412
+ conditions.append(f"seq_id < ${len(params)}")
413
+ where_clause = " AND ".join(conditions)
414
+ async with self._pool.acquire() as connection:
415
+ query = f"""
416
+ SELECT COUNT(*) AS total
417
+ FROM {KSADK_PG_EVENTS_TABLE}
418
+ WHERE {where_clause}
419
+ """
420
+ return int(await connection.fetchval(query, *params) or 0)
421
+
422
+ async def get_state(
423
+ self,
424
+ agent_id: str,
425
+ user_id: Optional[str],
426
+ session_id: Optional[str],
427
+ scope: str = "session",
428
+ ) -> Optional[SessionState]:
429
+ await self._ensure_schema()
430
+ async with self._pool.acquire() as connection:
431
+ if scope == "session" and session_id:
432
+ session = await self._get_session_with_connection(connection, session_id)
433
+ if session is None:
434
+ return None
435
+ return SessionState(
436
+ scope="session",
437
+ agent_id=session.agent_id,
438
+ user_id=session.user_id,
439
+ session_id=session.id,
440
+ state=dict(session.state),
441
+ version=session.version,
442
+ updated_at=session.updated_at,
443
+ )
444
+ row = await connection.fetchrow(
445
+ f"""
446
+ SELECT scope, agent_id, user_id, session_id, state_json, version, updated_at
447
+ FROM {KSADK_PG_STATES_TABLE}
448
+ WHERE namespace = $1 AND scope = $2 AND agent_id = $3 AND user_id = $4 AND session_id = $5
449
+ """,
450
+ self.namespace,
451
+ scope,
452
+ agent_id,
453
+ user_id or "",
454
+ session_id or "",
455
+ )
456
+ if row is None:
457
+ return None
458
+ return self._state_from_row(row)
459
+
460
+ async def update_state(
461
+ self,
462
+ *,
463
+ agent_id: str,
464
+ user_id: Optional[str],
465
+ session_id: Optional[str],
466
+ scope: str,
467
+ state_delta: dict[str, Any],
468
+ ) -> SessionState:
469
+ await self._ensure_schema()
470
+ async with self._pool.acquire() as connection:
471
+ async with connection.transaction():
472
+ updated_at = time.time()
473
+ if scope == "session":
474
+ if not session_id:
475
+ raise ValueError("session_id is required for session scope")
476
+ session = await self._get_session_with_connection(
477
+ connection,
478
+ session_id,
479
+ for_update=True,
480
+ )
481
+ if session is None:
482
+ raise ValueError(f"Session {session_id} not found")
483
+ next_state = dict(session.state)
484
+ next_state.update(state_delta)
485
+ next_version = session.version + 1
486
+ await self._write_session_state(
487
+ connection,
488
+ session_id=session.id,
489
+ agent_id=session.agent_id,
490
+ user_id=session.user_id,
491
+ state=next_state,
492
+ version=next_version,
493
+ updated_at=updated_at,
494
+ )
495
+ return SessionState(
496
+ scope="session",
497
+ agent_id=session.agent_id,
498
+ user_id=session.user_id,
499
+ session_id=session.id,
500
+ state=next_state,
501
+ version=next_version,
502
+ updated_at=updated_at,
503
+ )
504
+
505
+ row = await connection.fetchrow(
506
+ f"""
507
+ SELECT state_json, version
508
+ FROM {KSADK_PG_STATES_TABLE}
509
+ WHERE namespace = $1 AND scope = $2 AND agent_id = $3 AND user_id = $4 AND session_id = $5
510
+ FOR UPDATE
511
+ """,
512
+ self.namespace,
513
+ scope,
514
+ agent_id,
515
+ user_id or "",
516
+ session_id or "",
517
+ )
518
+ next_state = self._json_to_dict(row["state_json"]) if row else {}
519
+ next_state.update(state_delta)
520
+ next_version = (int(row["version"] or 0) + 1) if row else 1
521
+ await connection.execute(
522
+ f"""
523
+ INSERT INTO {KSADK_PG_STATES_TABLE} (
524
+ namespace, tenant_id, workspace_id, scope, agent_id, user_id, session_id, state_json, version, updated_at
525
+ )
526
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8::jsonb, $9, $10)
527
+ ON CONFLICT (namespace, scope, agent_id, user_id, session_id)
528
+ DO UPDATE SET state_json = EXCLUDED.state_json,
529
+ version = EXCLUDED.version,
530
+ updated_at = EXCLUDED.updated_at
531
+ """,
532
+ self.namespace,
533
+ self.tenant_id,
534
+ self.workspace_id,
535
+ scope,
536
+ agent_id,
537
+ user_id or "",
538
+ session_id or "",
539
+ json.dumps(next_state),
540
+ next_version,
541
+ updated_at,
542
+ )
543
+ return SessionState(
544
+ scope=scope,
545
+ agent_id=agent_id,
546
+ user_id=user_id or "",
547
+ session_id=session_id or "",
548
+ state=next_state,
549
+ version=next_version,
550
+ updated_at=updated_at,
551
+ )
552
+
553
+ async def aclose(self) -> None:
554
+ pool = self._pool
555
+ self._pool = None
556
+ self._schema_ready = False
557
+ if pool is None:
558
+ return
559
+ try:
560
+ await asyncio.wait_for(pool.close(), timeout=self.connect_timeout)
561
+ except (TimeoutError, OSError, ConnectionError, asyncio.TimeoutError):
562
+ pool.terminate()
563
+
564
+ async def _ensure_pool(self) -> None:
565
+ if self._pool is not None:
566
+ return
567
+ async with self._pool_lock:
568
+ if self._pool is not None:
569
+ return
570
+ try:
571
+ import asyncpg
572
+ except ImportError as exc:
573
+ raise SessionBackendUnavailable(
574
+ "asyncpg is required for KSADK_SESSION_BACKEND=postgres"
575
+ ) from exc
576
+ try:
577
+ self._pool = await asyncpg.create_pool(
578
+ dsn=self.dsn,
579
+ min_size=self.min_size,
580
+ max_size=self.max_size,
581
+ timeout=self.connect_timeout,
582
+ command_timeout=self.connect_timeout,
583
+ )
584
+ except (TimeoutError, OSError, ConnectionError, asyncio.TimeoutError) as exc:
585
+ raise SessionBackendUnavailable(
586
+ "Postgres session backend unavailable: "
587
+ f"could not connect to {mask_postgres_session_dsn(self.dsn)}"
588
+ ) from exc
589
+
590
+ async def _ensure_schema(self) -> None:
591
+ if self._schema_ready:
592
+ return
593
+ async with self._schema_lock:
594
+ if self._schema_ready:
595
+ return
596
+ await self._ensure_pool()
597
+ async with self._pool.acquire() as connection:
598
+ await connection.execute(
599
+ f"""
600
+ CREATE TABLE IF NOT EXISTS {KSADK_PG_SESSIONS_TABLE} (
601
+ namespace TEXT NOT NULL,
602
+ tenant_id TEXT NOT NULL DEFAULT 'default',
603
+ workspace_id TEXT NOT NULL DEFAULT 'default',
604
+ id TEXT NOT NULL,
605
+ agent_id TEXT NOT NULL,
606
+ user_id TEXT NOT NULL,
607
+ title TEXT NOT NULL DEFAULT '',
608
+ title_source TEXT NOT NULL DEFAULT '',
609
+ summary TEXT NOT NULL DEFAULT '',
610
+ first_prompt TEXT NOT NULL DEFAULT '',
611
+ last_prompt TEXT NOT NULL DEFAULT '',
612
+ state_json JSONB NOT NULL DEFAULT '{{}}'::jsonb,
613
+ created_at DOUBLE PRECISION NOT NULL,
614
+ updated_at DOUBLE PRECISION NOT NULL,
615
+ version INTEGER NOT NULL DEFAULT 0,
616
+ PRIMARY KEY (namespace, id)
617
+ );
618
+
619
+ CREATE TABLE IF NOT EXISTS {KSADK_PG_EVENTS_TABLE} (
620
+ namespace TEXT NOT NULL,
621
+ tenant_id TEXT NOT NULL DEFAULT 'default',
622
+ workspace_id TEXT NOT NULL DEFAULT 'default',
623
+ id TEXT NOT NULL,
624
+ session_id TEXT NOT NULL,
625
+ author TEXT NOT NULL,
626
+ event_type TEXT NOT NULL,
627
+ content_json JSONB NOT NULL DEFAULT '{{}}'::jsonb,
628
+ timestamp DOUBLE PRECISION NOT NULL,
629
+ state_delta_json JSONB NOT NULL DEFAULT '{{}}'::jsonb,
630
+ seq_id INTEGER NOT NULL,
631
+ invocation_id TEXT,
632
+ metadata_json JSONB NOT NULL DEFAULT '{{}}'::jsonb,
633
+ PRIMARY KEY (namespace, id),
634
+ UNIQUE (namespace, session_id, seq_id),
635
+ FOREIGN KEY (namespace, session_id)
636
+ REFERENCES {KSADK_PG_SESSIONS_TABLE}(namespace, id)
637
+ ON DELETE CASCADE
638
+ );
639
+
640
+ CREATE INDEX IF NOT EXISTS idx_ksadk_pg_events_session_seq
641
+ ON {KSADK_PG_EVENTS_TABLE} (namespace, session_id, seq_id);
642
+
643
+ CREATE TABLE IF NOT EXISTS {KSADK_PG_STATES_TABLE} (
644
+ namespace TEXT NOT NULL,
645
+ tenant_id TEXT NOT NULL DEFAULT 'default',
646
+ workspace_id TEXT NOT NULL DEFAULT 'default',
647
+ scope TEXT NOT NULL,
648
+ agent_id TEXT NOT NULL,
649
+ user_id TEXT NOT NULL DEFAULT '',
650
+ session_id TEXT NOT NULL DEFAULT '',
651
+ state_json JSONB NOT NULL DEFAULT '{{}}'::jsonb,
652
+ version INTEGER NOT NULL DEFAULT 0,
653
+ updated_at DOUBLE PRECISION NOT NULL,
654
+ PRIMARY KEY (namespace, scope, agent_id, user_id, session_id)
655
+ );
656
+
657
+ ALTER TABLE {KSADK_PG_SESSIONS_TABLE}
658
+ ADD COLUMN IF NOT EXISTS tenant_id TEXT NOT NULL DEFAULT 'default';
659
+ ALTER TABLE {KSADK_PG_SESSIONS_TABLE}
660
+ ADD COLUMN IF NOT EXISTS workspace_id TEXT NOT NULL DEFAULT 'default';
661
+ ALTER TABLE {KSADK_PG_EVENTS_TABLE}
662
+ ADD COLUMN IF NOT EXISTS tenant_id TEXT NOT NULL DEFAULT 'default';
663
+ ALTER TABLE {KSADK_PG_EVENTS_TABLE}
664
+ ADD COLUMN IF NOT EXISTS workspace_id TEXT NOT NULL DEFAULT 'default';
665
+ ALTER TABLE {KSADK_PG_STATES_TABLE}
666
+ ADD COLUMN IF NOT EXISTS tenant_id TEXT NOT NULL DEFAULT 'default';
667
+ ALTER TABLE {KSADK_PG_STATES_TABLE}
668
+ ADD COLUMN IF NOT EXISTS workspace_id TEXT NOT NULL DEFAULT 'default';
669
+ """
670
+ )
671
+ try:
672
+ await connection.execute(
673
+ f"""
674
+ CREATE OR REPLACE VIEW {PG_READABLE_EVENTS_VIEW} AS
675
+ SELECT
676
+ event_row.namespace,
677
+ event_row.tenant_id,
678
+ event_row.workspace_id,
679
+ session_row.agent_id,
680
+ session_row.user_id,
681
+ session_row.title AS session_title,
682
+ event_row.session_id,
683
+ event_row.seq_id,
684
+ event_row.id AS event_id,
685
+ event_row.invocation_id,
686
+ event_row.author,
687
+ event_row.event_type,
688
+ CASE
689
+ WHEN event_row.event_type = 'user_message' THEN 'user'
690
+ WHEN event_row.event_type IN (
691
+ 'assistant_message', 'reasoning', 'tool_call'
692
+ ) THEN 'assistant'
693
+ WHEN event_row.event_type = 'tool_result' THEN 'tool'
694
+ ELSE NULL
695
+ END AS message_role,
696
+ COALESCE(
697
+ NULLIF(event_row.content_json #>> '{{parts,0,text}}', ''),
698
+ NULLIF(event_row.content_json ->> 'text', ''),
699
+ NULLIF(event_row.metadata_json ->> 'reasoning', ''),
700
+ NULLIF(event_row.metadata_json ->> 'tool_output', '')
701
+ ) AS message_text,
702
+ event_row.metadata_json ->> 'tool_name' AS tool_name,
703
+ CASE
704
+ WHEN event_row.event_type = 'run_status' THEN COALESCE(
705
+ event_row.content_json ->> 'status',
706
+ event_row.metadata_json ->> 'status'
707
+ )
708
+ ELSE NULL
709
+ END AS lifecycle_status,
710
+ to_timestamp(event_row.timestamp) AS created_at,
711
+ event_row.content_json,
712
+ event_row.state_delta_json,
713
+ event_row.metadata_json
714
+ FROM {KSADK_PG_EVENTS_TABLE} AS event_row
715
+ JOIN {KSADK_PG_SESSIONS_TABLE} AS session_row
716
+ ON session_row.namespace = event_row.namespace
717
+ AND session_row.id = event_row.session_id;
718
+ """
719
+ )
720
+ except Exception as exc:
721
+ logger.warning("Postgres readable session view unavailable: %s", exc)
722
+ self._schema_ready = True
723
+
724
+ async def _get_session_with_connection(
725
+ self,
726
+ connection: Any,
727
+ session_id: str,
728
+ *,
729
+ for_update: bool = False,
730
+ ) -> Optional[Session]:
731
+ lock_clause = " FOR UPDATE" if for_update else ""
732
+ row = await connection.fetchrow(
733
+ f"""
734
+ SELECT id, agent_id, user_id, title, title_source, summary, first_prompt, last_prompt,
735
+ state_json, created_at, updated_at, version
736
+ FROM {KSADK_PG_SESSIONS_TABLE}
737
+ WHERE namespace = $1 AND id = $2
738
+ {lock_clause}
739
+ """,
740
+ self.namespace,
741
+ session_id,
742
+ )
743
+ if row is None:
744
+ return None
745
+ events = [] if for_update else await self._get_events_with_connection(connection, session_id)
746
+ return self._session_from_row(row, events=events)
747
+
748
+ async def _get_events_with_connection(self, connection: Any, session_id: str) -> list[SessionEvent]:
749
+ rows = await connection.fetch(
750
+ f"""
751
+ SELECT id, session_id, author, event_type, content_json, timestamp,
752
+ state_delta_json, seq_id, invocation_id, metadata_json
753
+ FROM {KSADK_PG_EVENTS_TABLE}
754
+ WHERE namespace = $1 AND session_id = $2
755
+ ORDER BY seq_id ASC
756
+ """,
757
+ self.namespace,
758
+ session_id,
759
+ )
760
+ return [self._event_from_row(row) for row in rows]
761
+
762
+ async def _write_session_state(
763
+ self,
764
+ connection: Any,
765
+ *,
766
+ session_id: str,
767
+ agent_id: str,
768
+ user_id: str,
769
+ state: dict[str, Any],
770
+ version: int,
771
+ updated_at: float,
772
+ ) -> None:
773
+ await connection.execute(
774
+ f"""
775
+ UPDATE {KSADK_PG_SESSIONS_TABLE}
776
+ SET state_json = $1::jsonb, updated_at = $2, version = $3
777
+ WHERE namespace = $4 AND id = $5
778
+ """,
779
+ json.dumps(state),
780
+ updated_at,
781
+ version,
782
+ self.namespace,
783
+ session_id,
784
+ )
785
+ await connection.execute(
786
+ f"""
787
+ INSERT INTO {KSADK_PG_STATES_TABLE} (
788
+ namespace, tenant_id, workspace_id, scope, agent_id, user_id, session_id, state_json, version, updated_at
789
+ )
790
+ VALUES ($1, $2, $3, 'session', $4, $5, $6, $7::jsonb, $8, $9)
791
+ ON CONFLICT (namespace, scope, agent_id, user_id, session_id)
792
+ DO UPDATE SET state_json = EXCLUDED.state_json,
793
+ version = EXCLUDED.version,
794
+ updated_at = EXCLUDED.updated_at
795
+ """,
796
+ self.namespace,
797
+ self.tenant_id,
798
+ self.workspace_id,
799
+ agent_id,
800
+ user_id,
801
+ session_id,
802
+ json.dumps(state),
803
+ version,
804
+ updated_at,
805
+ )
806
+
807
+ @classmethod
808
+ def _session_from_row(cls, row: Any, *, events: list[SessionEvent]) -> Session:
809
+ return Session(
810
+ id=row["id"],
811
+ agent_id=row["agent_id"],
812
+ user_id=row["user_id"],
813
+ title=row["title"],
814
+ title_source=row["title_source"],
815
+ summary=row["summary"],
816
+ first_prompt=row["first_prompt"],
817
+ last_prompt=row["last_prompt"],
818
+ state=cls._json_to_dict(row["state_json"]),
819
+ events=events,
820
+ created_at=float(row["created_at"]),
821
+ updated_at=float(row["updated_at"]),
822
+ version=int(row["version"] or 0),
823
+ )
824
+
825
+ @classmethod
826
+ def _event_from_row(cls, row: Any) -> SessionEvent:
827
+ return SessionEvent(
828
+ id=row["id"],
829
+ session_id=row["session_id"],
830
+ author=row["author"],
831
+ event_type=row["event_type"],
832
+ content=cls._json_to_dict(row["content_json"]),
833
+ timestamp=float(row["timestamp"]),
834
+ state_delta=cls._json_to_dict(row["state_delta_json"]),
835
+ seq_id=int(row["seq_id"] or 0),
836
+ invocation_id=row["invocation_id"],
837
+ metadata=cls._json_to_dict(row["metadata_json"]),
838
+ )
839
+
840
+ @classmethod
841
+ def _state_from_row(cls, row: Any) -> SessionState:
842
+ return SessionState(
843
+ scope=row["scope"],
844
+ agent_id=row["agent_id"],
845
+ user_id=row["user_id"],
846
+ session_id=row["session_id"],
847
+ state=cls._json_to_dict(row["state_json"]),
848
+ version=int(row["version"] or 0),
849
+ updated_at=float(row["updated_at"]),
850
+ )
851
+
852
+ @staticmethod
853
+ def _json_to_dict(value: Any) -> dict[str, Any]:
854
+ if value is None:
855
+ return {}
856
+ if isinstance(value, dict):
857
+ return dict(value)
858
+ if isinstance(value, str):
859
+ return dict(json.loads(value or "{}"))
860
+ return dict(value)
861
+
862
+
863
+ def create_postgres_session_service(
864
+ *,
865
+ dsn: str,
866
+ namespace: str = "default",
867
+ tenant_id: str = "default",
868
+ workspace_id: str = "default",
869
+ ) -> PostgresSessionService:
870
+ return PostgresSessionService(
871
+ dsn=dsn,
872
+ namespace=namespace,
873
+ tenant_id=tenant_id,
874
+ workspace_id=workspace_id,
875
+ )
876
+
877
+
878
+ def mask_postgres_session_dsn(dsn: str) -> str:
879
+ if not dsn:
880
+ return ""
881
+ try:
882
+ parts = urlsplit(dsn)
883
+ except ValueError:
884
+ return "***"
885
+ if not parts.password:
886
+ return dsn
887
+ username = parts.username or ""
888
+ host = parts.hostname or ""
889
+ port = f":{parts.port}" if parts.port else ""
890
+ auth = f"{username}:***@" if username else "***@"
891
+ return urlunsplit((parts.scheme, f"{auth}{host}{port}", parts.path, parts.query, parts.fragment))
892
+
893
+
894
+ __all__ = [
895
+ "KSADK_PG_EVENTS_TABLE",
896
+ "KSADK_PG_SESSIONS_TABLE",
897
+ "KSADK_PG_STATES_TABLE",
898
+ "PostgresSessionService",
899
+ "create_postgres_session_service",
900
+ "mask_postgres_session_dsn",
901
+ ]