agentengine-sdk-python 0.6.9__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 (384) hide show
  1. {agentengine_sdk_python-0.6.9.dist-info → agentengine_sdk_python-0.8.0.dist-info}/METADATA +41 -23
  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 +252 -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 +533 -726
  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 +173 -90
  54. ksadk/cli/cmd_invoke.py +388 -159
  55. ksadk/cli/cmd_launch.py +64 -28
  56. ksadk/cli/cmd_mcp.py +103 -64
  57. ksadk/cli/cmd_model.py +14 -5
  58. ksadk/cli/cmd_openclaw.py +488 -228
  59. ksadk/cli/cmd_replay.py +71 -0
  60. ksadk/cli/cmd_run.py +44 -14
  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 +38 -16
  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 +501 -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 +656 -0
  97. ksadk/conversations/model_context.py +22 -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 -5187
  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 +52 -39
  120. ksadk/deployment/manager.py +63 -65
  121. ksadk/deployment/providers/serverless.py +326 -209
  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 +267 -0
  156. ksadk/memory/adk/short_term_memory.py +33 -27
  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 +1248 -164
  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 -530
  183. ksadk/runners/langgraph_runner.py +490 -95
  184. ksadk/runners/patch_langchain.py +16 -16
  185. ksadk/runners/remote_runner.py +264 -38
  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 -3743
  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-C0meuOdi.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-bj2rZnP5.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-2u1ltDIj.js → architectureDiagram-3BPJPVTR-Dej8jX8c.js} +1 -1
  229. ksadk/server/static/assets/{blockDiagram-GPEHLZMM-D6fvdK20.js → blockDiagram-GPEHLZMM-1F64jqvy.js} +1 -1
  230. ksadk/server/static/assets/{c4Diagram-AAUBKEIU-BK82L5n5.js → c4Diagram-AAUBKEIU-9q7AUAKb.js} +1 -1
  231. ksadk/server/static/assets/channel-iUGv2N24.js +1 -0
  232. ksadk/server/static/assets/{chunk-2J33WTMH-DLVdkeyQ.js → chunk-2J33WTMH-6qgwJm7Q.js} +1 -1
  233. ksadk/server/static/assets/{chunk-4BX2VUAB-BbwsYcbW.js → chunk-4BX2VUAB-CsWIQRhc.js} +1 -1
  234. ksadk/server/static/assets/{chunk-55IACEB6-DOairxzw.js → chunk-55IACEB6-BK8paA20.js} +1 -1
  235. ksadk/server/static/assets/{chunk-727SXJPM-hCO487gs.js → chunk-727SXJPM-B-JEhy7h.js} +1 -1
  236. ksadk/server/static/assets/{chunk-AQP2D5EJ-XU8vDOuG.js → chunk-AQP2D5EJ-DYBvMHAa.js} +1 -1
  237. ksadk/server/static/assets/{chunk-FMBD7UC4-PrapyfMu.js → chunk-FMBD7UC4-BGhvzDYt.js} +1 -1
  238. ksadk/server/static/assets/{chunk-ND2GUHAM-CboKhTZ3.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-_N8bJ-EU.js → cose-bilkent-S5V4N54A-CX3yotHq.js} +1 -1
  243. ksadk/server/static/assets/{dagre-BM42HDAG-FoDlo5J2.js → dagre-BM42HDAG-C7TguAWo.js} +1 -1
  244. ksadk/server/static/assets/{diagram-2AECGRRQ-BBp6ebBw.js → diagram-2AECGRRQ-Dd17_kws.js} +1 -1
  245. ksadk/server/static/assets/{diagram-5GNKFQAL-CqOvG1PR.js → diagram-5GNKFQAL-DVIClIil.js} +1 -1
  246. ksadk/server/static/assets/{diagram-KO2AKTUF-O9T3t6ba.js → diagram-KO2AKTUF-Df_3gYQa.js} +1 -1
  247. ksadk/server/static/assets/{diagram-LMA3HP47-CGG8ekBO.js → diagram-LMA3HP47-BhLk6ZtA.js} +1 -1
  248. ksadk/server/static/assets/{diagram-OG6HWLK6-4BmH1EEg.js → diagram-OG6HWLK6-D4GNGvuu.js} +1 -1
  249. ksadk/server/static/assets/{dist-CiZHB6ZW.js → dist-6CVKuTAe.js} +1 -1
  250. ksadk/server/static/assets/{dist-BMKM66B4.js → dist-BUHRxvDG.js} +1 -1
  251. ksadk/server/static/assets/{dist-CZ6C3x8B.js → dist-BZ9n9AjO.js} +1 -1
  252. ksadk/server/static/assets/{dist-DbaH3p5h.js → dist-BibcG1V9.js} +1 -1
  253. ksadk/server/static/assets/{dist-BVzcWa6D.js → dist-Bs-jQcRX.js} +1 -1
  254. ksadk/server/static/assets/{dist-D99wf6_X.js → dist-C2xjE7cO.js} +1 -1
  255. ksadk/server/static/assets/{dist-DLMjL01k.js → dist-C7-3jInC.js} +1 -1
  256. ksadk/server/static/assets/{dist-DI-oVAXw.js → dist-C99THtIA.js} +1 -1
  257. ksadk/server/static/assets/{dist-BkJjNih3.js → dist-CGcp2ex8.js} +1 -1
  258. ksadk/server/static/assets/{dist-D5JGcxBx.js → dist-CVQRZjPu.js} +1 -1
  259. ksadk/server/static/assets/{dist-CWiTDN_V.js → dist-Cf23NY4L.js} +1 -1
  260. ksadk/server/static/assets/{dist-DLeM1OCK.js → dist-CgF3fj15.js} +1 -1
  261. ksadk/server/static/assets/{dist-BmuTWcm7.js → dist-Cwt7koer.js} +1 -1
  262. ksadk/server/static/assets/{dist-C2DKRFVK.js → dist-D82mtD2s.js} +1 -1
  263. ksadk/server/static/assets/{dist-B67uF2uK.js → dist-DF06ORQo.js} +1 -1
  264. ksadk/server/static/assets/{dist-Cwhk4lwI.js → dist-DHn6nBzr.js} +1 -1
  265. ksadk/server/static/assets/{dist-S4klkK5W.js → dist-Djgl2wVZ.js} +1 -1
  266. ksadk/server/static/assets/{dist-DCpZrjaK.js → dist-DlzCRy0S.js} +1 -1
  267. ksadk/server/static/assets/{dist-Cp1_jKwf.js → dist-DqNnNFrw.js} +1 -1
  268. ksadk/server/static/assets/{dist-6kSZvCZh.js → dist-DyvYLMW9.js} +1 -1
  269. ksadk/server/static/assets/{dist-DM0rEQPk.js → dist-eoW6tZXA.js} +1 -1
  270. ksadk/server/static/assets/{dist-Bk1l05Ni.js → dist-ivOya1LD.js} +1 -1
  271. ksadk/server/static/assets/{erDiagram-TEJ5UH35-oJhaci7S.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-DtTmUan-.js → flowDiagram-I6XJVG4X-DGaJjGNJ.js} +1 -1
  274. ksadk/server/static/assets/{ganttDiagram-6RSMTGT7-BSsb_eij.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-BR5s6Pws.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-DYPc5cvh.js → infoDiagram-5YYISTIA-CYIIsb8y.js} +1 -1
  281. ksadk/server/static/assets/{ishikawaDiagram-YF4QCWOH-MoBdALDg.js → ishikawaDiagram-YF4QCWOH-DLOHGvWw.js} +1 -1
  282. ksadk/server/static/assets/{journeyDiagram-JHISSGLW-DgLiQT8l.js → journeyDiagram-JHISSGLW-BIzKeejT.js} +1 -1
  283. ksadk/server/static/assets/{kanban-definition-UN3LZRKU-CsFx112F.js → kanban-definition-UN3LZRKU-BWHoFSw2.js} +1 -1
  284. ksadk/server/static/assets/{katex-DRsiwpM2.js → katex-DATssjp1.js} +1 -1
  285. ksadk/server/static/assets/{linear-TNRQ5Orv.js → linear-CvMBw9cA.js} +1 -1
  286. ksadk/server/static/assets/{mermaid-parser.core-D2eMVOgo.js → mermaid-parser.core-mGAcEwcq.js} +2 -2
  287. ksadk/server/static/assets/{mindmap-definition-RKZ34NQL-BtByYFhL.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-DPnuCB8c.js → pieDiagram-4H26LBE5-By-ra07M.js} +1 -1
  291. ksadk/server/static/assets/{quadrantDiagram-W4KKPZXB-miFpCPv4.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-mjB_yYkW.js → requirementDiagram-4Y6WPE33-DpW90iu3.js} +1 -1
  294. ksadk/server/static/assets/{sankeyDiagram-5OEKKPKP-D7hSlZZZ.js → sankeyDiagram-5OEKKPKP-DpGa6EAV.js} +1 -1
  295. ksadk/server/static/assets/{sequenceDiagram-3UESZ5HK-D9Cx6hC3.js → sequenceDiagram-3UESZ5HK-NTKNGGe5.js} +1 -1
  296. ksadk/server/static/assets/{stateDiagram-AJRCARHV-D_zrg47o.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-CwSec0Wa.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-agCVobiF.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-TmrlhWNt.js → wardleyDiagram-YWT4CUSO-BR54GPmr.js} +1 -1
  304. ksadk/server/static/assets/{xychartDiagram-2RQKCTM6-DV71V-ah.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 +86 -40
  308. ksadk/sessions/base.py +31 -11
  309. ksadk/sessions/continuity.py +28 -5
  310. ksadk/sessions/in_memory.py +46 -2
  311. ksadk/sessions/local_service.py +148 -17
  312. ksadk/sessions/postgres_service.py +216 -35
  313. ksadk/sessions/resilience.py +52 -0
  314. ksadk/sessions/resilient.py +388 -0
  315. ksadk/skills/models.py +17 -5
  316. ksadk/skills/package_store.py +5 -2
  317. ksadk/skills/runtime/agent.py +20 -5
  318. ksadk/skills/runtime/artifacts.py +1 -5
  319. ksadk/skills/runtime/backends/e2b.py +10 -4
  320. ksadk/skills/runtime/backends/local.py +15 -3
  321. ksadk/skills/runtime/base.py +1 -2
  322. ksadk/skills/runtime/executor.py +10 -3
  323. ksadk/skills/runtime/factory.py +4 -2
  324. ksadk/skills/runtime/loader.py +1 -2
  325. ksadk/skills/runtime/registry.py +15 -10
  326. ksadk/skills/runtime/request.py +3 -1
  327. ksadk/skills/service_client.py +38 -17
  328. ksadk/skills/tool_defs.py +15 -10
  329. ksadk/terminal_exec_policy.py +3 -4
  330. ksadk/tools/gateway.py +92 -15
  331. ksadk/tools/result_budget.py +12 -4
  332. ksadk/toolsets/__init__.py +136 -36
  333. ksadk/toolsets/platform.py +21 -5
  334. ksadk/toolsets/sandbox.py +82 -16
  335. ksadk/toolsets/skills.py +200 -39
  336. ksadk/toolsets/web.py +123 -26
  337. ksadk/toolsets/workspace.py +264 -114
  338. ksadk/tracing/exporters/inmemory_exporter.py +62 -51
  339. ksadk/tracing/exporters/langfuse_exporter.py +91 -76
  340. ksadk/tracing/setup.py +132 -53
  341. ksadk/tracing/span_utils.py +5 -2
  342. ksadk/tui/__init__.py +22 -7
  343. ksadk/tui/loop.py +1925 -0
  344. ksadk/tui/stream_render.py +69 -0
  345. ksadk/ui_config.py +5 -3
  346. ksadk/version.py +1 -1
  347. ksadk_runtime_common/schemas/runtime_event_v1.json +95 -0
  348. agentengine_sdk_python-0.6.9.dist-info/RECORD +0 -487
  349. ksadk/server/static/assets/CodeBlock-BbI4HPtJ.js +0 -9
  350. ksadk/server/static/assets/MathMessageMarkdown-DMLQYoLp.js +0 -8
  351. ksadk/server/static/assets/MermaidBlock-DCR8WZ17.js +0 -303
  352. ksadk/server/static/assets/NativeTerminalPanel-CKUvWhUz.js +0 -1
  353. ksadk/server/static/assets/architecture-7EHR7CIX-Cr6Xz1_c.js +0 -1
  354. ksadk/server/static/assets/channel-BSSOwFIb.js +0 -1
  355. ksadk/server/static/assets/chunk-QZHKN3VN-XXpdiwUL.js +0 -1
  356. ksadk/server/static/assets/classDiagram-4FO5ZUOK-C5HvGiyK.js +0 -1
  357. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-C5HvGiyK.js +0 -1
  358. ksadk/server/static/assets/eventmodeling-FCH6USID-CIgwHJLL.js +0 -1
  359. ksadk/server/static/assets/gitGraph-WXDBUCRP-BVAJ7uo0.js +0 -1
  360. ksadk/server/static/assets/index-BH7-pC0B.js +0 -165
  361. ksadk/server/static/assets/index-DAURbCsP.css +0 -1
  362. ksadk/server/static/assets/info-J43DQDTF-MT80V4ge.js +0 -1
  363. ksadk/server/static/assets/packet-YPE3B663-BLKhbXZB.js +0 -1
  364. ksadk/server/static/assets/pie-LRSECV5Y-DFOikjSY.js +0 -1
  365. ksadk/server/static/assets/radar-GUYGQ44K-095b1Ikw.js +0 -1
  366. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-J9kCb0nC.js +0 -1
  367. ksadk/server/static/assets/treeView-BLDUP644-yinfJEY6.js +0 -1
  368. ksadk/server/static/assets/treemap-LRROVOQU-DosUqN1Q.js +0 -1
  369. ksadk/server/static/assets/wardley-L42UT6IY-Bvp7-5uH.js +0 -1
  370. ksadk/tui/app.py +0 -400
  371. ksadk/tui/clipboard.py +0 -100
  372. ksadk/tui/widgets/__init__.py +0 -22
  373. ksadk/tui/widgets/assistant.py +0 -89
  374. ksadk/tui/widgets/base.py +0 -54
  375. ksadk/tui/widgets/chat_input.py +0 -246
  376. ksadk/tui/widgets/history.py +0 -156
  377. ksadk/tui/widgets/system.py +0 -87
  378. ksadk/tui/widgets/thinking.py +0 -110
  379. ksadk/tui/widgets/tool_call.py +0 -161
  380. ksadk/tui/widgets/user.py +0 -37
  381. {agentengine_sdk_python-0.6.9.dist-info → agentengine_sdk_python-0.8.0.dist-info}/WHEEL +0 -0
  382. {agentengine_sdk_python-0.6.9.dist-info → agentengine_sdk_python-0.8.0.dist-info}/entry_points.txt +0 -0
  383. {agentengine_sdk_python-0.6.9.dist-info → agentengine_sdk_python-0.8.0.dist-info}/licenses/LICENSE +0 -0
  384. {agentengine_sdk_python-0.6.9.dist-info → agentengine_sdk_python-0.8.0.dist-info}/top_level.txt +0 -0
@@ -1,539 +1,38 @@
1
- """LangChain runner with session continuity aware input preparation."""
1
+ """LangChainRunner - LangChain 框架运行时(复用 LangGraph 基座,deepagents 同款薄壳)。
2
+
3
+ 新 LangChain(``langchain.agents.create_agent``)返回的就是 LangGraph
4
+ ``CompiledStateGraph``,因此运行时复用 :class:`LangGraphRunner`,与
5
+ ``DeepAgentsRunner`` 同款薄壳模式,保持原生能力(工具调用 / 人工审批 HITL /
6
+ checkpoint / cancel)和行为一致。
7
+
8
+ **legacy LangChain 不再支持运行**:``AgentExecutor`` / ``LLMChain`` / LCEL 链
9
+ (``prompt | llm | parser``)只有 ``invoke``、没有 ``get_state``/checkpoint,不是
10
+ LangGraph 图。本 runner 在 ``load_agent`` 时识别并拒绝,给出迁移指引,而不是等
11
+ ``stream()`` 时才崩一个莫名其妙的 ``AttributeError``。
12
+ """
2
13
 
3
14
  from __future__ import annotations
4
15
 
5
- import inspect
6
- import logging
7
- import os
8
- import uuid
9
- from typing import Any, AsyncIterator, Dict, Optional
16
+ from ksadk.runners.langgraph_runner import LangGraphRunner
10
17
 
11
- from ksadk.runners.base_runner import BaseRunner
12
- from ksadk.runners.utils import (
13
- get_langfuse_callbacks,
14
- get_langfuse_metadata,
15
- load_agent_module,
16
- prepare_trace_metadata,
18
+ _LEGACY_LANGCHAIN_ERROR = (
19
+ "legacy LangChain(AgentExecutor / LLMChain / LCEL 链 `prompt | llm | parser`)"
20
+ "不再支持运行。\n"
21
+ "请迁移到 LangGraph 基座:\n"
22
+ " • 用 `langchain.agents.create_agent(...)` 定义 agent"
23
+ "(产出 LangGraph 图,自带工具调用 / 人工审批 HITL / checkpoint),或\n"
24
+ " • 直接用 `langgraph.graph.StateGraph` 编排。\n"
25
+ "迁移后 detector 会识别为 LANGCHAIN/LANGGRAPH,复用 LangGraphRunner 运行。"
17
26
  )
18
- from ksadk.sessions.continuity import LangChainSessionAdapter
19
27
 
20
- logger = logging.getLogger(__name__)
21
28
 
22
-
23
- class LangChainRunner(BaseRunner):
24
- """LangChain framework runner."""
29
+ class LangChainRunner(LangGraphRunner):
30
+ """LangChain 运行时(复用 :class:`LangGraphRunner`)。"""
25
31
 
26
32
  def load_agent(self) -> None:
27
- self._load_agent(force_reload=False)
28
-
29
- def _load_agent(self, *, force_reload: bool) -> None:
30
- self._agent, self._module = load_agent_module(
31
- self.project_dir,
32
- self.detection_result.entry_point,
33
- self.detection_result.agent_variable,
34
- force_reload=force_reload,
35
- )
36
- self._loaded_model_name = self.normalize_requested_model(
37
- os.getenv("OPENAI_MODEL_NAME") or os.getenv("MODEL_NAME")
38
- )
39
-
40
- def prepare_for_request(self, model: Optional[str]) -> None:
41
- normalized = self.sync_process_model_env(model)
42
- if normalized is None or self._agent is None:
43
- return
44
- if normalized == getattr(self, "_loaded_model_name", None):
45
- return
46
- self._load_agent(force_reload=True)
47
-
48
- def get_session_adapter(self):
49
- return LangChainSessionAdapter()
50
-
51
- def _get_config(self, session_id: Optional[str] = None) -> Optional[dict[str, Any]]:
52
- config: dict[str, Any] = {}
53
-
54
- langfuse_callbacks = get_langfuse_callbacks()
55
- if langfuse_callbacks:
56
- config["callbacks"] = langfuse_callbacks
57
-
58
- metadata = get_langfuse_metadata(session_id)
59
- user_id, tags, _, _ = prepare_trace_metadata(session_id)
60
- if user_id:
61
- metadata["langfuse_user_id"] = user_id
62
- if tags:
63
- metadata["langfuse_tags"] = tags
64
- config["metadata"] = metadata
65
-
66
- return config or None
67
-
68
- async def invoke(self, input_data: Dict[str, Any]) -> Dict[str, Any]:
69
- session_id = input_data.get("session_id") or str(uuid.uuid4())[:8]
70
- path = self._resolve_request_path()
71
- config = self._get_config(session_id)
72
- native_context = self.build_native_context(input_data.get("platform_context"))
73
-
74
- if path == "standard_hook":
75
- payload = self._prepare_with_standard_hook(input_data, session_id)
76
- result = await self._invoke_agent(payload, config=config, context=native_context)
77
- elif path == "runnable_with_message_history":
78
- result = await self._invoke_with_message_history(
79
- input_data,
80
- session_id,
81
- config=config,
82
- context=native_context,
83
- )
84
- else:
85
- payload = self._prepare_with_replay(input_data)
86
- result = await self._invoke_agent(payload, config=config, context=native_context)
87
-
88
- output = {"output": self._extract_output(result)}
89
- usage = self._extract_usage(result)
90
- if usage:
91
- output["usage"] = usage
92
- last_usage = self._extract_last_usage(result)
93
- if last_usage:
94
- output.setdefault("metadata", {})["last_usage"] = last_usage
95
- return output
96
-
97
- async def stream(self, input_data: Dict[str, Any]) -> AsyncIterator[Dict[str, Any]]:
98
- session_id = input_data.get("session_id") or str(uuid.uuid4())[:8]
99
- path = self._resolve_request_path()
100
- config = self._get_config(session_id)
101
- native_context = self.build_native_context(input_data.get("platform_context"))
102
-
103
- if path == "standard_hook":
104
- payload = self._prepare_with_standard_hook(input_data, session_id)
105
- elif path == "runnable_with_message_history":
106
- payload = {"input": self._prepare_message_history_input(input_data)}
107
- config = self._with_session_config(config, session_id)
108
- else:
109
- payload = self._prepare_with_replay(input_data)
110
-
111
- accumulated_text = ""
112
- last_chunk: Any = None
113
-
114
- try:
115
- if hasattr(self._agent, "astream"):
116
- kwargs = self._build_optional_call_kwargs(
117
- self._agent.astream,
118
- config=config,
119
- context=native_context,
120
- )
121
- async for chunk in self._agent.astream(payload, **kwargs):
122
- last_chunk = chunk
123
- delta, chunk_type = self._extract_chunk(chunk)
124
- if delta:
125
- accumulated_text += delta
126
- yield {"delta": delta, "type": chunk_type}
127
- elif hasattr(self._agent, "stream"):
128
- kwargs = self._build_optional_call_kwargs(
129
- self._agent.stream,
130
- config=config,
131
- context=native_context,
132
- )
133
- for chunk in self._agent.stream(payload, **kwargs):
134
- last_chunk = chunk
135
- delta, chunk_type = self._extract_chunk(chunk)
136
- if delta:
137
- accumulated_text += delta
138
- yield {"delta": delta, "type": chunk_type}
139
- except Exception as exc:
140
- print(f"\n⚠️ 流式调用失败: {exc},回退到同步模式")
141
-
142
- if not accumulated_text:
143
- result = await self.invoke(input_data)
144
- final_chunk = {"output": result.get("output", ""), "type": "final"}
145
- usage = self._extract_usage(result)
146
- if usage:
147
- final_chunk["usage"] = usage
148
- last_usage = self._extract_last_usage(result)
149
- if last_usage:
150
- final_chunk.setdefault("metadata", {})["last_usage"] = last_usage
151
- yield final_chunk
152
- return
153
-
154
- final_chunk = {"output": accumulated_text, "type": "final"}
155
- usage = self._extract_usage(last_chunk)
156
- if usage:
157
- final_chunk["usage"] = usage
158
- last_usage = self._extract_last_usage(last_chunk)
159
- if last_usage:
160
- final_chunk.setdefault("metadata", {})["last_usage"] = last_usage
161
- yield final_chunk
162
-
163
- def _resolve_request_path(self) -> str:
164
- module = getattr(self, "_module", None)
165
- if callable(getattr(module, "ksadk_prepare_input", None)):
166
- return "standard_hook"
167
- if self._is_runnable_with_message_history():
168
- return "runnable_with_message_history"
169
- return "replay"
170
-
171
- def _prepare_with_standard_hook(self, input_data: Dict[str, Any], session_id: str) -> dict[str, Any]:
172
- module = getattr(self, "_module", None)
173
- prepare_input = getattr(module, "ksadk_prepare_input", None)
174
- if not callable(prepare_input):
175
- return {"input": input_data.get("input", "")}
176
-
177
- payload = {"input": input_data.get("input", "")}
178
- session_context = {
179
- "session_id": session_id,
180
- "history": list(input_data.get("history") or []),
181
- "input_parts": list(input_data.get("input_parts") or []),
182
- "attachments": list(input_data.get("attachments") or []),
183
- "attachment_results": list(input_data.get("attachment_results") or []),
184
- "instructions": input_data.get("instructions"),
185
- "platform_context": input_data.get("platform_context"),
186
- "kb_context": input_data.get("kb_context"),
187
- "memory_context": input_data.get("memory_context"),
188
- }
189
- builtin_context = self._ksadk_builtin_tool_context()
190
- if builtin_context:
191
- session_context.update(builtin_context)
192
- prepared = prepare_input(payload, session_context)
193
- return prepared if isinstance(prepared, dict) else payload
194
-
195
- @staticmethod
196
- def _ksadk_builtin_tool_context() -> dict[str, Any]:
197
- try:
198
- from ksadk.toolsets import builtin_tool_descriptors_for_runtime, builtin_tools_mode, builtin_tools_profile
199
-
200
- mode = builtin_tools_mode(default="off")
201
- descriptors = builtin_tool_descriptors_for_runtime(mode=mode)
202
- if not descriptors:
203
- return {}
204
- return {
205
- "ksadk_tools": descriptors,
206
- "ksadk_builtin_tools_mode": mode,
207
- "ksadk_builtin_tools_profile": builtin_tools_profile("default"),
208
- "deferred_direct_injection_supported": False,
209
- }
210
- except Exception as exc:
211
- logger.warning("Failed to prepare ksadk built-in tool descriptors: %s", exc)
212
- return {}
213
-
214
- def _prepare_with_replay(self, input_data: Dict[str, Any]) -> dict[str, Any]:
215
- user_input = str(input_data.get("input", "") or "")
216
- history = list(input_data.get("history") or [])
217
- ambient_text = self._ambient_context_text(input_data)
218
- instructions = str(input_data.get("instructions") or "").strip()
219
- if not history and not ambient_text and not instructions:
220
- return {"input": user_input}
221
- return {
222
- "input": self._format_replay_prompt(
223
- user_input,
224
- history,
225
- ambient_text=ambient_text,
226
- instructions=instructions,
227
- )
228
- }
229
-
230
- @staticmethod
231
- def _ambient_context_text(input_data: Dict[str, Any]) -> str:
232
- sections: list[str] = []
233
- kb_context = input_data.get("kb_context") or {}
234
- kb_text = str(kb_context.get("formatted_text") or "").strip() if isinstance(kb_context, dict) else ""
235
- if kb_text:
236
- sections.append(f"Knowledge base context:\n{kb_text}")
237
-
238
- memory_context = input_data.get("memory_context") or {}
239
- memory_text = (
240
- str(memory_context.get("formatted_text") or "").strip()
241
- if isinstance(memory_context, dict)
242
- else ""
243
- )
244
- if memory_text:
245
- sections.append(f"Long-term memory context:\n{memory_text}")
246
-
247
- return "\n\n".join(section for section in sections if section)
248
-
249
- def _prepare_message_history_input(self, input_data: Dict[str, Any]) -> str:
250
- user_input = str(input_data.get("input", "") or "")
251
- context_text = self._request_context_text(input_data)
252
- if not context_text:
253
- return user_input
254
- current_input = user_input.strip() or "[empty message]"
255
- return f"{context_text}\n\nCurrent user input:\n{current_input}"
256
-
257
- def _request_context_text(self, input_data: Dict[str, Any]) -> str:
258
- ambient_text = self._ambient_context_text(input_data)
259
- instructions = str(input_data.get("instructions") or "").strip()
260
- return "\n\n".join(section for section in (instructions, ambient_text) if section)
261
-
262
- def _format_replay_prompt(
263
- self,
264
- user_input: str,
265
- history: list[dict[str, Any]],
266
- *,
267
- ambient_text: str = "",
268
- instructions: str = "",
269
- ) -> str:
270
- lines: list[str] = []
271
- if instructions:
272
- lines.append(instructions)
273
- if ambient_text:
274
- lines.append(ambient_text)
275
- if history:
276
- lines.append("Conversation history:")
277
- normalized_history: list[tuple[str, str]] = []
278
- for item in history:
279
- role = self._normalize_history_role(item.get("role"))
280
- content = str(item.get("content", "") or "").strip()
281
- if not role or not content:
282
- continue
283
- normalized_history.append((role, content))
284
- lines.append(f"{role}: {content}")
285
-
286
- if user_input.strip():
287
- if not normalized_history or normalized_history[-1] != ("user", user_input.strip()):
288
- lines.append(f"user: {user_input.strip()}")
289
- elif ambient_text and not history:
290
- lines.append("Current user input:\n[empty message]")
291
-
292
- return "\n".join(lines)
293
-
294
- @staticmethod
295
- def _normalize_history_role(role: Any) -> str:
296
- normalized = str(role or "").strip().lower()
297
- if normalized in {"assistant", "model"}:
298
- return "assistant"
299
- if normalized == "user":
300
- return "user"
301
- return normalized
302
-
303
- @staticmethod
304
- def _with_session_config(
305
- config: Optional[dict[str, Any]],
306
- session_id: str,
307
- ) -> dict[str, Any]:
308
- merged = dict(config or {})
309
- configurable = dict(merged.get("configurable") or {})
310
- configurable["session_id"] = session_id
311
- merged["configurable"] = configurable
312
- return merged
313
-
314
- async def _invoke_agent(
315
- self,
316
- payload: Any,
317
- *,
318
- config: Optional[dict[str, Any]],
319
- context: Optional[dict[str, Any]],
320
- ) -> Any:
321
- if hasattr(self._agent, "ainvoke"):
322
- kwargs = self._build_optional_call_kwargs(
323
- self._agent.ainvoke,
324
- config=config,
325
- context=context,
326
- )
327
- return await self._agent.ainvoke(payload, **kwargs)
328
- if hasattr(self._agent, "invoke"):
329
- kwargs = self._build_optional_call_kwargs(
330
- self._agent.invoke,
331
- config=config,
332
- context=context,
333
- )
334
- return self._agent.invoke(payload, **kwargs)
335
- if callable(self._agent):
336
- return self._agent(payload)
337
- raise TypeError("Agent 不支持 invoke 调用")
338
-
339
- def _is_runnable_with_message_history(self) -> bool:
340
- try:
341
- from langchain_core.runnables.history import RunnableWithMessageHistory
342
-
343
- return isinstance(self._agent, RunnableWithMessageHistory)
344
- except Exception:
345
- return False
346
-
347
- async def _invoke_with_message_history(
348
- self,
349
- input_data: Dict[str, Any],
350
- session_id: str,
351
- *,
352
- config: Optional[dict[str, Any]],
353
- context: Optional[dict[str, Any]],
354
- ) -> Any:
355
- context_text = self._request_context_text(input_data)
356
- payload = {"input": self._prepare_message_history_input(input_data)}
357
- session_config = self._with_session_config(config, session_id)
358
- wrapped_runnable = self._extract_wrapped_history_runnable()
359
- message_history = self._get_message_history_store(session_id)
360
-
361
- if context_text and wrapped_runnable is not None and message_history is not None:
362
- return await self._invoke_wrapped_history_with_ambient_context(
363
- input_data=input_data,
364
- wrapped_runnable=wrapped_runnable,
365
- message_history=message_history,
366
- session_config=session_config,
367
- context=context,
368
- ambient_text=context_text,
369
- )
370
-
371
- try:
372
- return await self._invoke_agent(payload, config=session_config, context=context)
373
- except Exception:
374
- if wrapped_runnable is None or message_history is None:
375
- raise
376
- return await self._invoke_wrapped_history_with_ambient_context(
377
- input_data=input_data,
378
- wrapped_runnable=wrapped_runnable,
379
- message_history=message_history,
380
- session_config=session_config,
381
- context=context,
382
- ambient_text=context_text,
383
- )
384
-
385
- async def _invoke_wrapped_runnable(
386
- self,
387
- runnable: Any,
388
- payload: Any,
389
- config: Optional[dict[str, Any]],
390
- context: Optional[dict[str, Any]],
391
- ) -> Any:
392
- if hasattr(runnable, "ainvoke"):
393
- kwargs = self._build_optional_call_kwargs(
394
- runnable.ainvoke,
395
- config=config,
396
- context=context,
397
- )
398
- return await runnable.ainvoke(payload, **kwargs)
399
- if hasattr(runnable, "invoke"):
400
- kwargs = self._build_optional_call_kwargs(
401
- runnable.invoke,
402
- config=config,
403
- context=context,
404
- )
405
- return runnable.invoke(payload, **kwargs)
406
- raise TypeError("Wrapped runnable does not support invoke")
407
-
408
- async def _invoke_wrapped_history_with_ambient_context(
409
- self,
410
- *,
411
- input_data: Dict[str, Any],
412
- wrapped_runnable: Any,
413
- message_history: Any,
414
- session_config: Optional[dict[str, Any]],
415
- context: Optional[dict[str, Any]],
416
- ambient_text: str,
417
- ) -> Any:
418
- from langchain_core.messages import AIMessage, HumanMessage, SystemMessage
419
-
420
- user_input = str(input_data.get("input", "") or "")
421
- prompt_messages = list(getattr(message_history, "messages", []))
422
- if ambient_text:
423
- prompt_messages = [SystemMessage(content=ambient_text), *prompt_messages]
424
- prompt_messages.append(HumanMessage(content=user_input or "[empty message]"))
425
- result = await self._invoke_wrapped_runnable(
426
- wrapped_runnable,
427
- {"input": prompt_messages},
428
- session_config,
429
- context,
430
- )
431
- output_text = self._extract_output(result)
432
- await self._append_message_history(
433
- message_history,
434
- [
435
- HumanMessage(content=user_input or "[empty message]"),
436
- AIMessage(content=output_text),
437
- ],
438
- )
439
- return result
440
-
441
- def _extract_wrapped_history_runnable(self) -> Any | None:
442
- runnable_lambda = self._get_nested_attr(
443
- self._agent,
444
- ("bound", "bound", "last", "bound"),
445
- )
446
- if runnable_lambda is None:
447
- logger.debug(
448
- "Unable to inspect RunnableWithMessageHistory wrapper: "
449
- "missing bound.bound.last.bound"
450
- )
451
- return None
452
-
453
- func = getattr(runnable_lambda, "func", None)
454
- if func is None:
455
- logger.debug(
456
- "Unable to inspect RunnableWithMessageHistory wrapper: missing lambda func"
457
- )
458
- return None
459
-
460
- try:
461
- closure = inspect.getclosurevars(func).nonlocals
462
- except Exception as exc:
463
- logger.debug(
464
- "Unable to inspect RunnableWithMessageHistory wrapper: %s",
465
- exc,
466
- )
467
- return None
468
- return closure.get("runnable_async") or closure.get("runnable_sync")
469
-
470
- @staticmethod
471
- def _get_nested_attr(obj: Any, path: tuple[str, ...]) -> Any | None:
472
- current = obj
473
- for name in path:
474
- current = getattr(current, name, None)
475
- if current is None:
476
- return None
477
- return current
478
-
479
- def _get_message_history_store(self, session_id: str) -> Any | None:
480
- get_session_history = getattr(self._agent, "get_session_history", None)
481
- if not callable(get_session_history):
482
- return None
483
- return get_session_history(session_id)
484
-
485
- async def _append_message_history(self, history_store: Any, messages: list[Any]) -> None:
486
- if hasattr(history_store, "aadd_messages"):
487
- await history_store.aadd_messages(messages)
488
- return
489
- if hasattr(history_store, "add_messages"):
490
- history_store.add_messages(messages)
491
- return
492
- for message in messages:
493
- role = getattr(message, "type", "")
494
- content = getattr(message, "content", "")
495
- if role == "human" and hasattr(history_store, "add_user_message"):
496
- history_store.add_user_message(content)
497
- elif role == "ai" and hasattr(history_store, "add_ai_message"):
498
- history_store.add_ai_message(content)
499
-
500
- @staticmethod
501
- def _extract_output(result: Any) -> str:
502
- if isinstance(result, dict):
503
- if "output" in result:
504
- return result["output"]
505
- if "text" in result:
506
- return result["text"]
507
- messages = result.get("messages")
508
- if isinstance(messages, list) and messages:
509
- last = messages[-1]
510
- if isinstance(last, dict):
511
- return str(last.get("content", str(last)))
512
- content = getattr(last, "content", None)
513
- if content is not None:
514
- return str(content)
515
- return str(result)
516
- content = getattr(result, "content", None)
517
- if content is not None:
518
- return str(content)
519
- return str(result)
520
-
521
- def _extract_chunk(self, chunk: Any) -> tuple[Optional[str], Optional[str]]:
522
- if isinstance(chunk, dict):
523
- if "output" in chunk:
524
- return chunk["output"], "text"
525
- if "text" in chunk:
526
- return chunk["text"], "text"
527
- return None, None
528
-
529
- reasoning = None
530
- if hasattr(chunk, "reasoning_content") and chunk.reasoning_content:
531
- reasoning = chunk.reasoning_content
532
- elif hasattr(chunk, "additional_kwargs"):
533
- reasoning = chunk.additional_kwargs.get("reasoning_content")
534
-
535
- if reasoning:
536
- return reasoning, "thinking"
537
-
538
- content = chunk.content if hasattr(chunk, "content") else str(chunk)
539
- return content if content else None, "text"
33
+ super().load_agent()
34
+ # 复用 LangGraphRunner 的前提:agent 必须是 LangGraph 图(create_agent /
35
+ # StateGraph 编译产物,具备 get_state/checkpoint)。legacy 链(LCEL /
36
+ # AgentExecutor)只有 invoke、无 get_state —— 在此拒绝,而不是运行时才崩。
37
+ if not hasattr(self._agent, "get_state"):
38
+ raise ValueError(_LEGACY_LANGCHAIN_ERROR)