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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (486) hide show
  1. agentengine_sdk_python-0.7.0.dist-info/METADATA +181 -0
  2. agentengine_sdk_python-0.7.0.dist-info/RECORD +482 -0
  3. {agentengine_sdk_python-0.6.4.dist-info → agentengine_sdk_python-0.7.0.dist-info}/WHEEL +1 -1
  4. agentengine_sdk_python-0.7.0.dist-info/entry_points.txt +3 -0
  5. agentengine_sdk_python-0.7.0.dist-info/licenses/LICENSE +175 -0
  6. agentengine_sdk_python-0.7.0.dist-info/top_level.txt +2 -0
  7. ksadk/__init__.py +13 -0
  8. ksadk/__main__.py +4 -0
  9. ksadk/a2a/__init__.py +15 -0
  10. ksadk/a2a/card_builder.py +64 -0
  11. ksadk/a2a/client.py +309 -0
  12. ksadk/a2a/executor.py +201 -0
  13. ksadk/a2a/server.py +79 -0
  14. ksadk/agents/__init__.py +20 -0
  15. ksadk/agents/base.py +370 -0
  16. ksadk/agents/context.py +38 -0
  17. ksadk/agents/event.py +35 -0
  18. ksadk/agents/loop_agent.py +71 -0
  19. ksadk/agents/parallel_agent.py +109 -0
  20. ksadk/agents/runner_adapter.py +24 -0
  21. ksadk/agents/sequential_agent.py +34 -0
  22. ksadk/api/__init__.py +3 -0
  23. ksadk/api/client.py +2246 -0
  24. ksadk/builders/__init__.py +20 -0
  25. ksadk/builders/base.py +66 -0
  26. ksadk/builders/code_builder.py +1990 -0
  27. ksadk/builders/container_builder.py +786 -0
  28. ksadk/builders/framework_requirements.py +59 -0
  29. ksadk/builders/ks3_uploader.py +389 -0
  30. ksadk/builders/mcp_builder.py +476 -0
  31. ksadk/builders/requirements_utils.py +75 -0
  32. ksadk/cli/__init__.py +531 -0
  33. ksadk/cli/__main__.py +4 -0
  34. ksadk/cli/agent_ref.py +204 -0
  35. ksadk/cli/cmd_a2a.py +167 -0
  36. ksadk/cli/cmd_agent.py +201 -0
  37. ksadk/cli/cmd_build.py +270 -0
  38. ksadk/cli/cmd_completion.py +304 -0
  39. ksadk/cli/cmd_config.py +758 -0
  40. ksadk/cli/cmd_create.py +2304 -0
  41. ksadk/cli/cmd_dashboard.py +900 -0
  42. ksadk/cli/cmd_deploy.py +704 -0
  43. ksadk/cli/cmd_destroy.py +345 -0
  44. ksadk/cli/cmd_files.py +1227 -0
  45. ksadk/cli/cmd_hermes.py +1263 -0
  46. ksadk/cli/cmd_invoke.py +1503 -0
  47. ksadk/cli/cmd_launch.py +564 -0
  48. ksadk/cli/cmd_mcp.py +1179 -0
  49. ksadk/cli/cmd_model.py +302 -0
  50. ksadk/cli/cmd_openclaw.py +3922 -0
  51. ksadk/cli/cmd_run.py +239 -0
  52. ksadk/cli/cmd_status.py +588 -0
  53. ksadk/cli/cmd_version.py +522 -0
  54. ksadk/cli/cmd_web.py +288 -0
  55. ksadk/cli/deploy_utils.py +87 -0
  56. ksadk/cli/dry_run.py +214 -0
  57. ksadk/cli/env_options.py +82 -0
  58. ksadk/cli/error_utils.py +525 -0
  59. ksadk/cli/global_options.py +31 -0
  60. ksadk/cli/local_runtime.py +97 -0
  61. ksadk/cli/model_catalog.py +136 -0
  62. ksadk/cli/network_options.py +412 -0
  63. ksadk/cli/resource_common.py +621 -0
  64. ksadk/cli/storage.py +84 -0
  65. ksadk/cli/ui.py +431 -0
  66. ksadk/cli/workflow_common.py +552 -0
  67. ksadk/common/__init__.py +14 -0
  68. ksadk/common/aicp_env.py +128 -0
  69. ksadk/common/auth.py +190 -0
  70. ksadk/common/constants.py +84 -0
  71. ksadk/common/llm_utils.py +61 -0
  72. ksadk/configs/__init__.py +61 -0
  73. ksadk/configs/env_registry.py +343 -0
  74. ksadk/configs/global_config.py +200 -0
  75. ksadk/configs/settings.py +706 -0
  76. ksadk/conversations/__init__.py +95 -0
  77. ksadk/conversations/attachment_storage.py +379 -0
  78. ksadk/conversations/attachments.py +774 -0
  79. ksadk/conversations/compaction_pipeline.py +387 -0
  80. ksadk/conversations/compaction_prompt.py +128 -0
  81. ksadk/conversations/context.py +303 -0
  82. ksadk/conversations/message_projection.py +269 -0
  83. ksadk/conversations/model_context.py +370 -0
  84. ksadk/conversations/model_options.py +136 -0
  85. ksadk/conversations/normalize.py +446 -0
  86. ksadk/conversations/reasoning_markup.py +91 -0
  87. ksadk/conversations/run_kinds.py +61 -0
  88. ksadk/conversations/run_status.py +53 -0
  89. ksadk/conversations/runtime.py +5276 -0
  90. ksadk/conversations/semantic_summary.py +359 -0
  91. ksadk/conversations/session_title.py +254 -0
  92. ksadk/deployment/__init__.py +83 -0
  93. ksadk/deployment/agent_access.py +226 -0
  94. ksadk/deployment/base.py +229 -0
  95. ksadk/deployment/manager.py +332 -0
  96. ksadk/deployment/providers/__init__.py +10 -0
  97. ksadk/deployment/providers/serverless.py +1115 -0
  98. ksadk/deployment/registry.py +120 -0
  99. ksadk/deployment/state.py +78 -0
  100. ksadk/deployment/ui_config.py +21 -0
  101. ksadk/detection/__init__.py +7 -0
  102. ksadk/detection/detector.py +431 -0
  103. ksadk/detection/mcp_detector.py +250 -0
  104. ksadk/hermes_terminal.py +467 -0
  105. ksadk/identity/__init__.py +17 -0
  106. ksadk/identity/resolver.py +385 -0
  107. ksadk/knowledge_base/__init__.py +62 -0
  108. ksadk/knowledge_base/adk_tool.py +47 -0
  109. ksadk/knowledge_base/client.py +297 -0
  110. ksadk/knowledge_base/langchain_tool.py +55 -0
  111. ksadk/knowledge_base/service.py +66 -0
  112. ksadk/knowledge_base/tool.py +50 -0
  113. ksadk/markdown.py +169 -0
  114. ksadk/mcp_runtime/__init__.py +231 -0
  115. ksadk/memory/__init__.py +57 -0
  116. ksadk/memory/adk/__init__.py +51 -0
  117. ksadk/memory/adk/backends/__init__.py +5 -0
  118. ksadk/memory/adk/backends/base_ltm_backend.py +52 -0
  119. ksadk/memory/adk/backends/http_ltm_backend.py +183 -0
  120. ksadk/memory/adk/backends/inmemory_ltm_backend.py +96 -0
  121. ksadk/memory/adk/backends/sdk_ltm_backend.py +456 -0
  122. ksadk/memory/adk/long_term_memory.py +273 -0
  123. ksadk/memory/adk/resilient_session_service.py +268 -0
  124. ksadk/memory/adk/short_term_memory.py +304 -0
  125. ksadk/memory/adk_tool.py +31 -0
  126. ksadk/memory/backends/__init__.py +6 -0
  127. ksadk/memory/backends/base.py +103 -0
  128. ksadk/memory/backends/memory.py +112 -0
  129. ksadk/memory/backends/redis.py +146 -0
  130. ksadk/memory/langchain_tool.py +39 -0
  131. ksadk/memory/ltm_backend_factory.py +24 -0
  132. ksadk/memory/manager.py +215 -0
  133. ksadk/memory/service.py +172 -0
  134. ksadk/memory/tool.py +96 -0
  135. ksadk/model_policy.py +223 -0
  136. ksadk/openclaw_gateway.py +378 -0
  137. ksadk/runners/__init__.py +8 -0
  138. ksadk/runners/adk_runner.py +1994 -0
  139. ksadk/runners/base_runner.py +305 -0
  140. ksadk/runners/deepagents_runner.py +13 -0
  141. ksadk/runners/factory.py +73 -0
  142. ksadk/runners/langchain_runner.py +751 -0
  143. ksadk/runners/langgraph_runner.py +985 -0
  144. ksadk/runners/patch_langchain.py +187 -0
  145. ksadk/runners/remote_runner.py +792 -0
  146. ksadk/runners/usage_accumulator.py +38 -0
  147. ksadk/runners/utils/__init__.py +19 -0
  148. ksadk/runners/utils/langfuse.py +230 -0
  149. ksadk/runners/utils/loader.py +62 -0
  150. ksadk/runtime_context.py +166 -0
  151. ksadk/runtime_state.py +25 -0
  152. ksadk/sandbox/__init__.py +28 -0
  153. ksadk/sandbox/backends/__init__.py +9 -0
  154. ksadk/sandbox/backends/e2b.py +154 -0
  155. ksadk/sandbox/backends/local_process.py +131 -0
  156. ksadk/sandbox/base.py +101 -0
  157. ksadk/sandbox/factory.py +53 -0
  158. ksadk/sandbox/registry.py +187 -0
  159. ksadk/server/__init__.py +7 -0
  160. ksadk/server/api_models.py +73 -0
  161. ksadk/server/app.py +3931 -0
  162. ksadk/server/static/assets/ArtifactsPanel-D-SSn2ee.js +1 -0
  163. ksadk/server/static/assets/CodeBlock-P16VOLYi.js +9 -0
  164. ksadk/server/static/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  165. ksadk/server/static/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  166. ksadk/server/static/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  167. ksadk/server/static/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  168. ksadk/server/static/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  169. ksadk/server/static/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  170. ksadk/server/static/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  171. ksadk/server/static/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  172. ksadk/server/static/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  173. ksadk/server/static/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  174. ksadk/server/static/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  175. ksadk/server/static/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  176. ksadk/server/static/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  177. ksadk/server/static/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  178. ksadk/server/static/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  179. ksadk/server/static/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  180. ksadk/server/static/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  181. ksadk/server/static/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  182. ksadk/server/static/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  183. ksadk/server/static/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  184. ksadk/server/static/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  185. ksadk/server/static/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  186. ksadk/server/static/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  187. ksadk/server/static/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  188. ksadk/server/static/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  189. ksadk/server/static/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  190. ksadk/server/static/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  191. ksadk/server/static/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  192. ksadk/server/static/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  193. ksadk/server/static/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  194. ksadk/server/static/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  195. ksadk/server/static/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  196. ksadk/server/static/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  197. ksadk/server/static/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  198. ksadk/server/static/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  199. ksadk/server/static/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  200. ksadk/server/static/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  201. ksadk/server/static/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  202. ksadk/server/static/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  203. ksadk/server/static/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  204. ksadk/server/static/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  205. ksadk/server/static/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  206. ksadk/server/static/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  207. ksadk/server/static/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  208. ksadk/server/static/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  209. ksadk/server/static/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  210. ksadk/server/static/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  211. ksadk/server/static/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  212. ksadk/server/static/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  213. ksadk/server/static/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  214. ksadk/server/static/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  215. ksadk/server/static/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  216. ksadk/server/static/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  217. ksadk/server/static/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  218. ksadk/server/static/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  219. ksadk/server/static/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  220. ksadk/server/static/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  221. ksadk/server/static/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  222. ksadk/server/static/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  223. ksadk/server/static/assets/MathMessageMarkdown-CdGiQWHR.js +8 -0
  224. ksadk/server/static/assets/MathMessageMarkdown-DeYh8QPr.css +1 -0
  225. ksadk/server/static/assets/MermaidBlock-IOcal8cm.js +303 -0
  226. ksadk/server/static/assets/NativeTerminalPanel-CHOd7Rch.css +1 -0
  227. ksadk/server/static/assets/NativeTerminalPanel-DGSDWsei.js +1 -0
  228. ksadk/server/static/assets/addon-fit-DthTIhi3.js +1 -0
  229. ksadk/server/static/assets/apl-CnwPGSsG.js +1 -0
  230. ksadk/server/static/assets/arc-BA13sHc9.js +1 -0
  231. ksadk/server/static/assets/architecture-7EHR7CIX-BvUlsA6l.js +1 -0
  232. ksadk/server/static/assets/architectureDiagram-3BPJPVTR-DzJzgVoL.js +36 -0
  233. ksadk/server/static/assets/asciiarmor-qTkVPQu6.js +1 -0
  234. ksadk/server/static/assets/asn1-Dr8qZg38.js +1 -0
  235. ksadk/server/static/assets/asterisk-Bja0s6e1.js +1 -0
  236. ksadk/server/static/assets/blockDiagram-GPEHLZMM-UTdVcZhn.js +132 -0
  237. ksadk/server/static/assets/brainfuck-D5EjA2JK.js +1 -0
  238. ksadk/server/static/assets/c4Diagram-AAUBKEIU-Dix0GD4m.js +10 -0
  239. ksadk/server/static/assets/channel-CTuydARX.js +1 -0
  240. ksadk/server/static/assets/chunk-2J33WTMH-C2JxuZ42.js +1 -0
  241. ksadk/server/static/assets/chunk-4BX2VUAB-Be57QPgD.js +1 -0
  242. ksadk/server/static/assets/chunk-55IACEB6-WjSuy4nv.js +1 -0
  243. ksadk/server/static/assets/chunk-727SXJPM-BOovP-b5.js +206 -0
  244. ksadk/server/static/assets/chunk-AQP2D5EJ-DOmZNmWj.js +231 -0
  245. ksadk/server/static/assets/chunk-FMBD7UC4-DzwlodkU.js +15 -0
  246. ksadk/server/static/assets/chunk-ND2GUHAM-DMqAikEU.js +1 -0
  247. ksadk/server/static/assets/chunk-QZHKN3VN-BnCydivS.js +1 -0
  248. ksadk/server/static/assets/classDiagram-4FO5ZUOK-BNHg45Be.js +1 -0
  249. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-BNHg45Be.js +1 -0
  250. ksadk/server/static/assets/clike-DHH8Ad3s.js +1 -0
  251. ksadk/server/static/assets/clojure-BflJGmDX.js +1 -0
  252. ksadk/server/static/assets/cmake-CyVbuzPu.js +1 -0
  253. ksadk/server/static/assets/cobol-B_OZ4V-R.js +1 -0
  254. ksadk/server/static/assets/coffeescript-B2pKbFk8.js +1 -0
  255. ksadk/server/static/assets/commonlisp-CcllspGY.js +1 -0
  256. ksadk/server/static/assets/cose-bilkent-S5V4N54A-Zhy2GBnP.js +1 -0
  257. ksadk/server/static/assets/crystal-M5-qzICs.js +1 -0
  258. ksadk/server/static/assets/css-CYpP4FRV.js +1 -0
  259. ksadk/server/static/assets/cypher-p9eYesGn.js +1 -0
  260. ksadk/server/static/assets/cytoscape.esm-DelgaX4f.js +321 -0
  261. ksadk/server/static/assets/d-BhMjBjQP.js +1 -0
  262. ksadk/server/static/assets/dagre-BM42HDAG-CbKrtIUz.js +4 -0
  263. ksadk/server/static/assets/dagre-Bx709z4p.js +1 -0
  264. ksadk/server/static/assets/defaultLocale-C8Fc0cco.js +1 -0
  265. ksadk/server/static/assets/diagram-2AECGRRQ-BRApgQRK.js +43 -0
  266. ksadk/server/static/assets/diagram-5GNKFQAL-D0xbnDiK.js +10 -0
  267. ksadk/server/static/assets/diagram-KO2AKTUF-CVugVI9L.js +3 -0
  268. ksadk/server/static/assets/diagram-LMA3HP47-DozUGgee.js +24 -0
  269. ksadk/server/static/assets/diagram-OG6HWLK6-ZOYsKlru.js +24 -0
  270. ksadk/server/static/assets/diff-ChtP43wD.js +1 -0
  271. ksadk/server/static/assets/dist-2hInLS_J.js +9 -0
  272. ksadk/server/static/assets/dist-8EEyGgDx.js +1 -0
  273. ksadk/server/static/assets/dist-8_SfK1IP.js +1 -0
  274. ksadk/server/static/assets/dist-B0NP_Z0z.js +23 -0
  275. ksadk/server/static/assets/dist-BIJVDMuB.js +1 -0
  276. ksadk/server/static/assets/dist-BmlMPsCc.js +2 -0
  277. ksadk/server/static/assets/dist-BrCcQ47T.js +1 -0
  278. ksadk/server/static/assets/dist-BssVmjIo.js +6 -0
  279. ksadk/server/static/assets/dist-C3HIIaN5.js +1 -0
  280. ksadk/server/static/assets/dist-CPBtqRTW.js +1 -0
  281. ksadk/server/static/assets/dist-CkEKJFtk.js +1 -0
  282. ksadk/server/static/assets/dist-D-JMdWPQ.js +1 -0
  283. ksadk/server/static/assets/dist-D-xOD048.js +1 -0
  284. ksadk/server/static/assets/dist-D57wnGWd.js +1 -0
  285. ksadk/server/static/assets/dist-DL_NKc_z.js +1 -0
  286. ksadk/server/static/assets/dist-DMezvBGJ.js +1 -0
  287. ksadk/server/static/assets/dist-DmFaq_Iy.js +1 -0
  288. ksadk/server/static/assets/dist-Dp0k7bWI.js +1 -0
  289. ksadk/server/static/assets/dist-DpKtt4Bo.js +1 -0
  290. ksadk/server/static/assets/dist-DyOkZmze.js +11 -0
  291. ksadk/server/static/assets/dist-DyWsb78Q.js +1 -0
  292. ksadk/server/static/assets/dist-gX6GOLKq.js +1 -0
  293. ksadk/server/static/assets/dockerfile-BLkNEvjs.js +1 -0
  294. ksadk/server/static/assets/dtd-DTF72YNO.js +1 -0
  295. ksadk/server/static/assets/dylan-C6jEEEk-.js +1 -0
  296. ksadk/server/static/assets/ebnf-D4c0_ac3.js +1 -0
  297. ksadk/server/static/assets/ecl-BSZaIHnp.js +1 -0
  298. ksadk/server/static/assets/eiffel-BEjRio4Q.js +1 -0
  299. ksadk/server/static/assets/elm-Cshzl8qu.js +1 -0
  300. ksadk/server/static/assets/erDiagram-TEJ5UH35-Bk-9bgE5.js +85 -0
  301. ksadk/server/static/assets/erlang-DaB2Rkuy.js +1 -0
  302. ksadk/server/static/assets/eventmodeling-FCH6USID-DsAgWnlf.js +1 -0
  303. ksadk/server/static/assets/factor-D7LVTn2l.js +1 -0
  304. ksadk/server/static/assets/fcl-ClOhbFR7.js +1 -0
  305. ksadk/server/static/assets/flowDiagram-I6XJVG4X-Dn9kZVuZ.js +162 -0
  306. ksadk/server/static/assets/forth-Cezjo90N.js +1 -0
  307. ksadk/server/static/assets/fortran-Bt6PBEDR.js +1 -0
  308. ksadk/server/static/assets/ganttDiagram-6RSMTGT7-BGxXlJqm.js +292 -0
  309. ksadk/server/static/assets/gas-BHEdbvp9.js +1 -0
  310. ksadk/server/static/assets/gherkin-oBAE_ms0.js +1 -0
  311. ksadk/server/static/assets/gitGraph-WXDBUCRP-BIao9Yjg.js +1 -0
  312. ksadk/server/static/assets/gitGraphDiagram-PVQCEYII-C7Q0X-wi.js +106 -0
  313. ksadk/server/static/assets/graphlib-B8gBHxth.js +1 -0
  314. ksadk/server/static/assets/groovy-BC3IOsC8.js +1 -0
  315. ksadk/server/static/assets/haskell-BRsoo5mP.js +1 -0
  316. ksadk/server/static/assets/haxe-DIz0ZZqd.js +1 -0
  317. ksadk/server/static/assets/http-CLVgA2GD.js +1 -0
  318. ksadk/server/static/assets/idl-BUZw3wgd.js +1 -0
  319. ksadk/server/static/assets/index-C00Lwg3L.js +165 -0
  320. ksadk/server/static/assets/index-DAURbCsP.css +1 -0
  321. ksadk/server/static/assets/info-J43DQDTF-CyipqGxU.js +1 -0
  322. ksadk/server/static/assets/infoDiagram-5YYISTIA-BO_CSqq5.js +2 -0
  323. ksadk/server/static/assets/init-D6jRqBbL.js +1 -0
  324. ksadk/server/static/assets/ishikawaDiagram-YF4QCWOH-eYLPLd46.js +70 -0
  325. ksadk/server/static/assets/javascript-9Tg8ixDm.js +1 -0
  326. ksadk/server/static/assets/journeyDiagram-JHISSGLW-De9geSb0.js +139 -0
  327. ksadk/server/static/assets/julia-CQfgDRfP.js +1 -0
  328. ksadk/server/static/assets/kanban-definition-UN3LZRKU-Cs80kQto.js +89 -0
  329. ksadk/server/static/assets/katex-DSrCFD8n.js +265 -0
  330. ksadk/server/static/assets/linear-CN9sbKTF.js +1 -0
  331. ksadk/server/static/assets/livescript-BXxG0Yva.js +1 -0
  332. ksadk/server/static/assets/lua-CiA1ziua.js +1 -0
  333. ksadk/server/static/assets/mathematica-u8YMmbU0.js +1 -0
  334. ksadk/server/static/assets/mbox-BEMVcqjs.js +1 -0
  335. ksadk/server/static/assets/mermaid-parser.core-DlgSBU8l.js +161 -0
  336. ksadk/server/static/assets/mindmap-definition-RKZ34NQL-9afz7Oug.js +96 -0
  337. ksadk/server/static/assets/mirc-C9zpzAZU.js +1 -0
  338. ksadk/server/static/assets/mllike-B45xgp2S.js +1 -0
  339. ksadk/server/static/assets/modelica-CqHI_q-D.js +1 -0
  340. ksadk/server/static/assets/mscgen-qgSLujhx.js +1 -0
  341. ksadk/server/static/assets/mumps-CW_TBmxz.js +1 -0
  342. ksadk/server/static/assets/nginx-BMaDbqW3.js +1 -0
  343. ksadk/server/static/assets/nsis-AQ_alPln.js +1 -0
  344. ksadk/server/static/assets/ntriples-d28e9m0E.js +1 -0
  345. ksadk/server/static/assets/octave-D2Q8cUp1.js +1 -0
  346. ksadk/server/static/assets/ordinal-hYBb2elL.js +1 -0
  347. ksadk/server/static/assets/oz-BwTct_5T.js +1 -0
  348. ksadk/server/static/assets/packet-YPE3B663-CGkyRxlg.js +1 -0
  349. ksadk/server/static/assets/pascal-Dp_KdFgX.js +1 -0
  350. ksadk/server/static/assets/perl-CdEHsPfU.js +1 -0
  351. ksadk/server/static/assets/pie-LRSECV5Y-M0uWAf4n.js +1 -0
  352. ksadk/server/static/assets/pieDiagram-4H26LBE5-DPv_VstN.js +30 -0
  353. ksadk/server/static/assets/pig-AF4Hwhju.js +1 -0
  354. ksadk/server/static/assets/powershell-CzG71I4L.js +1 -0
  355. ksadk/server/static/assets/properties-C357ku5U.js +1 -0
  356. ksadk/server/static/assets/protobuf-D1ij_kNL.js +1 -0
  357. ksadk/server/static/assets/pug-Bugr-47h.js +1 -0
  358. ksadk/server/static/assets/puppet-B4hC2X4m.js +1 -0
  359. ksadk/server/static/assets/python-BqYw9LYJ.js +1 -0
  360. ksadk/server/static/assets/q-B9NhS7L_.js +1 -0
  361. ksadk/server/static/assets/quadrantDiagram-W4KKPZXB-o77wZ1XK.js +7 -0
  362. ksadk/server/static/assets/r-DADKenSm.js +1 -0
  363. ksadk/server/static/assets/radar-GUYGQ44K-Bdbm24-x.js +1 -0
  364. ksadk/server/static/assets/requirementDiagram-4Y6WPE33-BYVw81VC.js +84 -0
  365. ksadk/server/static/assets/rpm-gpDK5sbt.js +1 -0
  366. ksadk/server/static/assets/ruby-DsYpTuWg.js +1 -0
  367. ksadk/server/static/assets/sankeyDiagram-5OEKKPKP-B7nZFMKT.js +40 -0
  368. ksadk/server/static/assets/sas-C2OyD2Y6.js +1 -0
  369. ksadk/server/static/assets/scheme-CyDdOh7e.js +1 -0
  370. ksadk/server/static/assets/sequenceDiagram-3UESZ5HK-BGRRrFw5.js +162 -0
  371. ksadk/server/static/assets/shell-Du5Qg9im.js +1 -0
  372. ksadk/server/static/assets/sieve-BAxa3IjF.js +1 -0
  373. ksadk/server/static/assets/simple-mode-DRpGK0lJ.js +1 -0
  374. ksadk/server/static/assets/smalltalk-BLp5-jwC.js +1 -0
  375. ksadk/server/static/assets/solr-BBopId9w.js +1 -0
  376. ksadk/server/static/assets/sparql-Dz-mlCAC.js +1 -0
  377. ksadk/server/static/assets/spreadsheet-CTIncYxj.js +1 -0
  378. ksadk/server/static/assets/sql-DcCJ9jop.js +1 -0
  379. ksadk/server/static/assets/stateDiagram-AJRCARHV-BUfHCoPs.js +1 -0
  380. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-8xBN_gLM.js +1 -0
  381. ksadk/server/static/assets/stex-sDrdk2BW.js +1 -0
  382. ksadk/server/static/assets/stylus-DLLZ8dgm.js +1 -0
  383. ksadk/server/static/assets/swift-DKB6_1j6.js +1 -0
  384. ksadk/server/static/assets/tcl-BGfruO1u.js +1 -0
  385. ksadk/server/static/assets/textile-DWBqthVk.js +1 -0
  386. ksadk/server/static/assets/tiddlywiki-VlUiK86J.js +1 -0
  387. ksadk/server/static/assets/tiki-CxVlf5KZ.js +1 -0
  388. ksadk/server/static/assets/timeline-definition-PNZ67QCA-FbCTGrf9.js +120 -0
  389. ksadk/server/static/assets/toml-LvoKBwCs.js +1 -0
  390. ksadk/server/static/assets/treeView-BLDUP644-npMo0ak1.js +1 -0
  391. ksadk/server/static/assets/treemap-LRROVOQU-CHdzrrdo.js +1 -0
  392. ksadk/server/static/assets/troff-C2dAgh7P.js +1 -0
  393. ksadk/server/static/assets/ttcn-BePYh-hG.js +1 -0
  394. ksadk/server/static/assets/ttcn-cfg-CY0aot7Q.js +1 -0
  395. ksadk/server/static/assets/turtle-BDLWE2cD.js +1 -0
  396. ksadk/server/static/assets/vb-BthdM_4N.js +1 -0
  397. ksadk/server/static/assets/vbscript-D9f6rSsU.js +1 -0
  398. ksadk/server/static/assets/velocity-CqftRsjg.js +1 -0
  399. ksadk/server/static/assets/vennDiagram-CIIHVFJN-DWgwtPsJ.js +34 -0
  400. ksadk/server/static/assets/verilog-D-x6ne0Z.js +1 -0
  401. ksadk/server/static/assets/vhdl-CMrOq2q1.js +1 -0
  402. ksadk/server/static/assets/wardley-L42UT6IY-BEQz7wyy.js +1 -0
  403. ksadk/server/static/assets/wardleyDiagram-YWT4CUSO-2x8G-tTM.js +78 -0
  404. ksadk/server/static/assets/webidl-D5jiJvOU.js +1 -0
  405. ksadk/server/static/assets/xquery-fj_R-kMw.js +1 -0
  406. ksadk/server/static/assets/xterm-DooSxjI5.js +36 -0
  407. ksadk/server/static/assets/xychartDiagram-2RQKCTM6-Drma3AYl.js +7 -0
  408. ksadk/server/static/assets/yacas-CXXgtw0p.js +1 -0
  409. ksadk/server/static/assets/z80-CL1naaMV.js +1 -0
  410. ksadk/server/static/favicon.svg +1 -0
  411. ksadk/server/static/icons.svg +24 -0
  412. ksadk/server/static/index.html +14 -0
  413. ksadk/server/terminal_sessions.py +551 -0
  414. ksadk/sessions/__init__.py +279 -0
  415. ksadk/sessions/base.py +354 -0
  416. ksadk/sessions/continuity.py +337 -0
  417. ksadk/sessions/errors.py +7 -0
  418. ksadk/sessions/in_memory.py +273 -0
  419. ksadk/sessions/local_service.py +949 -0
  420. ksadk/sessions/postgres_service.py +901 -0
  421. ksadk/sessions/resilience.py +52 -0
  422. ksadk/sessions/resilient.py +360 -0
  423. ksadk/sessions/sqlite_service.py +13 -0
  424. ksadk/skills/__init__.py +9 -0
  425. ksadk/skills/loader.py +46 -0
  426. ksadk/skills/models.py +120 -0
  427. ksadk/skills/package_store.py +104 -0
  428. ksadk/skills/runtime/__init__.py +17 -0
  429. ksadk/skills/runtime/agent.py +183 -0
  430. ksadk/skills/runtime/artifacts.py +39 -0
  431. ksadk/skills/runtime/backends/__init__.py +1 -0
  432. ksadk/skills/runtime/backends/disabled.py +8 -0
  433. ksadk/skills/runtime/backends/e2b.py +168 -0
  434. ksadk/skills/runtime/backends/local.py +95 -0
  435. ksadk/skills/runtime/base.py +103 -0
  436. ksadk/skills/runtime/executor.py +219 -0
  437. ksadk/skills/runtime/factory.py +37 -0
  438. ksadk/skills/runtime/loader.py +131 -0
  439. ksadk/skills/runtime/registry.py +150 -0
  440. ksadk/skills/runtime/request.py +67 -0
  441. ksadk/skills/service_client.py +239 -0
  442. ksadk/skills/service_env.py +58 -0
  443. ksadk/skills/tool_defs.py +221 -0
  444. ksadk/terminal_client.py +69 -0
  445. ksadk/terminal_exec_policy.py +229 -0
  446. ksadk/tools/__init__.py +17 -0
  447. ksadk/tools/gateway.py +230 -0
  448. ksadk/tools/result_budget.py +154 -0
  449. ksadk/toolsets/__init__.py +854 -0
  450. ksadk/toolsets/_langchain.py +11 -0
  451. ksadk/toolsets/platform.py +93 -0
  452. ksadk/toolsets/sandbox.py +310 -0
  453. ksadk/toolsets/skills.py +217 -0
  454. ksadk/toolsets/web.py +266 -0
  455. ksadk/toolsets/workspace.py +917 -0
  456. ksadk/toolsets/workspace_state.py +44 -0
  457. ksadk/tracing/__init__.py +37 -0
  458. ksadk/tracing/exporters/__init__.py +1 -0
  459. ksadk/tracing/exporters/inmemory_exporter.py +116 -0
  460. ksadk/tracing/exporters/langfuse_exporter.py +445 -0
  461. ksadk/tracing/setup.py +892 -0
  462. ksadk/tracing/span_utils.py +114 -0
  463. ksadk/tui/__init__.py +27 -0
  464. ksadk/tui/loop.py +1877 -0
  465. ksadk/tui/stream_render.py +68 -0
  466. ksadk/ui_config.py +168 -0
  467. ksadk/version.py +4 -0
  468. ksadk_runtime_common/__init__.py +20 -0
  469. ksadk_runtime_common/memory_backend/__init__.py +29 -0
  470. ksadk_runtime_common/memory_backend/manifest.py +79 -0
  471. ksadk_runtime_common/memory_backend/providers/__init__.py +6 -0
  472. ksadk_runtime_common/memory_backend/providers/lancedb.py +151 -0
  473. ksadk_runtime_common/memory_backend/providers/mem0.py +74 -0
  474. ksadk_runtime_common/memory_backend/registry.py +56 -0
  475. ksadk_runtime_common/memory_backend/render.py +71 -0
  476. ksadk_runtime_common/schemas/memory_backend_manifest.schema.json +148 -0
  477. ksadk_runtime_common/workspace_files/__init__.py +29 -0
  478. ksadk_runtime_common/workspace_files/bootstrap.py +56 -0
  479. ksadk_runtime_common/workspace_files/constants.py +9 -0
  480. ksadk_runtime_common/workspace_files/path_utils.py +71 -0
  481. ksadk_runtime_common/workspace_files/preview.py +96 -0
  482. ksadk_runtime_common/workspace_files/router.py +254 -0
  483. agentengine_sdk_python/__init__.py +0 -3
  484. agentengine_sdk_python-0.6.4.dist-info/METADATA +0 -48
  485. agentengine_sdk_python-0.6.4.dist-info/RECORD +0 -5
  486. agentengine_sdk_python-0.6.4.dist-info/top_level.txt +0 -1
@@ -0,0 +1,792 @@
1
+ """
2
+ RemoteRunner - 远程 Agent 运行时
3
+
4
+ 与 InteractionLoop 配合使用,提供和本地 Runner 一致的接口
5
+ """
6
+
7
+ import json
8
+ import os
9
+ from typing import Any, AsyncIterator, Dict, Mapping, Optional, Sequence
10
+
11
+ from ksadk.runners.base_runner import BaseRunner
12
+
13
+
14
+ class RemoteRunner(BaseRunner):
15
+ """远程 Agent 运行时
16
+
17
+ 通过 HTTP 调用远程部署的 Agent,兼容 OpenAI API 格式
18
+ """
19
+
20
+ def __init__(
21
+ self,
22
+ endpoint: str,
23
+ api_key: Optional[str] = None,
24
+ session_id: Optional[str] = None,
25
+ insecure: bool = False,
26
+ model: Optional[str] = None,
27
+ api_format: str = "chat_completions",
28
+ responses_session_header: Optional[str] = None,
29
+ ):
30
+ # 不调用父类 __init__,因为不需要 detection_result
31
+ self.endpoint = endpoint.rstrip("/")
32
+ self.api_key = api_key
33
+ self.session_id = session_id
34
+ self.insecure = insecure
35
+ self.model = model
36
+ self.api_format = self._normalize_api_format(api_format)
37
+ self.responses_session_header = (
38
+ str(
39
+ responses_session_header or os.environ.get("KSADK_RESPONSES_SESSION_HEADER") or ""
40
+ ).strip()
41
+ or None
42
+ )
43
+ self._agent = None # 兼容 BaseRunner
44
+ self._responses_tool_names: dict[str, str] = {}
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 = None # ListAgentModels 拿到的可选模型列表
51
+
52
+ @staticmethod
53
+ def _normalize_api_format(api_format: Optional[str]) -> str:
54
+ normalized = str(api_format or "chat_completions").strip().lower()
55
+ if normalized in {"responses", "response", "openresponses", "open_responses"}:
56
+ return "responses"
57
+ return "chat_completions"
58
+
59
+ def load_agent(self) -> None:
60
+ """远程 Runner 不需要加载 Agent"""
61
+ pass
62
+
63
+ def prepare_for_request(self, model: Optional[str]) -> None:
64
+ normalized = self.normalize_requested_model(model)
65
+ if normalized is None:
66
+ return
67
+ self.model = normalized
68
+
69
+ def _get_client_kwargs(self) -> dict:
70
+ """获取 httpx 客户端配置"""
71
+ is_local = any(x in self.endpoint for x in ["localhost", "127.0.0.1", "0.0.0.0"])
72
+ kwargs = {"timeout": 120, "trust_env": not is_local}
73
+ if self.insecure:
74
+ kwargs["verify"] = False
75
+ return kwargs
76
+
77
+ @staticmethod
78
+ def _build_responses_input(user_input: Any) -> Any:
79
+ """Use the OpenAI Responses-compatible simple string shape when possible.
80
+
81
+ OpenClaw accepts `input` as a string or item array, but rejects a Chat-style
82
+ message object whose `content` is a bare string. For remote chat/TUI calls
83
+ we only need the current user turn, so the string form is the safest common
84
+ denominator and matches OpenClaw's documented examples.
85
+ """
86
+ if isinstance(user_input, Mapping):
87
+ if user_input.get("type"):
88
+ return [dict(user_input)]
89
+ if RemoteRunner._is_chat_style_message(user_input):
90
+ return RemoteRunner._responses_message_text(user_input)
91
+ return dict(user_input)
92
+ if isinstance(user_input, Sequence) and not isinstance(user_input, (str, bytes, bytearray)):
93
+ items = list(user_input)
94
+ if any(isinstance(item, Mapping) and item.get("type") for item in items):
95
+ return [dict(item) if isinstance(item, Mapping) else item for item in items]
96
+ chat_messages = [
97
+ item
98
+ for item in items
99
+ if isinstance(item, Mapping) and RemoteRunner._is_chat_style_message(item)
100
+ ]
101
+ if chat_messages:
102
+ latest_user = next(
103
+ (
104
+ item
105
+ for item in reversed(chat_messages)
106
+ if str(item.get("role") or "").strip().lower() == "user"
107
+ ),
108
+ chat_messages[-1],
109
+ )
110
+ return RemoteRunner._responses_message_text(latest_user)
111
+ return items
112
+ return str(user_input or "")
113
+
114
+ @staticmethod
115
+ def _build_responses_conversation_history(history: Any, current_input: Any) -> list[dict[str, Any]]:
116
+ if not isinstance(history, Sequence) or isinstance(
117
+ history, (str, bytes, bytearray)
118
+ ):
119
+ return []
120
+
121
+ messages: list[dict[str, Any]] = []
122
+ current_text = RemoteRunner._responses_message_text(
123
+ {"role": "user", "content": current_input}
124
+ ).strip()
125
+ for item in history:
126
+ if not isinstance(item, Mapping):
127
+ continue
128
+ role = str(item.get("role") or "").strip().lower()
129
+ if role == "model":
130
+ role = "assistant"
131
+ if role not in {"user", "assistant"}:
132
+ continue
133
+ text = RemoteRunner._responses_message_text(item).strip()
134
+ if not text:
135
+ continue
136
+ if role == "user" and current_text and text == current_text:
137
+ continue
138
+ messages.append(
139
+ {
140
+ "role": role,
141
+ "content": [{"type": "input_text", "text": text}],
142
+ }
143
+ )
144
+ return messages
145
+
146
+ @staticmethod
147
+ def _responses_conversation_name(input_data: Mapping[str, Any], session_id: Optional[str]) -> str:
148
+ if not session_id:
149
+ return ""
150
+ platform_context = input_data.get("platform_context")
151
+ agent_id = ""
152
+ if isinstance(platform_context, Mapping):
153
+ agent_id = str(platform_context.get("agent_id") or "").strip()
154
+ if agent_id:
155
+ return f"agentengine:{agent_id}:{session_id}"
156
+ return f"agentengine:{session_id}"
157
+
158
+ @staticmethod
159
+ def _responses_conversation_value(value: Any) -> str:
160
+ if isinstance(value, Mapping):
161
+ return str(value.get("id") or "").strip()
162
+ return str(value or "").strip()
163
+
164
+ def _build_responses_payload(
165
+ self,
166
+ input_data: Mapping[str, Any],
167
+ *,
168
+ stream: bool,
169
+ ) -> dict[str, Any]:
170
+ user_input = input_data.get("input", "")
171
+ session_id = input_data.get("session_id") or self.session_id
172
+ previous_response_id = input_data.get("previous_response_id")
173
+
174
+ if self.responses_session_header:
175
+ payload = {
176
+ "input": self._build_responses_input(user_input),
177
+ "stream": stream,
178
+ }
179
+ else:
180
+ payload = {
181
+ "input": self._build_responses_input(user_input),
182
+ "stream": stream,
183
+ }
184
+ history_enabled = bool(input_data.get("responses_conversation")) and not previous_response_id
185
+ if history_enabled:
186
+ history = self._build_responses_conversation_history(
187
+ input_data.get("history"),
188
+ user_input,
189
+ )
190
+ if history:
191
+ payload["conversation_history"] = history
192
+ conversation = self._responses_conversation_value(input_data.get("conversation"))
193
+ if conversation and not previous_response_id:
194
+ payload["conversation"] = conversation
195
+ elif (
196
+ input_data.get("responses_conversation")
197
+ and session_id
198
+ and not previous_response_id
199
+ ):
200
+ conversation = self._responses_conversation_name(input_data, str(session_id))
201
+ if conversation:
202
+ payload["conversation"] = conversation
203
+
204
+ if previous_response_id:
205
+ payload["previous_response_id"] = str(previous_response_id)
206
+ tools = self._builtin_response_tool_schemas(input_data)
207
+ if tools:
208
+ payload["tools"] = tools
209
+ return payload
210
+
211
+ @staticmethod
212
+ def _builtin_response_tool_schemas(input_data: Mapping[str, Any] | None = None) -> list[dict[str, Any]]:
213
+ try:
214
+ from ksadk.toolsets import builtin_tool_descriptors_for_runtime, builtin_tools_mode, describe_agentengine_tools
215
+
216
+ mode = builtin_tools_mode(default="off")
217
+ descriptors = builtin_tool_descriptors_for_runtime(mode=mode)
218
+ except Exception:
219
+ return []
220
+ deferred_names = RemoteRunner._deferred_tool_names(input_data)
221
+ if deferred_names:
222
+ try:
223
+ direct_descriptors = describe_agentengine_tools(include=deferred_names, profile="coding")
224
+ except Exception:
225
+ direct_descriptors = []
226
+ direct_descriptors = [
227
+ item
228
+ for item in direct_descriptors
229
+ if str(item.get("execution") or "builtin") != "external"
230
+ ]
231
+ existing_names = {str(item.get("name") or "") for item in descriptors}
232
+ descriptors = [
233
+ *descriptors,
234
+ *[
235
+ item
236
+ for item in direct_descriptors
237
+ if str(item.get("name") or "") not in existing_names
238
+ ],
239
+ ]
240
+ return [RemoteRunner._response_tool_schema(descriptor) for descriptor in descriptors]
241
+
242
+ @staticmethod
243
+ def _deferred_tool_names(input_data: Mapping[str, Any] | None) -> list[str]:
244
+ if not isinstance(input_data, Mapping):
245
+ return []
246
+ raw_names = input_data.get("deferred_tool_names")
247
+ if not isinstance(raw_names, Sequence) or isinstance(raw_names, (str, bytes, bytearray)):
248
+ return []
249
+ names: list[str] = []
250
+ seen: set[str] = set()
251
+ for item in raw_names:
252
+ name = str(item or "").strip()
253
+ if not name or name in seen:
254
+ continue
255
+ seen.add(name)
256
+ names.append(name)
257
+ return names
258
+
259
+ @staticmethod
260
+ def _response_tool_schema(descriptor: Mapping[str, Any]) -> dict[str, Any]:
261
+ args = descriptor.get("args")
262
+ properties = dict(args) if isinstance(args, Mapping) else {}
263
+ required = [
264
+ name
265
+ for name, schema in properties.items()
266
+ if isinstance(schema, Mapping) and schema.get("required") is True
267
+ ]
268
+ parameters: dict[str, Any] = {
269
+ "type": "object",
270
+ "properties": properties,
271
+ }
272
+ if required:
273
+ parameters["required"] = required
274
+ return {
275
+ "type": "function",
276
+ "name": str(descriptor.get("name") or ""),
277
+ "description": str(descriptor.get("description") or descriptor.get("name") or ""),
278
+ "parameters": parameters,
279
+ }
280
+
281
+ @staticmethod
282
+ def _is_chat_style_message(value: Mapping[str, Any]) -> bool:
283
+ return not value.get("type") and ("role" in value or "content" in value)
284
+
285
+ @staticmethod
286
+ def _responses_message_text(message: Mapping[str, Any]) -> str:
287
+ content = message.get("content")
288
+ if isinstance(content, str):
289
+ return content
290
+ if isinstance(content, Sequence) and not isinstance(content, (str, bytes, bytearray)):
291
+ parts: list[str] = []
292
+ for part in content:
293
+ if isinstance(part, str):
294
+ parts.append(part)
295
+ elif isinstance(part, Mapping):
296
+ text = part.get("text")
297
+ if isinstance(text, str):
298
+ parts.append(text)
299
+ return "".join(parts)
300
+ return str(content or "")
301
+
302
+ def _get_headers(self, session_id: Optional[str] = None) -> dict:
303
+ """获取请求头"""
304
+ headers = {"Content-Type": "application/json"}
305
+ if self.api_key:
306
+ headers["Authorization"] = f"Bearer {self.api_key}"
307
+ if self.api_format == "responses" and session_id and self.responses_session_header:
308
+ headers[self.responses_session_header] = session_id
309
+ return headers
310
+
311
+ @staticmethod
312
+ def _response_usage_payload(data: Mapping[str, Any]) -> dict[str, Any]:
313
+ usage = data.get("usage")
314
+ if isinstance(usage, Mapping):
315
+ return dict(usage)
316
+ response = data.get("response")
317
+ if isinstance(response, Mapping) and isinstance(response.get("usage"), Mapping):
318
+ return dict(response["usage"])
319
+ return {}
320
+
321
+ async def invoke(self, input_data: Dict[str, Any]) -> Dict[str, Any]:
322
+ """非流式调用远程 Agent"""
323
+ import httpx
324
+
325
+ user_input = input_data.get("input", "")
326
+ session_id = input_data.get("session_id") or self.session_id
327
+
328
+ if self.api_format == "responses":
329
+ url = f"{self.endpoint}/v1/responses"
330
+ payload = self._build_responses_payload(input_data, stream=False)
331
+ else:
332
+ url = f"{self.endpoint}/v1/chat/completions"
333
+ payload = {
334
+ "messages": [{"role": "user", "content": user_input}],
335
+ "stream": False,
336
+ }
337
+ if session_id and self.api_format != "responses":
338
+ payload["session_id"] = session_id
339
+ if self.model:
340
+ payload["model"] = self.model
341
+
342
+ async with httpx.AsyncClient(**self._get_client_kwargs()) as client:
343
+ response = await client.post(url, json=payload, headers=self._get_headers(session_id))
344
+ response.raise_for_status()
345
+ data = response.json()
346
+
347
+ usage = self._response_usage_payload(data)
348
+
349
+ if self.api_format == "responses":
350
+ result = {"output": self._extract_responses_output_text(data) or str(data)}
351
+ if usage:
352
+ result["usage"] = usage
353
+ return result
354
+
355
+ # 提取 OpenAI Chat Completions 格式响应
356
+ try:
357
+ content = data["choices"][0]["message"]["content"]
358
+ except (KeyError, IndexError):
359
+ content = str(data)
360
+
361
+ result = {"output": content}
362
+ if usage:
363
+ result["usage"] = usage
364
+ return result
365
+
366
+ async def stream(self, input_data: Dict[str, Any]) -> AsyncIterator[Dict[str, Any]]:
367
+ """流式调用远程 Agent"""
368
+ import httpx
369
+
370
+ # 工具 item/call_id 只在单次 response 内有效。RemoteRunner 会被 TUI 多轮复用,
371
+ # 若保留上一轮的追踪状态,runtime 复用 id 时 response.completed 会被误判为重放。
372
+ self._responses_tool_names.clear()
373
+ self._responses_tool_args.clear()
374
+ self._responses_streamed_item_keys.clear()
375
+ self._responses_text_streamed = False
376
+ self._responses_reasoning_streamed = False
377
+
378
+ user_input = input_data.get("input", "")
379
+ session_id = input_data.get("session_id") or self.session_id
380
+
381
+ if self.api_format == "responses":
382
+ url = f"{self.endpoint}/v1/responses"
383
+ payload = self._build_responses_payload(input_data, stream=True)
384
+ else:
385
+ url = f"{self.endpoint}/v1/chat/completions"
386
+ payload = {
387
+ "messages": [{"role": "user", "content": user_input}],
388
+ "stream": True,
389
+ "stream_options": {"include_usage": True},
390
+ }
391
+ if session_id and self.api_format != "responses":
392
+ payload["session_id"] = session_id
393
+ if self.model:
394
+ payload["model"] = self.model
395
+
396
+ async with httpx.AsyncClient(**self._get_client_kwargs()) as client:
397
+ async with client.stream(
398
+ "POST", url, json=payload, headers=self._get_headers(session_id)
399
+ ) as response:
400
+ response.raise_for_status()
401
+
402
+ event_name = ""
403
+ accumulated_text = ""
404
+ final_sent = False
405
+ async for line in response.aiter_lines():
406
+ if not line:
407
+ event_name = ""
408
+ continue
409
+
410
+ if line.startswith("event:"):
411
+ event_name = line.split(":", 1)[1].strip()
412
+ continue
413
+
414
+ if line.startswith("data: "):
415
+ data_str = line[6:].strip()
416
+ if data_str == "[DONE]":
417
+ break
418
+
419
+ try:
420
+ data = json.loads(data_str)
421
+
422
+ # 记录回包里的真实模型名:
423
+ # chat completions 顶层 data.model;responses 格式在
424
+ # data.response.model(response.completed 事件的 response 对象)。
425
+ observed = data.get("model") if isinstance(data, Mapping) else None
426
+ if not observed and isinstance(data, Mapping):
427
+ resp = data.get("response")
428
+ if isinstance(resp, Mapping):
429
+ observed = resp.get("model")
430
+ if observed and not isinstance(observed, (list, dict)):
431
+ self._observed_model = str(observed)
432
+
433
+ if self.api_format == "responses":
434
+ async for item in self._iter_responses_stream_events(
435
+ data, event_name=event_name
436
+ ):
437
+ yield item
438
+ continue
439
+
440
+ # 兜底:api_format 标成 chat 但 runtime 实发 responses 格式
441
+ # 事件(event_name 或 data.type 以 response. 开头)→ 按 responses
442
+ # 解析,否则 response.reasoning.delta 会被 chat 路径当顶层 text 显示。
443
+ _ev = event_name or (str(data.get("type")) if isinstance(data, Mapping) else "")
444
+ if _ev.startswith("response."):
445
+ async for item in self._iter_responses_stream_events(
446
+ data, event_name=event_name
447
+ ):
448
+ yield item
449
+ continue
450
+
451
+ # 解析 OpenAI Chat Completions 流式格式
452
+ choices = data.get("choices", [])
453
+ usage = data.get("usage")
454
+ if isinstance(usage, Mapping):
455
+ final_chunk = {"type": "final", "usage": dict(usage)}
456
+ metadata = data.get("metadata")
457
+ if isinstance(metadata, Mapping):
458
+ final_chunk["metadata"] = dict(metadata)
459
+ yield final_chunk
460
+ final_sent = True
461
+ if choices:
462
+ delta = choices[0].get("delta", {})
463
+ content = delta.get("content", "")
464
+ reasoning = delta.get("reasoning_content", "")
465
+
466
+ if reasoning:
467
+ yield {"delta": reasoning, "type": "thinking"}
468
+ if content:
469
+ accumulated_text += content
470
+ yield {"delta": content, "type": "text"}
471
+ else:
472
+ # 非标准简化流(runtime 直发顶层 delta,无 choices 包装):
473
+ # 兜底提取顶层 delta 作为正文,与 _extract_content 口径一致。
474
+ top_delta = data.get("delta")
475
+ if isinstance(top_delta, str) and top_delta:
476
+ accumulated_text += top_delta
477
+ yield {"delta": top_delta, "type": "text"}
478
+
479
+ except json.JSONDecodeError:
480
+ pass
481
+ if self.api_format != "responses" and accumulated_text and not final_sent:
482
+ yield {"output": accumulated_text, "type": "final"}
483
+
484
+ @staticmethod
485
+ def _extract_responses_output_text(data: Dict[str, Any]) -> str:
486
+ output_text = data.get("output_text")
487
+ if output_text:
488
+ return str(output_text)
489
+ output = data.get("output") or []
490
+ for item in output:
491
+ if not isinstance(item, dict):
492
+ continue
493
+ for content in item.get("content") or []:
494
+ if isinstance(content, dict) and content.get("text"):
495
+ return str(content["text"])
496
+ return ""
497
+
498
+ @staticmethod
499
+ def _stringify_responses_payload(value: Any) -> str:
500
+ if value is None:
501
+ return ""
502
+ if isinstance(value, str):
503
+ return value
504
+ if isinstance(value, (dict, list)):
505
+ return json.dumps(value, ensure_ascii=False, indent=2)
506
+ return str(value)
507
+
508
+ @staticmethod
509
+ def _responses_error_message(data: Dict[str, Any]) -> str:
510
+ response = data.get("response") if isinstance(data.get("response"), dict) else data
511
+ error = response.get("error") if isinstance(response, dict) else data.get("error")
512
+ if isinstance(error, dict):
513
+ return str(error.get("message") or error.get("code") or "Agent 运行失败")
514
+ if error:
515
+ return str(error)
516
+ return "Agent 运行失败"
517
+
518
+ @staticmethod
519
+ def _responses_item_key(item: Dict[str, Any], data: Dict[str, Any]) -> str:
520
+ return str(
521
+ item.get("id")
522
+ or item.get("item_id")
523
+ or item.get("call_id")
524
+ or data.get("item_id")
525
+ or data.get("call_id")
526
+ or data.get("output_index")
527
+ or ""
528
+ )
529
+
530
+ def _remember_responses_tool(
531
+ self, key: str, item: Dict[str, Any], name: str, args: str
532
+ ) -> None:
533
+ if key:
534
+ self._responses_streamed_item_keys.add(key)
535
+ if key:
536
+ self._responses_tool_names[key] = name
537
+ self._responses_tool_args[key] = args
538
+ call_id = str(item.get("call_id") or "")
539
+ if call_id:
540
+ self._responses_streamed_item_keys.add(call_id)
541
+ self._responses_tool_names[call_id] = name
542
+ self._responses_tool_args[call_id] = args
543
+
544
+ def _responses_tool_name(self, key: str, item: Dict[str, Any], fallback: str = "tool") -> str:
545
+ call_id = str(item.get("call_id") or "")
546
+ return str(
547
+ item.get("name")
548
+ or item.get("tool_name")
549
+ or (self._responses_tool_names.get(key) if key else "")
550
+ or (self._responses_tool_names.get(call_id) if call_id else "")
551
+ or fallback
552
+ )
553
+
554
+ @staticmethod
555
+ def _responses_item_text(item: Dict[str, Any]) -> str:
556
+ for field in ("output_text", "text", "summary_text", "summary", "delta"):
557
+ value = item.get(field)
558
+ if isinstance(value, str) and value:
559
+ return value
560
+ content = item.get("content")
561
+ if isinstance(content, list):
562
+ parts: list[str] = []
563
+ for part in content:
564
+ if isinstance(part, str):
565
+ parts.append(part)
566
+ elif isinstance(part, dict) and isinstance(part.get("text"), str):
567
+ parts.append(part["text"])
568
+ return "".join(parts)
569
+ if isinstance(content, str):
570
+ return content
571
+ return ""
572
+
573
+ async def _iter_responses_output_item(
574
+ self,
575
+ data: Dict[str, Any],
576
+ *,
577
+ status: str,
578
+ replay_completed_text: bool = False,
579
+ replay_completed_reasoning: bool = False,
580
+ ) -> AsyncIterator[Dict[str, Any]]:
581
+ item = data.get("item") or data.get("output_item") or data
582
+ if not isinstance(item, dict):
583
+ return
584
+
585
+ item_type = str(item.get("type") or "").strip()
586
+ key = self._responses_item_key(item, data)
587
+ if item_type == "function_call":
588
+ name = self._responses_tool_name(key, item)
589
+ args = self._stringify_responses_payload(
590
+ item.get("arguments")
591
+ if "arguments" in item
592
+ else item.get("args", item.get("input"))
593
+ )
594
+ self._remember_responses_tool(key, item, name, args)
595
+ yield {"type": "tool_call", "tool_name": name, "tool_args": args, "status": status, "call_id": key}
596
+ return
597
+
598
+ if item_type == "function_call_output":
599
+ name = self._responses_tool_name(key, item)
600
+ if key:
601
+ self._responses_streamed_item_keys.add(key)
602
+ call_id = str(item.get("call_id") or "")
603
+ if call_id:
604
+ self._responses_streamed_item_keys.add(call_id)
605
+ output = self._stringify_responses_payload(
606
+ item.get("output") if "output" in item else item.get("result", item.get("content"))
607
+ )
608
+ yield {"type": "tool_result", "tool_name": name, "tool_output": output, "call_id": call_id or key}
609
+ return
610
+
611
+ if item_type == "mcp_approval_request":
612
+ name = str(item.get("name") or "approval")
613
+ args = self._stringify_responses_payload(item.get("arguments") or item.get("args"))
614
+ approval_request_id = str(item.get("id") or item.get("approval_request_id") or "")
615
+ yield {
616
+ "type": "tool_call",
617
+ "tool_name": name,
618
+ "tool_args": args,
619
+ "status": "paused",
620
+ "approval_request_id": approval_request_id,
621
+ }
622
+ yield {
623
+ "type": "interrupt",
624
+ "interrupt_info": {
625
+ "id": approval_request_id,
626
+ "approval_request_id": approval_request_id,
627
+ "name": name,
628
+ "server_label": str(item.get("server_label") or ""),
629
+ },
630
+ }
631
+ return
632
+
633
+ if item_type in {"reasoning", "reasoning_summary", "reasoning_summary_text"}:
634
+ text = self._responses_item_text(item)
635
+ if text and (status != "completed" or replay_completed_reasoning):
636
+ self._responses_reasoning_streamed = True
637
+ yield {"delta": text, "type": "thinking"}
638
+ return
639
+
640
+ if item_type == "message":
641
+ text = self._responses_item_text(item)
642
+ if text and (status != "completed" or replay_completed_text):
643
+ self._responses_text_streamed = True
644
+ yield {"delta": text, "type": "text"}
645
+ return
646
+
647
+ async def _iter_responses_stream_events(
648
+ self,
649
+ data: Dict[str, Any],
650
+ *,
651
+ event_name: str = "",
652
+ ) -> AsyncIterator[Dict[str, Any]]:
653
+ event_type = str(data.get("type") or event_name or data.get("_event") or "")
654
+ if event_name == "response.reasoning.delta":
655
+ delta = data.get("delta")
656
+ if delta:
657
+ self._responses_reasoning_streamed = True
658
+ yield {"delta": str(delta), "type": "thinking"}
659
+ return
660
+ if event_type in {
661
+ "response.reasoning.delta",
662
+ "response.reasoning_text.delta",
663
+ "response.reasoning_summary.delta",
664
+ "response.reasoning_summary_text.delta",
665
+ }:
666
+ delta = data.get("delta") or data.get("text")
667
+ if delta:
668
+ self._responses_reasoning_streamed = True
669
+ yield {"delta": str(delta), "type": "thinking"}
670
+ return
671
+ if event_type in {"response.output_text.delta", "response.output_text.done"}:
672
+ text = data.get("delta") or data.get("text")
673
+ if text and (
674
+ event_type == "response.output_text.delta" or not self._responses_text_streamed
675
+ ):
676
+ self._responses_text_streamed = True
677
+ yield {"delta": str(text), "type": "text"}
678
+ return
679
+ if event_type == "response.output_item.added":
680
+ async for item in self._iter_responses_output_item(data, status="running"):
681
+ yield item
682
+ return
683
+ if event_type == "response.output_item.done":
684
+ async for item in self._iter_responses_output_item(data, status="completed"):
685
+ yield item
686
+ return
687
+ # ksadk/runtime 特有 tool 事件(对标 hosted UI responses-stream.js:176-186)
688
+ if event_type in {"response.tool_call", "response.ksadk.stage_tool_call"}:
689
+ name = str(data.get("name") or data.get("tool_name") or "tool")
690
+ args = self._stringify_responses_payload(data.get("args") if "args" in data else data.get("arguments"))
691
+ cid = str(data.get("call_id") or data.get("item_id") or data.get("run_id") or "")
692
+ yield {"type": "tool_call", "tool_name": name, "tool_args": args, "status": "running", "call_id": cid}
693
+ return
694
+ if event_type in {
695
+ "response.tool_result",
696
+ "response.ksadk.tool_result",
697
+ "response.ksadk.stage_tool_result",
698
+ }:
699
+ name = str(data.get("name") or data.get("tool_name") or "tool")
700
+ output = self._stringify_responses_payload(data.get("output") if "output" in data else data.get("result"))
701
+ cid = str(data.get("call_id") or data.get("item_id") or data.get("run_id") or "")
702
+ yield {
703
+ "type": "tool_result",
704
+ "tool_name": name,
705
+ "tool_output": output,
706
+ "call_id": cid,
707
+ }
708
+ return
709
+ if event_type == "response.function_call_arguments.delta":
710
+ key = str(data.get("item_id") or data.get("call_id") or "")
711
+ name = self._responses_tool_name(key, data)
712
+ args = f"{self._responses_tool_args.get(key, '')}{str(data.get('delta') or '')}"
713
+ if key:
714
+ self._responses_tool_args[key] = args
715
+ yield {"type": "tool_call", "tool_name": name, "tool_args": args, "status": "running", "call_id": key}
716
+ return
717
+ if event_type == "response.function_call_arguments.done":
718
+ key = str(data.get("item_id") or data.get("call_id") or "")
719
+ name = self._responses_tool_name(key, data)
720
+ args = self._stringify_responses_payload(
721
+ data.get("arguments") or self._responses_tool_args.get(key, "")
722
+ )
723
+ if key:
724
+ self._responses_tool_args[key] = args
725
+ yield {"type": "tool_call", "tool_name": name, "tool_args": args, "status": "running", "call_id": key}
726
+ return
727
+ if event_type == "response.completed":
728
+ response = data.get("response") if isinstance(data.get("response"), dict) else data
729
+ output = response.get("output") if isinstance(response, dict) else None
730
+ if isinstance(output, list):
731
+ replayed_item_keys = set(self._responses_streamed_item_keys)
732
+ replay_completed_text = not self._responses_text_streamed
733
+ replay_completed_reasoning = not self._responses_reasoning_streamed
734
+ for item in output:
735
+ if isinstance(item, dict):
736
+ key = self._responses_item_key(item, {"item": item})
737
+ call_id = str(item.get("call_id") or "")
738
+ if (key and key in replayed_item_keys) or (
739
+ call_id and call_id in replayed_item_keys
740
+ ):
741
+ continue
742
+ async for projected in self._iter_responses_output_item(
743
+ {"item": item},
744
+ status="completed",
745
+ replay_completed_text=replay_completed_text,
746
+ replay_completed_reasoning=replay_completed_reasoning,
747
+ ):
748
+ yield projected
749
+ chunk = {
750
+ "type": "responses_output",
751
+ "output": output,
752
+ "response_id": response.get("id"),
753
+ }
754
+ usage = response.get("usage")
755
+ if isinstance(usage, Mapping):
756
+ chunk["usage"] = dict(usage)
757
+ metadata = response.get("metadata")
758
+ if isinstance(metadata, Mapping):
759
+ chunk["metadata"] = dict(metadata)
760
+ yield chunk
761
+ return
762
+ # response.content_part.delta:glm 等模型把 reasoning 走这个事件,
763
+ # partType 含 "reasoning" → thinking(不显示),否则 text(对标 hosted UI)。
764
+ if event_type == "response.content_part.delta":
765
+ part = data.get("part") if isinstance(data.get("part"), dict) else {}
766
+ delta = data.get("delta")
767
+ part_type = str(part.get("type") or (delta.get("type") if isinstance(delta, dict) else "") or data.get("content_type") or "")
768
+ text = ""
769
+ if isinstance(delta, dict):
770
+ text = str(delta.get("text") or delta.get("content") or "")
771
+ elif isinstance(delta, str):
772
+ text = delta
773
+ if not text:
774
+ text = str(data.get("text") or "")
775
+ if not text:
776
+ return
777
+ if "reasoning" in part_type:
778
+ self._responses_reasoning_streamed = True
779
+ yield {"delta": text, "type": "thinking"}
780
+ else:
781
+ self._responses_text_streamed = True
782
+ yield {"delta": text, "type": "text"}
783
+ return
784
+ if event_type == "response.failed":
785
+ yield {"type": "error", "message": self._responses_error_message(data)}
786
+ return
787
+ if event_type == "response.incomplete":
788
+ yield {"type": "error", "message": "Agent 响应未完成"}
789
+ return
790
+ # 未知事件默认丢弃(对标 hosted UI responses-stream.js: 未知事件 return [])。
791
+ # 之前默认把 data.delta 当 text 显示,会导致 reasoning 走未识别事件时漏进正文。
792
+ # 正文已由 output_text.delta / content_part.delta 显式处理,未知事件不该当正文。