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
@@ -5,12 +5,6 @@ Monkey patch for langchain-openai to support reasoning_content field (e.g. for D
5
5
  import logging
6
6
  from typing import Any, Mapping, cast
7
7
 
8
- from ksadk.conversations.model_options import (
9
- model_options_for_chat_completions,
10
- model_options_for_responses,
11
- )
12
- from ksadk.runtime_context import get_current_invocation_context
13
-
14
8
  from langchain_core.messages import (
15
9
  AIMessageChunk,
16
10
  BaseMessageChunk,
@@ -22,6 +16,12 @@ from langchain_core.messages import (
22
16
  )
23
17
  from langchain_core.messages.tool import tool_call_chunk
24
18
 
19
+ from ksadk.conversations.model_options import (
20
+ model_options_for_chat_completions,
21
+ model_options_for_responses,
22
+ )
23
+ from ksadk.runtime_context import get_current_invocation_context
24
+
25
25
  logger = logging.getLogger(__name__)
26
26
 
27
27
  # Original function reference (to avoid recursion if patched multiple times)
@@ -95,22 +95,22 @@ _original_chat_get_request_payload = None
95
95
  def _patched_convert_message_to_dict(message, *args, **kwargs):
96
96
  """Patched version to include reasoning_content in outgoing requests."""
97
97
  from langchain_core.messages import AIMessage
98
-
98
+
99
99
  # Call original function first
100
100
  result = _original_convert_message_to_dict(message, *args, **kwargs)
101
-
101
+
102
102
  # If this is an AIMessage with tool_calls and reasoning_content in additional_kwargs
103
103
  if isinstance(message, AIMessage):
104
- additional_kwargs = getattr(message, 'additional_kwargs', {}) or {}
105
- reasoning = additional_kwargs.get('reasoning_content')
106
-
104
+ additional_kwargs = getattr(message, "additional_kwargs", {}) or {}
105
+ reasoning = additional_kwargs.get("reasoning_content")
106
+
107
107
  # Only add if we have tool_calls (required by some thinking models)
108
108
  if message.tool_calls and reasoning is not None:
109
- result['reasoning_content'] = reasoning
109
+ result["reasoning_content"] = reasoning
110
110
  elif message.tool_calls and reasoning is None:
111
111
  # Force add empty reasoning_content for thinking models
112
- result['reasoning_content'] = ''
113
-
112
+ result["reasoning_content"] = ""
113
+
114
114
  return result
115
115
 
116
116
 
@@ -168,7 +168,7 @@ def apply_patch():
168
168
  # Patch 1: Fix receiving responses (capture reasoning_content)
169
169
  _original_convert_delta = base_module._convert_delta_to_message_chunk
170
170
  base_module._convert_delta_to_message_chunk = _patched_convert_delta_to_message_chunk
171
-
171
+
172
172
  # Patch 2: Fix sending requests (include reasoning_content for tool_call messages)
173
173
  _original_convert_message_to_dict = base_module._convert_message_to_dict
174
174
  base_module._convert_message_to_dict = _patched_convert_message_to_dict
@@ -177,7 +177,7 @@ def apply_patch():
177
177
  base_module.BaseChatOpenAI._get_request_payload = _patched_base_get_request_payload
178
178
  _original_chat_get_request_payload = base_module.ChatOpenAI._get_request_payload
179
179
  base_module.ChatOpenAI._get_request_payload = _patched_chat_get_request_payload
180
-
180
+
181
181
  base_module._ksadk_patched = True
182
182
 
183
183
  # logger.info("Applied langchain-openai patch for reasoning_content support")
@@ -1,7 +1,7 @@
1
1
  """
2
2
  RemoteRunner - 远程 Agent 运行时
3
3
 
4
- 与 AgentTUI 配合使用,提供和本地 Runner 一致的接口
4
+ 与 InteractionLoop 配合使用,提供和本地 Runner 一致的接口
5
5
  """
6
6
 
7
7
  import json
@@ -43,6 +43,13 @@ class RemoteRunner(BaseRunner):
43
43
  self._agent = None # 兼容 BaseRunner
44
44
  self._responses_tool_names: dict[str, str] = {}
45
45
  self._responses_tool_args: dict[str, str] = {}
46
+ self._responses_streamed_item_keys: set[str] = set()
47
+ self._responses_text_streamed = False
48
+ self._responses_reasoning_streamed = False
49
+ self._observed_model: str | None = None # 流式回包里观察到的真实模型名
50
+ self.available_models: list[dict[str, Any]] | None = (
51
+ None # ListAgentModels 拿到的可选模型列表
52
+ )
46
53
 
47
54
  @staticmethod
48
55
  def _normalize_api_format(api_format: Optional[str]) -> str:
@@ -107,19 +114,45 @@ class RemoteRunner(BaseRunner):
107
114
  return str(user_input or "")
108
115
 
109
116
  @staticmethod
110
- def _build_responses_conversation_history(history: Any, current_input: Any) -> list[dict[str, Any]]:
111
- if not isinstance(history, Sequence) or isinstance(
112
- history, (str, bytes, bytearray)
113
- ):
117
+ def _build_responses_conversation_history(
118
+ history: Any, current_input: Any
119
+ ) -> list[dict[str, Any]]:
120
+ if not isinstance(history, Sequence) or isinstance(history, (str, bytes, bytearray)):
114
121
  return []
115
122
 
116
123
  messages: list[dict[str, Any]] = []
124
+ current_output_call_ids: set[str] = set()
125
+ if isinstance(current_input, Mapping):
126
+ current_items = [current_input]
127
+ elif isinstance(current_input, Sequence) and not isinstance(
128
+ current_input, (str, bytes, bytearray)
129
+ ):
130
+ current_items = [item for item in current_input if isinstance(item, Mapping)]
131
+ else:
132
+ current_items = []
133
+ for item in current_items:
134
+ if str(item.get("type") or "").strip().lower() != "function_call_output":
135
+ continue
136
+ call_id = str(item.get("call_id") or "").strip()
137
+ if call_id:
138
+ current_output_call_ids.add(call_id)
117
139
  current_text = RemoteRunner._responses_message_text(
118
140
  {"role": "user", "content": current_input}
119
141
  ).strip()
120
142
  for item in history:
121
143
  if not isinstance(item, Mapping):
122
144
  continue
145
+ item_type = str(item.get("type") or "").strip().lower()
146
+ if item_type in {"function_call", "function_call_output"}:
147
+ # Responses tool items are already protocol-shaped. Do not
148
+ # reinterpret them as chat messages or they lose call_id.
149
+ if (
150
+ item_type == "function_call_output"
151
+ and str(item.get("call_id") or "").strip() in current_output_call_ids
152
+ ):
153
+ continue
154
+ messages.append(dict(item))
155
+ continue
123
156
  role = str(item.get("role") or "").strip().lower()
124
157
  if role == "model":
125
158
  role = "assistant"
@@ -139,7 +172,9 @@ class RemoteRunner(BaseRunner):
139
172
  return messages
140
173
 
141
174
  @staticmethod
142
- def _responses_conversation_name(input_data: Mapping[str, Any], session_id: Optional[str]) -> str:
175
+ def _responses_conversation_name(
176
+ input_data: Mapping[str, Any], session_id: Optional[str]
177
+ ) -> str:
143
178
  if not session_id:
144
179
  return ""
145
180
  platform_context = input_data.get("platform_context")
@@ -176,10 +211,27 @@ class RemoteRunner(BaseRunner):
176
211
  "input": self._build_responses_input(user_input),
177
212
  "stream": stream,
178
213
  }
179
- history_enabled = bool(input_data.get("responses_conversation")) and not previous_response_id
214
+ history_enabled = (
215
+ bool(input_data.get("responses_conversation"))
216
+ or bool(input_data.get("responses_history"))
217
+ ) and not previous_response_id
180
218
  if history_enabled:
219
+ structured_history = input_data.get("responses_history")
220
+ history_input: Sequence[Any] | None
221
+ if isinstance(structured_history, Sequence) and not isinstance(
222
+ structured_history, (str, bytes, bytearray)
223
+ ):
224
+ history_input = structured_history
225
+ else:
226
+ fallback_history = input_data.get("history")
227
+ history_input = (
228
+ fallback_history
229
+ if isinstance(fallback_history, Sequence)
230
+ and not isinstance(fallback_history, (str, bytes, bytearray))
231
+ else None
232
+ )
181
233
  history = self._build_responses_conversation_history(
182
- input_data.get("history"),
234
+ history_input,
183
235
  user_input,
184
236
  )
185
237
  if history:
@@ -188,9 +240,7 @@ class RemoteRunner(BaseRunner):
188
240
  if conversation and not previous_response_id:
189
241
  payload["conversation"] = conversation
190
242
  elif (
191
- input_data.get("responses_conversation")
192
- and session_id
193
- and not previous_response_id
243
+ input_data.get("responses_conversation") and session_id and not previous_response_id
194
244
  ):
195
245
  conversation = self._responses_conversation_name(input_data, str(session_id))
196
246
  if conversation:
@@ -204,9 +254,15 @@ class RemoteRunner(BaseRunner):
204
254
  return payload
205
255
 
206
256
  @staticmethod
207
- def _builtin_response_tool_schemas(input_data: Mapping[str, Any] | None = None) -> list[dict[str, Any]]:
257
+ def _builtin_response_tool_schemas(
258
+ input_data: Mapping[str, Any] | None = None,
259
+ ) -> list[dict[str, Any]]:
208
260
  try:
209
- from ksadk.toolsets import builtin_tool_descriptors_for_runtime, builtin_tools_mode, describe_agentengine_tools
261
+ from ksadk.toolsets import (
262
+ builtin_tool_descriptors_for_runtime,
263
+ builtin_tools_mode,
264
+ describe_agentengine_tools,
265
+ )
210
266
 
211
267
  mode = builtin_tools_mode(default="off")
212
268
  descriptors = builtin_tool_descriptors_for_runtime(mode=mode)
@@ -215,7 +271,9 @@ class RemoteRunner(BaseRunner):
215
271
  deferred_names = RemoteRunner._deferred_tool_names(input_data)
216
272
  if deferred_names:
217
273
  try:
218
- direct_descriptors = describe_agentengine_tools(include=deferred_names, profile="coding")
274
+ direct_descriptors = describe_agentengine_tools(
275
+ include=deferred_names, profile="coding"
276
+ )
219
277
  except Exception:
220
278
  direct_descriptors = []
221
279
  direct_descriptors = [
@@ -342,7 +400,9 @@ class RemoteRunner(BaseRunner):
342
400
  usage = self._response_usage_payload(data)
343
401
 
344
402
  if self.api_format == "responses":
345
- result = {"output": self._extract_responses_output_text(data) or str(data)}
403
+ result: dict[str, Any] = {
404
+ "output": self._extract_responses_output_text(data) or str(data)
405
+ }
346
406
  if usage:
347
407
  result["usage"] = usage
348
408
  return result
@@ -362,6 +422,14 @@ class RemoteRunner(BaseRunner):
362
422
  """流式调用远程 Agent"""
363
423
  import httpx
364
424
 
425
+ # 工具 item/call_id 只在单次 response 内有效。RemoteRunner 会被 TUI 多轮复用,
426
+ # 若保留上一轮的追踪状态,runtime 复用 id 时 response.completed 会被误判为重放。
427
+ self._responses_tool_names.clear()
428
+ self._responses_tool_args.clear()
429
+ self._responses_streamed_item_keys.clear()
430
+ self._responses_text_streamed = False
431
+ self._responses_reasoning_streamed = False
432
+
365
433
  user_input = input_data.get("input", "")
366
434
  session_id = input_data.get("session_id") or self.session_id
367
435
 
@@ -406,6 +474,17 @@ class RemoteRunner(BaseRunner):
406
474
  try:
407
475
  data = json.loads(data_str)
408
476
 
477
+ # 记录回包里的真实模型名:
478
+ # chat completions 顶层 data.model;responses 格式在
479
+ # data.response.model(response.completed 事件的 response 对象)。
480
+ observed = data.get("model") if isinstance(data, Mapping) else None
481
+ if not observed and isinstance(data, Mapping):
482
+ resp = data.get("response")
483
+ if isinstance(resp, Mapping):
484
+ observed = resp.get("model")
485
+ if observed and not isinstance(observed, (list, dict)):
486
+ self._observed_model = str(observed)
487
+
409
488
  if self.api_format == "responses":
410
489
  async for item in self._iter_responses_stream_events(
411
490
  data, event_name=event_name
@@ -413,11 +492,28 @@ class RemoteRunner(BaseRunner):
413
492
  yield item
414
493
  continue
415
494
 
495
+ # 兜底:api_format 标成 chat 但 runtime 实发 responses 格式
496
+ # 事件(event_name 或 data.type 以 response. 开头)→ 按 responses
497
+ # 解析,否则 response.reasoning.delta 会被 chat 路径当顶层 text 显示。
498
+ _ev = event_name or (
499
+ str(data.get("type")) if isinstance(data, Mapping) else ""
500
+ )
501
+ if _ev.startswith("response."):
502
+ async for item in self._iter_responses_stream_events(
503
+ data, event_name=event_name
504
+ ):
505
+ yield item
506
+ continue
507
+
416
508
  # 解析 OpenAI Chat Completions 流式格式
417
509
  choices = data.get("choices", [])
418
510
  usage = data.get("usage")
419
511
  if isinstance(usage, Mapping):
420
- yield {"type": "final", "usage": dict(usage)}
512
+ final_chunk = {"type": "final", "usage": dict(usage)}
513
+ metadata = data.get("metadata")
514
+ if isinstance(metadata, Mapping):
515
+ final_chunk["metadata"] = dict(metadata)
516
+ yield final_chunk
421
517
  final_sent = True
422
518
  if choices:
423
519
  delta = choices[0].get("delta", {})
@@ -429,6 +525,13 @@ class RemoteRunner(BaseRunner):
429
525
  if content:
430
526
  accumulated_text += content
431
527
  yield {"delta": content, "type": "text"}
528
+ else:
529
+ # 非标准简化流(runtime 直发顶层 delta,无 choices 包装):
530
+ # 兜底提取顶层 delta 作为正文,与 _extract_content 口径一致。
531
+ top_delta = data.get("delta")
532
+ if isinstance(top_delta, str) and top_delta:
533
+ accumulated_text += top_delta
534
+ yield {"delta": top_delta, "type": "text"}
432
535
 
433
536
  except json.JSONDecodeError:
434
537
  pass
@@ -484,11 +587,14 @@ class RemoteRunner(BaseRunner):
484
587
  def _remember_responses_tool(
485
588
  self, key: str, item: Dict[str, Any], name: str, args: str
486
589
  ) -> None:
590
+ if key:
591
+ self._responses_streamed_item_keys.add(key)
487
592
  if key:
488
593
  self._responses_tool_names[key] = name
489
594
  self._responses_tool_args[key] = args
490
595
  call_id = str(item.get("call_id") or "")
491
596
  if call_id:
597
+ self._responses_streamed_item_keys.add(call_id)
492
598
  self._responses_tool_names[call_id] = name
493
599
  self._responses_tool_args[call_id] = args
494
600
 
@@ -526,6 +632,8 @@ class RemoteRunner(BaseRunner):
526
632
  data: Dict[str, Any],
527
633
  *,
528
634
  status: str,
635
+ replay_completed_text: bool = False,
636
+ replay_completed_reasoning: bool = False,
529
637
  ) -> AsyncIterator[Dict[str, Any]]:
530
638
  item = data.get("item") or data.get("output_item") or data
531
639
  if not isinstance(item, dict):
@@ -541,15 +649,31 @@ class RemoteRunner(BaseRunner):
541
649
  else item.get("args", item.get("input"))
542
650
  )
543
651
  self._remember_responses_tool(key, item, name, args)
544
- yield {"type": "tool_call", "tool_name": name, "tool_args": args, "status": status}
652
+ yield {
653
+ "type": "tool_call",
654
+ "tool_name": name,
655
+ "tool_args": args,
656
+ "status": status,
657
+ "call_id": key,
658
+ }
545
659
  return
546
660
 
547
661
  if item_type == "function_call_output":
548
662
  name = self._responses_tool_name(key, item)
663
+ if key:
664
+ self._responses_streamed_item_keys.add(key)
665
+ call_id = str(item.get("call_id") or "")
666
+ if call_id:
667
+ self._responses_streamed_item_keys.add(call_id)
549
668
  output = self._stringify_responses_payload(
550
669
  item.get("output") if "output" in item else item.get("result", item.get("content"))
551
670
  )
552
- yield {"type": "tool_result", "tool_name": name, "tool_output": output}
671
+ yield {
672
+ "type": "tool_result",
673
+ "tool_name": name,
674
+ "tool_output": output,
675
+ "call_id": call_id or key,
676
+ }
553
677
  return
554
678
 
555
679
  if item_type == "mcp_approval_request":
@@ -576,13 +700,15 @@ class RemoteRunner(BaseRunner):
576
700
 
577
701
  if item_type in {"reasoning", "reasoning_summary", "reasoning_summary_text"}:
578
702
  text = self._responses_item_text(item)
579
- if text:
703
+ if text and (status != "completed" or replay_completed_reasoning):
704
+ self._responses_reasoning_streamed = True
580
705
  yield {"delta": text, "type": "thinking"}
581
706
  return
582
707
 
583
708
  if item_type == "message":
584
709
  text = self._responses_item_text(item)
585
- if text and status != "completed":
710
+ if text and (status != "completed" or replay_completed_text):
711
+ self._responses_text_streamed = True
586
712
  yield {"delta": text, "type": "text"}
587
713
  return
588
714
 
@@ -596,6 +722,7 @@ class RemoteRunner(BaseRunner):
596
722
  if event_name == "response.reasoning.delta":
597
723
  delta = data.get("delta")
598
724
  if delta:
725
+ self._responses_reasoning_streamed = True
599
726
  yield {"delta": str(delta), "type": "thinking"}
600
727
  return
601
728
  if event_type in {
@@ -606,12 +733,16 @@ class RemoteRunner(BaseRunner):
606
733
  }:
607
734
  delta = data.get("delta") or data.get("text")
608
735
  if delta:
736
+ self._responses_reasoning_streamed = True
609
737
  yield {"delta": str(delta), "type": "thinking"}
610
738
  return
611
- if event_type == "response.output_text.delta":
612
- delta = data.get("delta")
613
- if delta:
614
- yield {"delta": str(delta), "type": "text"}
739
+ if event_type in {"response.output_text.delta", "response.output_text.done"}:
740
+ text = data.get("delta") or data.get("text")
741
+ if text and (
742
+ event_type == "response.output_text.delta" or not self._responses_text_streamed
743
+ ):
744
+ self._responses_text_streamed = True
745
+ yield {"delta": str(text), "type": "text"}
615
746
  return
616
747
  if event_type == "response.output_item.added":
617
748
  async for item in self._iter_responses_output_item(data, status="running"):
@@ -621,13 +752,51 @@ class RemoteRunner(BaseRunner):
621
752
  async for item in self._iter_responses_output_item(data, status="completed"):
622
753
  yield item
623
754
  return
755
+ # ksadk/runtime 特有 tool 事件(对标 hosted UI responses-stream.js:176-186)
756
+ if event_type in {"response.tool_call", "response.ksadk.stage_tool_call"}:
757
+ name = str(data.get("name") or data.get("tool_name") or "tool")
758
+ args = self._stringify_responses_payload(
759
+ data.get("args") if "args" in data else data.get("arguments")
760
+ )
761
+ cid = str(data.get("call_id") or data.get("item_id") or data.get("run_id") or "")
762
+ yield {
763
+ "type": "tool_call",
764
+ "tool_name": name,
765
+ "tool_args": args,
766
+ "status": "running",
767
+ "call_id": cid,
768
+ }
769
+ return
770
+ if event_type in {
771
+ "response.tool_result",
772
+ "response.ksadk.tool_result",
773
+ "response.ksadk.stage_tool_result",
774
+ }:
775
+ name = str(data.get("name") or data.get("tool_name") or "tool")
776
+ output = self._stringify_responses_payload(
777
+ data.get("output") if "output" in data else data.get("result")
778
+ )
779
+ cid = str(data.get("call_id") or data.get("item_id") or data.get("run_id") or "")
780
+ yield {
781
+ "type": "tool_result",
782
+ "tool_name": name,
783
+ "tool_output": output,
784
+ "call_id": cid,
785
+ }
786
+ return
624
787
  if event_type == "response.function_call_arguments.delta":
625
788
  key = str(data.get("item_id") or data.get("call_id") or "")
626
789
  name = self._responses_tool_name(key, data)
627
790
  args = f"{self._responses_tool_args.get(key, '')}{str(data.get('delta') or '')}"
628
791
  if key:
629
792
  self._responses_tool_args[key] = args
630
- yield {"type": "tool_call", "tool_name": name, "tool_args": args, "status": "running"}
793
+ yield {
794
+ "type": "tool_call",
795
+ "tool_name": name,
796
+ "tool_args": args,
797
+ "status": "running",
798
+ "call_id": key,
799
+ }
631
800
  return
632
801
  if event_type == "response.function_call_arguments.done":
633
802
  key = str(data.get("item_id") or data.get("call_id") or "")
@@ -637,31 +806,88 @@ class RemoteRunner(BaseRunner):
637
806
  )
638
807
  if key:
639
808
  self._responses_tool_args[key] = args
640
- yield {"type": "tool_call", "tool_name": name, "tool_args": args, "status": "running"}
809
+ yield {
810
+ "type": "tool_call",
811
+ "tool_name": name,
812
+ "tool_args": args,
813
+ "status": "running",
814
+ "call_id": key,
815
+ }
641
816
  return
642
817
  if event_type == "response.completed":
643
- response = data.get("response") if isinstance(data.get("response"), dict) else data
644
- output = response.get("output") if isinstance(response, dict) else None
645
- if isinstance(output, list):
818
+ nested_response = data.get("response")
819
+ response_data: dict[str, Any] = (
820
+ dict(nested_response) if isinstance(nested_response, dict) else data
821
+ )
822
+ completed_output = (
823
+ response_data.get("output") if isinstance(response_data, dict) else None
824
+ )
825
+ if isinstance(completed_output, list):
826
+ replayed_item_keys = set(self._responses_streamed_item_keys)
827
+ replay_completed_text = not self._responses_text_streamed
828
+ replay_completed_reasoning = not self._responses_reasoning_streamed
829
+ for item in completed_output:
830
+ if isinstance(item, dict):
831
+ key = self._responses_item_key(item, {"item": item})
832
+ call_id = str(item.get("call_id") or "")
833
+ if (key and key in replayed_item_keys) or (
834
+ call_id and call_id in replayed_item_keys
835
+ ):
836
+ continue
837
+ async for projected in self._iter_responses_output_item(
838
+ {"item": item},
839
+ status="completed",
840
+ replay_completed_text=replay_completed_text,
841
+ replay_completed_reasoning=replay_completed_reasoning,
842
+ ):
843
+ yield projected
646
844
  chunk = {
647
845
  "type": "responses_output",
648
- "output": output,
649
- "response_id": response.get("id"),
846
+ "output": completed_output,
847
+ "response_id": response_data.get("id"),
650
848
  }
651
- usage = response.get("usage")
849
+ usage = response_data.get("usage")
652
850
  if isinstance(usage, Mapping):
653
851
  chunk["usage"] = dict(usage)
852
+ metadata = response_data.get("metadata")
853
+ if isinstance(metadata, Mapping):
854
+ chunk["metadata"] = dict(metadata)
654
855
  yield chunk
655
856
  return
857
+ # response.content_part.delta:glm 等模型把 reasoning 走这个事件,
858
+ # partType 含 "reasoning" → thinking(不显示),否则 text(对标 hosted UI)。
859
+ if event_type == "response.content_part.delta":
860
+ part_value = data.get("part")
861
+ part: dict[str, Any] = dict(part_value) if isinstance(part_value, dict) else {}
862
+ delta = data.get("delta")
863
+ part_type = str(
864
+ part.get("type")
865
+ or (delta.get("type") if isinstance(delta, dict) else "")
866
+ or data.get("content_type")
867
+ or ""
868
+ )
869
+ text = ""
870
+ if isinstance(delta, dict):
871
+ text = str(delta.get("text") or delta.get("content") or "")
872
+ elif isinstance(delta, str):
873
+ text = delta
874
+ if not text:
875
+ text = str(data.get("text") or "")
876
+ if not text:
877
+ return
878
+ if "reasoning" in part_type:
879
+ self._responses_reasoning_streamed = True
880
+ yield {"delta": text, "type": "thinking"}
881
+ else:
882
+ self._responses_text_streamed = True
883
+ yield {"delta": text, "type": "text"}
884
+ return
656
885
  if event_type == "response.failed":
657
886
  yield {"type": "error", "message": self._responses_error_message(data)}
658
887
  return
659
888
  if event_type == "response.incomplete":
660
889
  yield {"type": "error", "message": "Agent 响应未完成"}
661
890
  return
662
- if isinstance(data.get("delta"), str):
663
- yield {"delta": str(data["delta"]), "type": "text"}
664
- return
665
- output_text = RemoteRunner._extract_responses_output_text(data)
666
- if output_text and event_type != "response.completed":
667
- yield {"delta": output_text, "type": "text"}
891
+ # 未知事件默认丢弃(对标 hosted UI responses-stream.js: 未知事件 return [])。
892
+ # 之前默认把 data.delta 当 text 显示,会导致 reasoning 走未识别事件时漏进正文。
893
+ # 正文已由 output_text.delta / content_part.delta 显式处理,未知事件不该当正文。
@@ -6,6 +6,7 @@ cached_tokens;Anthropic 经 langchain_anthropic 转换后 input_tokens 含 cache
6
6
  cache_creation),直接相加不重复;input_token_details 键名不统一(cached/cache_read/
7
7
  cache_creation),逐键求和作诊断明细。
8
8
  """
9
+
9
10
  from __future__ import annotations
10
11
 
11
12
  from typing import Any
@@ -157,7 +157,7 @@ def get_langfuse_callbacks() -> list[Any]:
157
157
  return callbacks
158
158
 
159
159
 
160
- def get_langfuse_metadata(session_id: str = None) -> dict:
160
+ def get_langfuse_metadata(session_id: str | None = None) -> dict[str, Any]:
161
161
  """获取 Langfuse 的 metadata 字典
162
162
 
163
163
  通过 metadata 字段传递 trace 属性:
@@ -171,7 +171,7 @@ def get_langfuse_metadata(session_id: str = None) -> dict:
171
171
  Returns:
172
172
  包含 Langfuse 属性的 metadata 字典
173
173
  """
174
- metadata = {}
174
+ metadata: dict[str, Any] = {}
175
175
 
176
176
  if session_id:
177
177
  metadata["langfuse_session_id"] = session_id
@@ -201,7 +201,7 @@ def get_langfuse_metadata(session_id: str = None) -> dict:
201
201
  return metadata
202
202
 
203
203
 
204
- def prepare_trace_metadata(session_id: str = None) -> tuple:
204
+ def prepare_trace_metadata(session_id: str | None = None) -> tuple[Any, list[Any], Any, Any]:
205
205
  """准备 Trace 元数据
206
206
 
207
207
  Returns:
@@ -18,37 +18,37 @@ def load_agent_module(
18
18
  force_reload: bool = False,
19
19
  ) -> Any:
20
20
  """加载 Agent 模块
21
-
21
+
22
22
  Args:
23
23
  project_dir: 项目目录
24
24
  entry_point: 入口文件 (e.g., "agent.py")
25
25
  agent_variable: Agent 变量名 (e.g., "root_agent", "graph")
26
-
26
+
27
27
  Returns:
28
28
  加载的 Agent 对象
29
-
29
+
30
30
  Raises:
31
31
  ImportError: 模块导入失败
32
32
  AttributeError: 未找到 Agent 变量
33
33
  """
34
34
  project_path = Path(project_dir).resolve()
35
-
35
+
36
36
  # 添加项目目录到 Python 路径
37
37
  if str(project_path) not in sys.path:
38
38
  sys.path.insert(0, str(project_path))
39
39
  src_path = project_path / "src"
40
40
  if src_path.is_dir() and str(src_path) not in sys.path:
41
41
  sys.path.insert(0, str(src_path))
42
-
42
+
43
43
  # 确定模块名
44
44
  if entry_point.endswith(".py"):
45
45
  module_name = entry_point[:-3]
46
46
  else:
47
47
  module_name = entry_point
48
-
48
+
49
49
  # 路径转换为模块路径
50
50
  module_name = module_name.replace("/", ".").replace("\\", ".")
51
-
51
+
52
52
  try:
53
53
  if force_reload and module_name in sys.modules:
54
54
  module = importlib.reload(sys.modules[module_name])