agentengine-sdk-python 0.7.0__py3-none-any.whl → 0.8.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (371) hide show
  1. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/METADATA +36 -20
  2. agentengine_sdk_python-0.8.0.dist-info/RECORD +578 -0
  3. ksadk/a2a/__init__.py +178 -11
  4. ksadk/a2a/bootstrap.py +334 -0
  5. ksadk/a2a/card.py +120 -0
  6. ksadk/a2a/context_store.py +203 -0
  7. ksadk/a2a/control_plane.py +818 -0
  8. ksadk/a2a/credential.py +99 -0
  9. ksadk/a2a/event_adapter.py +149 -0
  10. ksadk/a2a/executor.py +406 -89
  11. ksadk/a2a/external_transport.py +516 -0
  12. ksadk/a2a/identity.py +304 -0
  13. ksadk/a2a/ids.py +22 -0
  14. ksadk/a2a/langgraph.py +285 -0
  15. ksadk/a2a/resume_store.py +201 -0
  16. ksadk/a2a/routes.py +105 -0
  17. ksadk/a2a/server.py +107 -60
  18. ksadk/a2a/space_client.py +1101 -0
  19. ksadk/a2a/task_adapter.py +423 -0
  20. ksadk/a2a/task_event_dispatcher.py +167 -0
  21. ksadk/a2a/task_event_outbox.py +326 -0
  22. ksadk/a2a/task_store.py +206 -0
  23. ksadk/a2ui/__init__.py +27 -0
  24. ksadk/a2ui/core.py +186 -0
  25. ksadk/a2ui/models.py +166 -0
  26. ksadk/a2ui/renderer.py +198 -0
  27. ksadk/agui/__init__.py +9 -0
  28. ksadk/agui/a2ui_projection.py +92 -0
  29. ksadk/agui/agent.py +857 -0
  30. ksadk/agui/config.py +86 -0
  31. ksadk/agui/routes.py +55 -0
  32. ksadk/api/client.py +233 -191
  33. ksadk/builders/__init__.py +2 -0
  34. ksadk/builders/base.py +16 -14
  35. ksadk/builders/code_builder.py +318 -236
  36. ksadk/builders/container_builder.py +187 -167
  37. ksadk/builders/framework_requirements.py +29 -11
  38. ksadk/builders/ks3_uploader.py +58 -27
  39. ksadk/builders/managed_runtime_builder.py +145 -0
  40. ksadk/builders/mcp_builder.py +91 -92
  41. ksadk/builders/requirements_utils.py +1 -5
  42. ksadk/cli/__init__.py +89 -171
  43. ksadk/cli/cmd_a2a.py +254 -70
  44. ksadk/cli/cmd_agent.py +19 -5
  45. ksadk/cli/cmd_build.py +158 -29
  46. ksadk/cli/cmd_completion.py +47 -35
  47. ksadk/cli/cmd_config.py +267 -198
  48. ksadk/cli/cmd_create.py +500 -720
  49. ksadk/cli/cmd_dashboard.py +120 -45
  50. ksadk/cli/cmd_deploy.py +117 -58
  51. ksadk/cli/cmd_destroy.py +44 -14
  52. ksadk/cli/cmd_files.py +63 -24
  53. ksadk/cli/cmd_hermes.py +168 -89
  54. ksadk/cli/cmd_invoke.py +184 -122
  55. ksadk/cli/cmd_launch.py +64 -28
  56. ksadk/cli/cmd_mcp.py +98 -64
  57. ksadk/cli/cmd_model.py +14 -5
  58. ksadk/cli/cmd_openclaw.py +483 -227
  59. ksadk/cli/cmd_replay.py +71 -0
  60. ksadk/cli/cmd_run.py +33 -10
  61. ksadk/cli/cmd_status.py +80 -31
  62. ksadk/cli/cmd_version.py +20 -13
  63. ksadk/cli/cmd_web.py +89 -13
  64. ksadk/cli/deploy_utils.py +20 -20
  65. ksadk/cli/dry_run.py +5 -3
  66. ksadk/cli/error_utils.py +37 -12
  67. ksadk/cli/global_options.py +1 -2
  68. ksadk/cli/local_runtime.py +1 -2
  69. ksadk/cli/model_catalog.py +6 -2
  70. ksadk/cli/network_options.py +34 -14
  71. ksadk/cli/resource_common.py +6 -2
  72. ksadk/cli/storage.py +0 -1
  73. ksadk/cli/ui.py +5 -3
  74. ksadk/cli/workflow_common.py +51 -17
  75. ksadk/codex/__init__.py +12 -0
  76. ksadk/codex/client.py +408 -0
  77. ksadk/codex/phase.py +143 -0
  78. ksadk/codex/runtime.py +449 -0
  79. ksadk/common/aicp_env.py +0 -1
  80. ksadk/common/auth.py +2 -2
  81. ksadk/common/constants.py +1 -3
  82. ksadk/common/llm_utils.py +17 -13
  83. ksadk/compat/__init__.py +5 -0
  84. ksadk/compat/adk_compat.py +200 -0
  85. ksadk/compat/copilotkit_a2ui.py +330 -0
  86. ksadk/configs/__init__.py +12 -12
  87. ksadk/configs/env_registry.py +500 -100
  88. ksadk/configs/global_config.py +2 -1
  89. ksadk/configs/settings.py +151 -124
  90. ksadk/conversations/__init__.py +7 -5
  91. ksadk/conversations/attachment_storage.py +16 -11
  92. ksadk/conversations/attachments.py +44 -36
  93. ksadk/conversations/compaction_pipeline.py +12 -12
  94. ksadk/conversations/compaction_prompt.py +9 -5
  95. ksadk/conversations/context.py +221 -6
  96. ksadk/conversations/message_projection.py +438 -51
  97. ksadk/conversations/model_context.py +12 -6
  98. ksadk/conversations/model_options.py +0 -1
  99. ksadk/conversations/normalize.py +20 -16
  100. ksadk/conversations/reasoning_markup.py +1 -1
  101. ksadk/conversations/runtime.py +339 -5255
  102. ksadk/conversations/runtime_compaction.py +333 -0
  103. ksadk/conversations/runtime_constants.py +27 -0
  104. ksadk/conversations/runtime_governance.py +185 -0
  105. ksadk/conversations/runtime_input.py +652 -0
  106. ksadk/conversations/runtime_invocation.py +395 -0
  107. ksadk/conversations/runtime_metadata.py +475 -0
  108. ksadk/conversations/runtime_observability.py +355 -0
  109. ksadk/conversations/runtime_payloads.py +272 -0
  110. ksadk/conversations/runtime_persistence.py +440 -0
  111. ksadk/conversations/runtime_preparation.py +418 -0
  112. ksadk/conversations/runtime_resume.py +816 -0
  113. ksadk/conversations/runtime_stream_events.py +902 -0
  114. ksadk/conversations/runtime_streaming.py +547 -0
  115. ksadk/conversations/semantic_summary.py +17 -5
  116. ksadk/conversations/session_title.py +6 -3
  117. ksadk/deployment/__init__.py +15 -16
  118. ksadk/deployment/agent_access.py +12 -23
  119. ksadk/deployment/base.py +51 -38
  120. ksadk/deployment/manager.py +63 -65
  121. ksadk/deployment/providers/serverless.py +309 -202
  122. ksadk/deployment/registry.py +38 -32
  123. ksadk/deployment/state.py +11 -11
  124. ksadk/deployment/ui_config.py +1 -1
  125. ksadk/detection/__init__.py +1 -1
  126. ksadk/detection/detector.py +146 -83
  127. ksadk/detection/mcp_detector.py +9 -6
  128. ksadk/events/__init__.py +25 -0
  129. ksadk/events/parser.py +191 -0
  130. ksadk/events/replay.py +37 -0
  131. ksadk/events/runtime_event.py +264 -0
  132. ksadk/events/store.py +317 -0
  133. ksadk/harness/__init__.py +34 -0
  134. ksadk/harness/app.py +278 -0
  135. ksadk/harness/config.py +181 -0
  136. ksadk/harness/reasoner.py +105 -0
  137. ksadk/harness/runner.py +211 -0
  138. ksadk/harness/sandbox.py +141 -0
  139. ksadk/harness/tools.py +222 -0
  140. ksadk/hermes_terminal.py +23 -12
  141. ksadk/identity/resolver.py +15 -9
  142. ksadk/ids.py +32 -0
  143. ksadk/knowledge_base/adk_tool.py +1 -1
  144. ksadk/knowledge_base/client.py +23 -29
  145. ksadk/managed_runtime.py +188 -0
  146. ksadk/markdown.py +5 -2
  147. ksadk/mcp_runtime/__init__.py +9 -6
  148. ksadk/memory/__init__.py +1 -1
  149. ksadk/memory/adk/__init__.py +2 -0
  150. ksadk/memory/adk/backends/base_ltm_backend.py +2 -6
  151. ksadk/memory/adk/backends/http_ltm_backend.py +13 -21
  152. ksadk/memory/adk/backends/inmemory_ltm_backend.py +7 -13
  153. ksadk/memory/adk/backends/sdk_ltm_backend.py +26 -33
  154. ksadk/memory/adk/long_term_memory.py +31 -35
  155. ksadk/memory/adk/resilient_session_service.py +4 -5
  156. ksadk/memory/adk/short_term_memory.py +12 -21
  157. ksadk/memory/adk_tool.py +3 -2
  158. ksadk/memory/backends/base.py +19 -19
  159. ksadk/memory/backends/memory.py +24 -25
  160. ksadk/memory/backends/redis.py +31 -30
  161. ksadk/memory/langchain_tool.py +2 -1
  162. ksadk/memory/manager.py +52 -47
  163. ksadk/memory/service.py +10 -8
  164. ksadk/model_policy.py +15 -7
  165. ksadk/model_proxy/__init__.py +51 -0
  166. ksadk/model_proxy/bootstrap.py +80 -0
  167. ksadk/model_proxy/cache.py +165 -0
  168. ksadk/model_proxy/config.py +45 -0
  169. ksadk/model_proxy/demo_webui.py +115 -0
  170. ksadk/model_proxy/detect.py +145 -0
  171. ksadk/model_proxy/gate.py +68 -0
  172. ksadk/model_proxy/namespace.py +173 -0
  173. ksadk/model_proxy/protocol_proxy.py +22 -0
  174. ksadk/model_proxy/server.py +300 -0
  175. ksadk/model_proxy/transform.py +691 -0
  176. ksadk/openclaw_gateway.py +29 -14
  177. ksadk/runners/adk_runner.py +345 -120
  178. ksadk/runners/base_runner.py +46 -29
  179. ksadk/runners/codex_runner.py +132 -0
  180. ksadk/runners/deepagents_runner.py +0 -1
  181. ksadk/runners/factory.py +17 -5
  182. ksadk/runners/langchain_runner.py +29 -742
  183. ksadk/runners/langgraph_runner.py +352 -90
  184. ksadk/runners/patch_langchain.py +16 -16
  185. ksadk/runners/remote_runner.py +134 -33
  186. ksadk/runners/usage_accumulator.py +1 -0
  187. ksadk/runners/utils/langfuse.py +3 -3
  188. ksadk/runners/utils/loader.py +7 -7
  189. ksadk/runtime/__init__.py +41 -0
  190. ksadk/runtime/adapter.py +345 -0
  191. ksadk/runtime/framework_adapters.py +124 -0
  192. ksadk/runtime/preprocessing.py +118 -0
  193. ksadk/runtime/runner_adapter.py +873 -0
  194. ksadk/runtime_context.py +18 -3
  195. ksadk/runtime_state.py +0 -1
  196. ksadk/sandbox/__init__.py +4 -1
  197. ksadk/sandbox/backends/__init__.py +4 -1
  198. ksadk/sandbox/backends/e2b.py +13 -5
  199. ksadk/sandbox/backends/local_process.py +11 -3
  200. ksadk/sandbox/base.py +10 -15
  201. ksadk/sandbox/factory.py +14 -4
  202. ksadk/sandbox/registry.py +57 -6
  203. ksadk/server/api_models.py +15 -5
  204. ksadk/server/app.py +455 -3885
  205. ksadk/server/composition.py +21 -0
  206. ksadk/server/factory.py +624 -0
  207. ksadk/server/routes/__init__.py +1 -0
  208. ksadk/server/routes/checkpoint_resolution.py +116 -0
  209. ksadk/server/routes/common.py +713 -0
  210. ksadk/server/routes/control.py +327 -0
  211. ksadk/server/routes/dependencies.py +98 -0
  212. ksadk/server/routes/misc.py +448 -0
  213. ksadk/server/routes/models.py +443 -0
  214. ksadk/server/routes/openai_compat.py +207 -0
  215. ksadk/server/routes/projection.py +795 -0
  216. ksadk/server/routes/routers.py +52 -0
  217. ksadk/server/routes/run.py +726 -0
  218. ksadk/server/routes/sessions.py +649 -0
  219. ksadk/server/routes/streaming.py +223 -0
  220. ksadk/server/routes/workspace.py +381 -0
  221. ksadk/server/static/assets/{ArtifactsPanel-D-SSn2ee.js → ArtifactsPanel-Cjnqt-8W.js} +1 -1
  222. ksadk/server/static/assets/CodeBlock-BqyqZfuB.js +9 -0
  223. ksadk/server/static/assets/MathMessageMarkdown-BpH7jiFM.js +8 -0
  224. ksadk/server/static/assets/MermaidBlock-DWuxETaJ.js +303 -0
  225. ksadk/server/static/assets/NativeTerminalPanel-MDTopWMO.js +1 -0
  226. ksadk/server/static/assets/{arc-BA13sHc9.js → arc-CFKwSk_B.js} +1 -1
  227. ksadk/server/static/assets/architecture-7EHR7CIX-CynqOWjZ.js +1 -0
  228. ksadk/server/static/assets/{architectureDiagram-3BPJPVTR-DzJzgVoL.js → architectureDiagram-3BPJPVTR-Dej8jX8c.js} +1 -1
  229. ksadk/server/static/assets/{blockDiagram-GPEHLZMM-UTdVcZhn.js → blockDiagram-GPEHLZMM-1F64jqvy.js} +1 -1
  230. ksadk/server/static/assets/{c4Diagram-AAUBKEIU-Dix0GD4m.js → c4Diagram-AAUBKEIU-9q7AUAKb.js} +1 -1
  231. ksadk/server/static/assets/channel-iUGv2N24.js +1 -0
  232. ksadk/server/static/assets/{chunk-2J33WTMH-C2JxuZ42.js → chunk-2J33WTMH-6qgwJm7Q.js} +1 -1
  233. ksadk/server/static/assets/{chunk-4BX2VUAB-Be57QPgD.js → chunk-4BX2VUAB-CsWIQRhc.js} +1 -1
  234. ksadk/server/static/assets/{chunk-55IACEB6-WjSuy4nv.js → chunk-55IACEB6-BK8paA20.js} +1 -1
  235. ksadk/server/static/assets/{chunk-727SXJPM-BOovP-b5.js → chunk-727SXJPM-B-JEhy7h.js} +1 -1
  236. ksadk/server/static/assets/{chunk-AQP2D5EJ-DOmZNmWj.js → chunk-AQP2D5EJ-DYBvMHAa.js} +1 -1
  237. ksadk/server/static/assets/{chunk-FMBD7UC4-DzwlodkU.js → chunk-FMBD7UC4-BGhvzDYt.js} +1 -1
  238. ksadk/server/static/assets/{chunk-ND2GUHAM-DMqAikEU.js → chunk-ND2GUHAM-D98vPd-E.js} +1 -1
  239. ksadk/server/static/assets/chunk-QZHKN3VN-YQIEXeF6.js +1 -0
  240. ksadk/server/static/assets/classDiagram-4FO5ZUOK-CDAUuoXK.js +1 -0
  241. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-CDAUuoXK.js +1 -0
  242. ksadk/server/static/assets/{cose-bilkent-S5V4N54A-Zhy2GBnP.js → cose-bilkent-S5V4N54A-CX3yotHq.js} +1 -1
  243. ksadk/server/static/assets/{dagre-BM42HDAG-CbKrtIUz.js → dagre-BM42HDAG-C7TguAWo.js} +1 -1
  244. ksadk/server/static/assets/{diagram-2AECGRRQ-BRApgQRK.js → diagram-2AECGRRQ-Dd17_kws.js} +1 -1
  245. ksadk/server/static/assets/{diagram-5GNKFQAL-D0xbnDiK.js → diagram-5GNKFQAL-DVIClIil.js} +1 -1
  246. ksadk/server/static/assets/{diagram-KO2AKTUF-CVugVI9L.js → diagram-KO2AKTUF-Df_3gYQa.js} +1 -1
  247. ksadk/server/static/assets/{diagram-LMA3HP47-DozUGgee.js → diagram-LMA3HP47-BhLk6ZtA.js} +1 -1
  248. ksadk/server/static/assets/{diagram-OG6HWLK6-ZOYsKlru.js → diagram-OG6HWLK6-D4GNGvuu.js} +1 -1
  249. ksadk/server/static/assets/{dist-DmFaq_Iy.js → dist-6CVKuTAe.js} +1 -1
  250. ksadk/server/static/assets/{dist-8EEyGgDx.js → dist-BUHRxvDG.js} +1 -1
  251. ksadk/server/static/assets/{dist-B0NP_Z0z.js → dist-BZ9n9AjO.js} +1 -1
  252. ksadk/server/static/assets/{dist-DMezvBGJ.js → dist-BibcG1V9.js} +1 -1
  253. ksadk/server/static/assets/{dist-C3HIIaN5.js → dist-Bs-jQcRX.js} +1 -1
  254. ksadk/server/static/assets/{dist-BrCcQ47T.js → dist-C2xjE7cO.js} +1 -1
  255. ksadk/server/static/assets/{dist-Dp0k7bWI.js → dist-C7-3jInC.js} +1 -1
  256. ksadk/server/static/assets/{dist-D-xOD048.js → dist-C99THtIA.js} +1 -1
  257. ksadk/server/static/assets/{dist-CkEKJFtk.js → dist-CGcp2ex8.js} +1 -1
  258. ksadk/server/static/assets/{dist-DyOkZmze.js → dist-CVQRZjPu.js} +1 -1
  259. ksadk/server/static/assets/{dist-BssVmjIo.js → dist-Cf23NY4L.js} +1 -1
  260. ksadk/server/static/assets/{dist-BIJVDMuB.js → dist-CgF3fj15.js} +1 -1
  261. ksadk/server/static/assets/{dist-2hInLS_J.js → dist-Cwt7koer.js} +1 -1
  262. ksadk/server/static/assets/{dist-DyWsb78Q.js → dist-D82mtD2s.js} +1 -1
  263. ksadk/server/static/assets/{dist-D-JMdWPQ.js → dist-DF06ORQo.js} +1 -1
  264. ksadk/server/static/assets/{dist-BmlMPsCc.js → dist-DHn6nBzr.js} +1 -1
  265. ksadk/server/static/assets/{dist-gX6GOLKq.js → dist-Djgl2wVZ.js} +1 -1
  266. ksadk/server/static/assets/{dist-DpKtt4Bo.js → dist-DlzCRy0S.js} +1 -1
  267. ksadk/server/static/assets/{dist-8_SfK1IP.js → dist-DqNnNFrw.js} +1 -1
  268. ksadk/server/static/assets/{dist-D57wnGWd.js → dist-DyvYLMW9.js} +1 -1
  269. ksadk/server/static/assets/{dist-CPBtqRTW.js → dist-eoW6tZXA.js} +1 -1
  270. ksadk/server/static/assets/{dist-DL_NKc_z.js → dist-ivOya1LD.js} +1 -1
  271. ksadk/server/static/assets/{erDiagram-TEJ5UH35-Bk-9bgE5.js → erDiagram-TEJ5UH35-CnfRcY2M.js} +1 -1
  272. ksadk/server/static/assets/eventmodeling-FCH6USID-ChYO-ijM.js +1 -0
  273. ksadk/server/static/assets/{flowDiagram-I6XJVG4X-Dn9kZVuZ.js → flowDiagram-I6XJVG4X-DGaJjGNJ.js} +1 -1
  274. ksadk/server/static/assets/{ganttDiagram-6RSMTGT7-BGxXlJqm.js → ganttDiagram-6RSMTGT7-DpCoB2g9.js} +1 -1
  275. ksadk/server/static/assets/gitGraph-WXDBUCRP-BN_0Fk-j.js +1 -0
  276. ksadk/server/static/assets/{gitGraphDiagram-PVQCEYII-C7Q0X-wi.js → gitGraphDiagram-PVQCEYII-9IKVFBVT.js} +1 -1
  277. ksadk/server/static/assets/index-QSwCHuB8.js +177 -0
  278. ksadk/server/static/assets/index-jOPmTOZH.css +2 -0
  279. ksadk/server/static/assets/info-J43DQDTF-Cp6o3vId.js +1 -0
  280. ksadk/server/static/assets/{infoDiagram-5YYISTIA-BO_CSqq5.js → infoDiagram-5YYISTIA-CYIIsb8y.js} +1 -1
  281. ksadk/server/static/assets/{ishikawaDiagram-YF4QCWOH-eYLPLd46.js → ishikawaDiagram-YF4QCWOH-DLOHGvWw.js} +1 -1
  282. ksadk/server/static/assets/{journeyDiagram-JHISSGLW-De9geSb0.js → journeyDiagram-JHISSGLW-BIzKeejT.js} +1 -1
  283. ksadk/server/static/assets/{kanban-definition-UN3LZRKU-Cs80kQto.js → kanban-definition-UN3LZRKU-BWHoFSw2.js} +1 -1
  284. ksadk/server/static/assets/{katex-DSrCFD8n.js → katex-DATssjp1.js} +1 -1
  285. ksadk/server/static/assets/{linear-CN9sbKTF.js → linear-CvMBw9cA.js} +1 -1
  286. ksadk/server/static/assets/{mermaid-parser.core-DlgSBU8l.js → mermaid-parser.core-mGAcEwcq.js} +2 -2
  287. ksadk/server/static/assets/{mindmap-definition-RKZ34NQL-9afz7Oug.js → mindmap-definition-RKZ34NQL-CSAQxEAe.js} +1 -1
  288. ksadk/server/static/assets/packet-YPE3B663-wQzct3cT.js +1 -0
  289. ksadk/server/static/assets/pie-LRSECV5Y-BgTQiv-9.js +1 -0
  290. ksadk/server/static/assets/{pieDiagram-4H26LBE5-DPv_VstN.js → pieDiagram-4H26LBE5-By-ra07M.js} +1 -1
  291. ksadk/server/static/assets/{quadrantDiagram-W4KKPZXB-o77wZ1XK.js → quadrantDiagram-W4KKPZXB-CxIR4JXI.js} +1 -1
  292. ksadk/server/static/assets/radar-GUYGQ44K-BIq5fXsn.js +1 -0
  293. ksadk/server/static/assets/{requirementDiagram-4Y6WPE33-BYVw81VC.js → requirementDiagram-4Y6WPE33-DpW90iu3.js} +1 -1
  294. ksadk/server/static/assets/{sankeyDiagram-5OEKKPKP-B7nZFMKT.js → sankeyDiagram-5OEKKPKP-DpGa6EAV.js} +1 -1
  295. ksadk/server/static/assets/{sequenceDiagram-3UESZ5HK-BGRRrFw5.js → sequenceDiagram-3UESZ5HK-NTKNGGe5.js} +1 -1
  296. ksadk/server/static/assets/{stateDiagram-AJRCARHV-BUfHCoPs.js → stateDiagram-AJRCARHV-DGpd9yFG.js} +1 -1
  297. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-B3o579IQ.js +1 -0
  298. ksadk/server/static/assets/{timeline-definition-PNZ67QCA-FbCTGrf9.js → timeline-definition-PNZ67QCA-jqoYs3jQ.js} +1 -1
  299. ksadk/server/static/assets/treeView-BLDUP644-Dqi-E0EM.js +1 -0
  300. ksadk/server/static/assets/treemap-LRROVOQU-ClQP9CJ9.js +1 -0
  301. ksadk/server/static/assets/{vennDiagram-CIIHVFJN-DWgwtPsJ.js → vennDiagram-CIIHVFJN-l3Z7-wbP.js} +1 -1
  302. ksadk/server/static/assets/wardley-L42UT6IY-8XLvnNIs.js +1 -0
  303. ksadk/server/static/assets/{wardleyDiagram-YWT4CUSO-2x8G-tTM.js → wardleyDiagram-YWT4CUSO-BR54GPmr.js} +1 -1
  304. ksadk/server/static/assets/{xychartDiagram-2RQKCTM6-Drma3AYl.js → xychartDiagram-2RQKCTM6-SkiH8GsK.js} +1 -1
  305. ksadk/server/static/index.html +2 -2
  306. ksadk/server/terminal_sessions.py +111 -58
  307. ksadk/sessions/__init__.py +69 -19
  308. ksadk/sessions/base.py +31 -11
  309. ksadk/sessions/continuity.py +2 -3
  310. ksadk/sessions/in_memory.py +46 -2
  311. ksadk/sessions/local_service.py +148 -17
  312. ksadk/sessions/postgres_service.py +143 -25
  313. ksadk/sessions/resilient.py +36 -8
  314. ksadk/skills/models.py +17 -5
  315. ksadk/skills/package_store.py +5 -2
  316. ksadk/skills/runtime/agent.py +20 -5
  317. ksadk/skills/runtime/artifacts.py +1 -5
  318. ksadk/skills/runtime/backends/e2b.py +10 -4
  319. ksadk/skills/runtime/backends/local.py +15 -3
  320. ksadk/skills/runtime/base.py +1 -2
  321. ksadk/skills/runtime/executor.py +10 -3
  322. ksadk/skills/runtime/factory.py +4 -2
  323. ksadk/skills/runtime/loader.py +1 -2
  324. ksadk/skills/runtime/registry.py +15 -10
  325. ksadk/skills/runtime/request.py +3 -1
  326. ksadk/skills/service_client.py +38 -17
  327. ksadk/skills/tool_defs.py +15 -10
  328. ksadk/terminal_exec_policy.py +3 -4
  329. ksadk/tools/gateway.py +92 -15
  330. ksadk/tools/result_budget.py +12 -4
  331. ksadk/toolsets/__init__.py +134 -36
  332. ksadk/toolsets/platform.py +21 -5
  333. ksadk/toolsets/sandbox.py +82 -16
  334. ksadk/toolsets/skills.py +200 -39
  335. ksadk/toolsets/web.py +123 -26
  336. ksadk/toolsets/workspace.py +212 -101
  337. ksadk/tracing/exporters/inmemory_exporter.py +62 -51
  338. ksadk/tracing/exporters/langfuse_exporter.py +91 -76
  339. ksadk/tracing/setup.py +69 -53
  340. ksadk/tracing/span_utils.py +5 -2
  341. ksadk/tui/loop.py +78 -30
  342. ksadk/tui/stream_render.py +1 -0
  343. ksadk/ui_config.py +5 -3
  344. ksadk/version.py +1 -1
  345. ksadk_runtime_common/schemas/runtime_event_v1.json +95 -0
  346. agentengine_sdk_python-0.7.0.dist-info/RECORD +0 -482
  347. ksadk/server/static/assets/CodeBlock-P16VOLYi.js +0 -9
  348. ksadk/server/static/assets/MathMessageMarkdown-CdGiQWHR.js +0 -8
  349. ksadk/server/static/assets/MermaidBlock-IOcal8cm.js +0 -303
  350. ksadk/server/static/assets/NativeTerminalPanel-DGSDWsei.js +0 -1
  351. ksadk/server/static/assets/architecture-7EHR7CIX-BvUlsA6l.js +0 -1
  352. ksadk/server/static/assets/channel-CTuydARX.js +0 -1
  353. ksadk/server/static/assets/chunk-QZHKN3VN-BnCydivS.js +0 -1
  354. ksadk/server/static/assets/classDiagram-4FO5ZUOK-BNHg45Be.js +0 -1
  355. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-BNHg45Be.js +0 -1
  356. ksadk/server/static/assets/eventmodeling-FCH6USID-DsAgWnlf.js +0 -1
  357. ksadk/server/static/assets/gitGraph-WXDBUCRP-BIao9Yjg.js +0 -1
  358. ksadk/server/static/assets/index-C00Lwg3L.js +0 -165
  359. ksadk/server/static/assets/index-DAURbCsP.css +0 -1
  360. ksadk/server/static/assets/info-J43DQDTF-CyipqGxU.js +0 -1
  361. ksadk/server/static/assets/packet-YPE3B663-CGkyRxlg.js +0 -1
  362. ksadk/server/static/assets/pie-LRSECV5Y-M0uWAf4n.js +0 -1
  363. ksadk/server/static/assets/radar-GUYGQ44K-Bdbm24-x.js +0 -1
  364. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-8xBN_gLM.js +0 -1
  365. ksadk/server/static/assets/treeView-BLDUP644-npMo0ak1.js +0 -1
  366. ksadk/server/static/assets/treemap-LRROVOQU-CHdzrrdo.js +0 -1
  367. ksadk/server/static/assets/wardley-L42UT6IY-BEQz7wyy.js +0 -1
  368. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/WHEEL +0 -0
  369. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/entry_points.txt +0 -0
  370. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/licenses/LICENSE +0 -0
  371. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/top_level.txt +0 -0
@@ -23,19 +23,19 @@
23
23
  import json
24
24
  import logging
25
25
  import os
26
- from typing import Any, List, Literal
26
+ from typing import Any, List, Literal, Optional, cast
27
27
 
28
- from google.adk.events.event import Event
29
- from google.adk.memory.base_memory_service import (
28
+ from pydantic import BaseModel, ConfigDict, Field, PrivateAttr
29
+ from typing_extensions import Union, override
30
+
31
+ from ksadk.compat.adk_compat import (
30
32
  BaseMemoryService,
33
+ Event,
34
+ MemoryEntry,
31
35
  SearchMemoryResponse,
36
+ Session,
32
37
  )
33
- from google.adk.memory.memory_entry import MemoryEntry
34
- from google.adk.sessions import Session
35
- from google.genai import types
36
- from pydantic import BaseModel, ConfigDict, Field
37
- from typing_extensions import Union, override
38
-
38
+ from ksadk.compat.adk_compat import genai_types as types
39
39
  from ksadk.memory.adk.backends.base_ltm_backend import BaseLongTermMemoryBackend
40
40
  from ksadk.memory.service import LongTermMemoryService
41
41
 
@@ -83,8 +83,8 @@ class LongTermMemory(BaseMemoryService, BaseModel):
83
83
  index: str = ""
84
84
  app_name: str = ""
85
85
 
86
- _backend: BaseLongTermMemoryBackend = None
87
- _service: LongTermMemoryService = None
86
+ _backend: Optional[BaseLongTermMemoryBackend] = PrivateAttr(default=None)
87
+ _service: Optional[LongTermMemoryService] = PrivateAttr(default=None)
88
88
 
89
89
  model_config = ConfigDict(arbitrary_types_allowed=True)
90
90
 
@@ -105,14 +105,18 @@ class LongTermMemory(BaseMemoryService, BaseModel):
105
105
  )
106
106
 
107
107
  def _get_service(self) -> LongTermMemoryService:
108
- if self._service is None:
108
+ service = self._service
109
+ if service is None:
109
110
  self.model_post_init(None)
110
- if self._backend is not None and self._service._backend is not self._backend:
111
- self._service.backend = self._backend
112
- self._service._backend = self._backend
113
- self._service.index = getattr(self._backend, "index", self._service.index)
114
- self.index = self._service.index
115
- return self._service
111
+ service = self._service
112
+ if service is None:
113
+ raise RuntimeError("LongTermMemory service initialization failed")
114
+ if self._backend is not None and service._backend is not self._backend:
115
+ service.backend = self._backend
116
+ service._backend = self._backend
117
+ service.index = getattr(self._backend, "index", service.index)
118
+ self.index = service.index
119
+ return service
116
120
 
117
121
  def _filter_and_convert_events(self, events: List[Event]) -> List[str]:
118
122
  """过滤并序列化 session 事件
@@ -157,9 +161,7 @@ class LongTermMemory(BaseMemoryService, BaseModel):
157
161
  event_strings = self._filter_and_convert_events(session.events)
158
162
 
159
163
  if not event_strings:
160
- logger.info(
161
- f"No user events to save for session={session.id}"
162
- )
164
+ logger.info(f"No user events to save for session={session.id}")
163
165
  return
164
166
 
165
167
  logger.info(
@@ -200,9 +202,7 @@ class LongTermMemory(BaseMemoryService, BaseModel):
200
202
  query=query, top_k=self.top_k, user_id=user_id
201
203
  )
202
204
  except Exception as e:
203
- logger.error(
204
- f"Error during memory search: {e}. Returning empty results."
205
- )
205
+ logger.error(f"Error during memory search: {e}. Returning empty results.")
206
206
 
207
207
  # 转换为 MemoryEntry 格式
208
208
  memory_events = []
@@ -213,9 +213,7 @@ class LongTermMemory(BaseMemoryService, BaseModel):
213
213
  text = memory_dict["parts"][0]["text"]
214
214
  role = memory_dict.get("role", "user")
215
215
  except (KeyError, IndexError):
216
- logger.warning(
217
- f"Non-standard memory format: {memory[:100]}. Skipping."
218
- )
216
+ logger.warning(f"Non-standard memory format: {memory[:100]}. Skipping.")
219
217
  continue
220
218
  except json.JSONDecodeError:
221
219
  # 非 JSON 格式的记忆字符串,直接作为 text
@@ -225,9 +223,7 @@ class LongTermMemory(BaseMemoryService, BaseModel):
225
223
  memory_events.append(
226
224
  MemoryEntry(
227
225
  author="user",
228
- content=types.Content(
229
- parts=[types.Part(text=text)], role=role
230
- ),
226
+ content=types.Content(parts=[types.Part(text=text)], role=role),
231
227
  )
232
228
  )
233
229
 
@@ -256,16 +252,16 @@ class LongTermMemory(BaseMemoryService, BaseModel):
256
252
  KSADK_LTM_INDEX: 索引名称
257
253
  """
258
254
  service = LongTermMemoryService.from_env(app_name=app_name, backend=backend)
259
- backend_name = (
260
- backend
261
- or os.environ.get("KSADK_LTM_BACKEND", "local")
262
- )
255
+ backend_name = backend or os.environ.get("KSADK_LTM_BACKEND", "local")
263
256
  backend_config = dict(service.backend_config)
264
257
  if "index" in backend_config and backend_name != "local":
265
258
  backend_config.pop("index", None)
266
259
 
260
+ if backend_name not in {"local", "http", "sdk"}:
261
+ raise ValueError(f"Unsupported long-term memory backend: {backend_name}")
262
+ normalized_backend = cast(Literal["local", "http", "sdk"], backend_name)
267
263
  return cls(
268
- backend=backend_name,
264
+ backend=normalized_backend,
269
265
  backend_config=backend_config,
270
266
  top_k=service.top_k,
271
267
  index=service.index,
@@ -4,15 +4,14 @@ import asyncio
4
4
  import logging
5
5
  from typing import Any, Optional
6
6
 
7
- from google.adk.events.event import Event
8
- from google.adk.sessions import InMemorySessionService
9
- from google.adk.sessions.base_session_service import (
7
+ from ksadk.compat.adk_compat import (
10
8
  BaseSessionService,
9
+ Event,
11
10
  GetSessionConfig,
11
+ InMemorySessionService,
12
12
  ListSessionsResponse,
13
+ Session,
13
14
  )
14
- from google.adk.sessions.session import Session
15
-
16
15
  from ksadk.sessions.resilience import is_session_backend_failure
17
16
 
18
17
  logger = logging.getLogger(__name__)
@@ -24,14 +24,15 @@
24
24
 
25
25
  import logging
26
26
  import os
27
- from typing import Any, Literal, Optional
27
+ from typing import Any, Literal, Optional, cast
28
28
 
29
- from google.adk.sessions import (
29
+ from pydantic import BaseModel, PrivateAttr
30
+
31
+ from ksadk.compat.adk_compat import (
30
32
  BaseSessionService,
31
33
  InMemorySessionService,
32
34
  Session,
33
35
  )
34
- from pydantic import BaseModel, PrivateAttr
35
36
 
36
37
  logger = logging.getLogger(__name__)
37
38
 
@@ -119,14 +120,9 @@ class ShortTermMemory(BaseModel):
119
120
  logger.info("ShortTermMemory: using InMemorySessionService")
120
121
 
121
122
  case "sqlite":
122
- db_url = _normalize_database_url(
123
- f"sqlite:///{self.local_database_path}"
124
- )
123
+ db_url = _normalize_database_url(f"sqlite:///{self.local_database_path}")
125
124
  self._init_database_service(db_url)
126
- logger.info(
127
- f"ShortTermMemory: using SQLite at "
128
- f"{self.local_database_path}"
129
- )
125
+ logger.info(f"ShortTermMemory: using SQLite at " f"{self.local_database_path}")
130
126
 
131
127
  case "database":
132
128
  if not self.db_url:
@@ -148,8 +144,7 @@ class ShortTermMemory(BaseModel):
148
144
  """初始化数据库 SessionService"""
149
145
  normalized_db_url = _normalize_database_url(db_url)
150
146
  try:
151
- from google.adk.sessions import DatabaseSessionService
152
-
147
+ from ksadk.compat.adk_compat import DatabaseSessionService
153
148
  from ksadk.memory.adk.resilient_session_service import ResilientADKSessionService
154
149
  from ksadk.sessions.resilience import session_backend_timeout_seconds
155
150
 
@@ -165,8 +160,7 @@ class ShortTermMemory(BaseModel):
165
160
  DatabaseSessionService(db_url=normalized_db_url, **service_kwargs)
166
161
  )
167
162
  logger.info(
168
- f"ShortTermMemory: using DatabaseSessionService "
169
- f"({normalized_db_url[:30]}...)"
163
+ f"ShortTermMemory: using DatabaseSessionService " f"({normalized_db_url[:30]}...)"
170
164
  )
171
165
  except ImportError:
172
166
  logger.warning(
@@ -218,8 +212,7 @@ class ShortTermMemory(BaseModel):
218
212
  )
219
213
  if session:
220
214
  logger.debug(
221
- f"Session {session_id} already exists "
222
- f"(app={app_name}, user={user_id})"
215
+ f"Session {session_id} already exists " f"(app={app_name}, user={user_id})"
223
216
  )
224
217
  return session
225
218
  except Exception as e:
@@ -238,10 +231,7 @@ class ShortTermMemory(BaseModel):
238
231
  app_name=app_name,
239
232
  user_id=user_id,
240
233
  )
241
- logger.info(
242
- f"Created session: id={session.id}, "
243
- f"app={app_name}, user={user_id}"
244
- )
234
+ logger.info(f"Created session: id={session.id}, " f"app={app_name}, user={user_id}")
245
235
  return session
246
236
  except Exception as e:
247
237
  logger.error(f"Failed to create session: {e}")
@@ -297,8 +287,9 @@ class ShortTermMemory(BaseModel):
297
287
  else:
298
288
  backend = "local"
299
289
 
290
+ backend_name = cast(Literal["local", "sqlite", "database"], backend)
300
291
  return cls(
301
- backend=backend,
292
+ backend=backend_name,
302
293
  db_url=db_url,
303
294
  local_database_path=db_path,
304
295
  )
ksadk/memory/adk_tool.py CHANGED
@@ -21,11 +21,12 @@ def save_memory(content: str) -> dict:
21
21
 
22
22
  def create_adk_tool():
23
23
  try:
24
- from google.adk.tools import FunctionTool
24
+ from ksadk.compat.adk_compat import FunctionTool
25
25
 
26
26
  return FunctionTool(func=save_memory)
27
27
  except ImportError:
28
28
  logger.warning(
29
- "google-adk not installed, returning raw function as tool. Install with: pip install ksadk[adk]"
29
+ "google-adk not installed, returning raw function as tool. "
30
+ "Install with: pip install ksadk[adk]"
30
31
  )
31
32
  return save_memory
@@ -1,29 +1,29 @@
1
1
  """Base Memory Backend - 抽象基类"""
2
2
 
3
3
  from abc import ABC, abstractmethod
4
- from typing import Any, Optional, List, Dict
5
4
  from datetime import timedelta
5
+ from typing import Any, Dict, List, Optional
6
6
 
7
7
 
8
8
  class BaseMemoryBackend(ABC):
9
9
  """记忆存储后端抽象基类
10
-
10
+
11
11
  所有后端实现必须继承此类并实现以下方法。
12
12
  """
13
-
13
+
14
14
  @abstractmethod
15
15
  def get(self, key: str, session_id: Optional[str] = None) -> Optional[Any]:
16
16
  """获取值
17
-
17
+
18
18
  Args:
19
19
  key: 键名
20
20
  session_id: 可选的会话 ID,用于隔离不同会话的数据
21
-
21
+
22
22
  Returns:
23
23
  存储的值,不存在返回 None
24
24
  """
25
25
  pass
26
-
26
+
27
27
  @abstractmethod
28
28
  def set(
29
29
  self,
@@ -33,43 +33,43 @@ class BaseMemoryBackend(ABC):
33
33
  ttl: Optional[timedelta] = None,
34
34
  ) -> bool:
35
35
  """设置值
36
-
36
+
37
37
  Args:
38
38
  key: 键名
39
39
  value: 值 (会自动序列化)
40
40
  session_id: 可选的会话 ID
41
41
  ttl: 可选的过期时间
42
-
42
+
43
43
  Returns:
44
44
  是否成功
45
45
  """
46
46
  pass
47
-
47
+
48
48
  @abstractmethod
49
49
  def delete(self, key: str, session_id: Optional[str] = None) -> bool:
50
50
  """删除键
51
-
51
+
52
52
  Args:
53
53
  key: 键名
54
54
  session_id: 可选的会话 ID
55
-
55
+
56
56
  Returns:
57
57
  是否成功
58
58
  """
59
59
  pass
60
-
60
+
61
61
  @abstractmethod
62
62
  def exists(self, key: str, session_id: Optional[str] = None) -> bool:
63
63
  """检查键是否存在"""
64
64
  pass
65
-
65
+
66
66
  @abstractmethod
67
67
  def clear_session(self, session_id: str) -> bool:
68
68
  """清除整个会话的所有数据"""
69
69
  pass
70
-
70
+
71
71
  # ===== 消息历史相关 (短期记忆) =====
72
-
72
+
73
73
  @abstractmethod
74
74
  def add_message(
75
75
  self,
@@ -80,7 +80,7 @@ class BaseMemoryBackend(ABC):
80
80
  ) -> bool:
81
81
  """添加消息到会话历史"""
82
82
  pass
83
-
83
+
84
84
  @abstractmethod
85
85
  def get_messages(
86
86
  self,
@@ -88,16 +88,16 @@ class BaseMemoryBackend(ABC):
88
88
  limit: Optional[int] = None,
89
89
  ) -> List[Dict]:
90
90
  """获取会话消息历史
91
-
91
+
92
92
  Args:
93
93
  session_id: 会话 ID
94
94
  limit: 最近 N 条消息,None 表示全部
95
-
95
+
96
96
  Returns:
97
97
  消息列表 [{role, content, timestamp, ...}]
98
98
  """
99
99
  pass
100
-
100
+
101
101
  def close(self) -> None:
102
102
  """关闭连接 (可选实现)"""
103
103
  pass
@@ -1,49 +1,48 @@
1
1
  """In-Memory Backend - 内存存储 (开发/测试用)"""
2
2
 
3
- import json
4
- from datetime import datetime, timedelta
5
- from typing import Any, Optional, List, Dict
6
3
  from collections import defaultdict
4
+ from datetime import datetime, timedelta
5
+ from typing import Any, Dict, List, Optional
7
6
 
8
7
  from ksadk.memory.backends.base import BaseMemoryBackend
9
8
 
10
9
 
11
10
  class InMemoryBackend(BaseMemoryBackend):
12
11
  """内存存储后端
13
-
12
+
14
13
  适用于开发和测试,数据在进程退出后丢失。
15
14
  """
16
-
15
+
17
16
  def __init__(self):
18
17
  # {session_id: {key: (value, expires_at)}}
19
18
  self._data: Dict[str, Dict[str, tuple]] = defaultdict(dict)
20
19
  # {session_id: [messages]}
21
20
  self._messages: Dict[str, List[Dict]] = defaultdict(list)
22
-
21
+
23
22
  def _make_key(self, key: str, session_id: Optional[str]) -> tuple:
24
23
  """生成复合键"""
25
24
  sid = session_id or "__global__"
26
25
  return sid, key
27
-
26
+
28
27
  def _is_expired(self, expires_at: Optional[datetime]) -> bool:
29
28
  if expires_at is None:
30
29
  return False
31
30
  return datetime.utcnow() > expires_at
32
-
31
+
33
32
  def get(self, key: str, session_id: Optional[str] = None) -> Optional[Any]:
34
33
  sid, k = self._make_key(key, session_id)
35
-
34
+
36
35
  if sid not in self._data or k not in self._data[sid]:
37
36
  return None
38
-
37
+
39
38
  value, expires_at = self._data[sid][k]
40
-
39
+
41
40
  if self._is_expired(expires_at):
42
41
  del self._data[sid][k]
43
42
  return None
44
-
43
+
45
44
  return value
46
-
45
+
47
46
  def set(
48
47
  self,
49
48
  key: str,
@@ -52,32 +51,32 @@ class InMemoryBackend(BaseMemoryBackend):
52
51
  ttl: Optional[timedelta] = None,
53
52
  ) -> bool:
54
53
  sid, k = self._make_key(key, session_id)
55
-
54
+
56
55
  expires_at = None
57
56
  if ttl:
58
57
  expires_at = datetime.utcnow() + ttl
59
-
58
+
60
59
  self._data[sid][k] = (value, expires_at)
61
60
  return True
62
-
61
+
63
62
  def delete(self, key: str, session_id: Optional[str] = None) -> bool:
64
63
  sid, k = self._make_key(key, session_id)
65
-
64
+
66
65
  if sid in self._data and k in self._data[sid]:
67
66
  del self._data[sid][k]
68
67
  return True
69
68
  return False
70
-
69
+
71
70
  def exists(self, key: str, session_id: Optional[str] = None) -> bool:
72
71
  return self.get(key, session_id) is not None
73
-
72
+
74
73
  def clear_session(self, session_id: str) -> bool:
75
74
  if session_id in self._data:
76
75
  del self._data[session_id]
77
76
  if session_id in self._messages:
78
77
  del self._messages[session_id]
79
78
  return True
80
-
79
+
81
80
  def add_message(
82
81
  self,
83
82
  session_id: str,
@@ -85,28 +84,28 @@ class InMemoryBackend(BaseMemoryBackend):
85
84
  content: str,
86
85
  metadata: Optional[Dict] = None,
87
86
  ) -> bool:
88
- msg = {
87
+ msg: Dict[str, Any] = {
89
88
  "role": role,
90
89
  "content": content,
91
90
  "timestamp": datetime.utcnow().isoformat() + "Z",
92
91
  }
93
92
  if metadata:
94
93
  msg["metadata"] = metadata
95
-
94
+
96
95
  self._messages[session_id].append(msg)
97
96
  return True
98
-
97
+
99
98
  def get_messages(
100
99
  self,
101
100
  session_id: str,
102
101
  limit: Optional[int] = None,
103
102
  ) -> List[Dict]:
104
103
  messages = self._messages.get(session_id, [])
105
-
104
+
106
105
  if limit:
107
106
  return messages[-limit:]
108
107
  return messages.copy()
109
-
108
+
110
109
  def close(self) -> None:
111
110
  self._data.clear()
112
111
  self._messages.clear()
@@ -2,20 +2,20 @@
2
2
 
3
3
  import json
4
4
  from datetime import datetime, timedelta
5
- from typing import Any, Optional, List, Dict
5
+ from typing import Any, Dict, List, Optional
6
6
 
7
7
  from ksadk.memory.backends.base import BaseMemoryBackend
8
8
 
9
9
 
10
10
  class RedisBackend(BaseMemoryBackend):
11
11
  """Redis 存储后端
12
-
12
+
13
13
  适用于短期记忆和会话状态存储。
14
-
14
+
15
15
  使用示例:
16
16
  backend = RedisBackend(url="redis://localhost:6379/0")
17
17
  """
18
-
18
+
19
19
  def __init__(
20
20
  self,
21
21
  url: str = "redis://localhost:6379/0",
@@ -26,39 +26,40 @@ class RedisBackend(BaseMemoryBackend):
26
26
  self.prefix = prefix
27
27
  self.default_ttl = default_ttl
28
28
  self._client = None
29
-
29
+
30
30
  @property
31
31
  def client(self):
32
32
  """懒加载 Redis 客户端"""
33
33
  if self._client is None:
34
34
  try:
35
35
  import redis
36
+
36
37
  self._client = redis.from_url(self.url, decode_responses=True)
37
38
  except ImportError:
38
39
  raise ImportError("redis package required. Install with: pip install redis")
39
40
  return self._client
40
-
41
+
41
42
  def _make_key(self, key: str, session_id: Optional[str]) -> str:
42
43
  """生成 Redis 键"""
43
44
  if session_id:
44
45
  return f"{self.prefix}session:{session_id}:{key}"
45
46
  return f"{self.prefix}global:{key}"
46
-
47
+
47
48
  def _messages_key(self, session_id: str) -> str:
48
49
  return f"{self.prefix}messages:{session_id}"
49
-
50
+
50
51
  def get(self, key: str, session_id: Optional[str] = None) -> Optional[Any]:
51
52
  redis_key = self._make_key(key, session_id)
52
53
  value = self.client.get(redis_key)
53
-
54
+
54
55
  if value is None:
55
56
  return None
56
-
57
+
57
58
  try:
58
59
  return json.loads(value)
59
60
  except json.JSONDecodeError:
60
61
  return value
61
-
62
+
62
63
  def set(
63
64
  self,
64
65
  key: str,
@@ -67,40 +68,40 @@ class RedisBackend(BaseMemoryBackend):
67
68
  ttl: Optional[timedelta] = None,
68
69
  ) -> bool:
69
70
  redis_key = self._make_key(key, session_id)
70
-
71
+
71
72
  # 序列化
72
73
  if not isinstance(value, str):
73
74
  value = json.dumps(value, ensure_ascii=False)
74
-
75
+
75
76
  # 设置过期时间
76
77
  ex = None
77
78
  if ttl:
78
79
  ex = int(ttl.total_seconds())
79
80
  elif self.default_ttl:
80
81
  ex = int(self.default_ttl.total_seconds())
81
-
82
+
82
83
  self.client.set(redis_key, value, ex=ex)
83
84
  return True
84
-
85
+
85
86
  def delete(self, key: str, session_id: Optional[str] = None) -> bool:
86
87
  redis_key = self._make_key(key, session_id)
87
- return self.client.delete(redis_key) > 0
88
-
88
+ return bool(self.client.delete(redis_key) > 0)
89
+
89
90
  def exists(self, key: str, session_id: Optional[str] = None) -> bool:
90
91
  redis_key = self._make_key(key, session_id)
91
- return self.client.exists(redis_key) > 0
92
-
92
+ return bool(self.client.exists(redis_key) > 0)
93
+
93
94
  def clear_session(self, session_id: str) -> bool:
94
95
  pattern = f"{self.prefix}session:{session_id}:*"
95
96
  keys = list(self.client.scan_iter(match=pattern))
96
-
97
+
97
98
  # 也删除消息
98
99
  keys.append(self._messages_key(session_id))
99
-
100
+
100
101
  if keys:
101
102
  self.client.delete(*keys)
102
103
  return True
103
-
104
+
104
105
  def add_message(
105
106
  self,
106
107
  session_id: str,
@@ -108,38 +109,38 @@ class RedisBackend(BaseMemoryBackend):
108
109
  content: str,
109
110
  metadata: Optional[Dict] = None,
110
111
  ) -> bool:
111
- msg = {
112
+ msg: dict[str, Any] = {
112
113
  "role": role,
113
114
  "content": content,
114
115
  "timestamp": datetime.utcnow().isoformat() + "Z",
115
116
  }
116
117
  if metadata:
117
118
  msg["metadata"] = metadata
118
-
119
+
119
120
  redis_key = self._messages_key(session_id)
120
121
  self.client.rpush(redis_key, json.dumps(msg, ensure_ascii=False))
121
-
122
+
122
123
  # 可以设置消息历史的过期时间
123
124
  if self.default_ttl:
124
125
  self.client.expire(redis_key, int(self.default_ttl.total_seconds()))
125
-
126
+
126
127
  return True
127
-
128
+
128
129
  def get_messages(
129
130
  self,
130
131
  session_id: str,
131
132
  limit: Optional[int] = None,
132
133
  ) -> List[Dict]:
133
134
  redis_key = self._messages_key(session_id)
134
-
135
+
135
136
  if limit:
136
137
  # 获取最后 N 条
137
138
  raw = self.client.lrange(redis_key, -limit, -1)
138
139
  else:
139
140
  raw = self.client.lrange(redis_key, 0, -1)
140
-
141
+
141
142
  return [json.loads(m) for m in raw]
142
-
143
+
143
144
  def close(self) -> None:
144
145
  if self._client:
145
146
  self._client.close()
@@ -31,7 +31,8 @@ def create_langchain_tools():
31
31
  return load_memory_tool, save_memory_tool
32
32
  except ImportError:
33
33
  logger.warning(
34
- "langchain-core not installed, returning raw functions. Install with: pip install langchain-core"
34
+ "langchain-core not installed, returning raw functions. "
35
+ "Install with: pip install langchain-core"
35
36
  )
36
37
  return _load_memory, _save_memory
37
38