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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (371) hide show
  1. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/METADATA +36 -20
  2. agentengine_sdk_python-0.8.0.dist-info/RECORD +578 -0
  3. ksadk/a2a/__init__.py +178 -11
  4. ksadk/a2a/bootstrap.py +334 -0
  5. ksadk/a2a/card.py +120 -0
  6. ksadk/a2a/context_store.py +203 -0
  7. ksadk/a2a/control_plane.py +818 -0
  8. ksadk/a2a/credential.py +99 -0
  9. ksadk/a2a/event_adapter.py +149 -0
  10. ksadk/a2a/executor.py +406 -89
  11. ksadk/a2a/external_transport.py +516 -0
  12. ksadk/a2a/identity.py +304 -0
  13. ksadk/a2a/ids.py +22 -0
  14. ksadk/a2a/langgraph.py +285 -0
  15. ksadk/a2a/resume_store.py +201 -0
  16. ksadk/a2a/routes.py +105 -0
  17. ksadk/a2a/server.py +107 -60
  18. ksadk/a2a/space_client.py +1101 -0
  19. ksadk/a2a/task_adapter.py +423 -0
  20. ksadk/a2a/task_event_dispatcher.py +167 -0
  21. ksadk/a2a/task_event_outbox.py +326 -0
  22. ksadk/a2a/task_store.py +206 -0
  23. ksadk/a2ui/__init__.py +27 -0
  24. ksadk/a2ui/core.py +186 -0
  25. ksadk/a2ui/models.py +166 -0
  26. ksadk/a2ui/renderer.py +198 -0
  27. ksadk/agui/__init__.py +9 -0
  28. ksadk/agui/a2ui_projection.py +92 -0
  29. ksadk/agui/agent.py +857 -0
  30. ksadk/agui/config.py +86 -0
  31. ksadk/agui/routes.py +55 -0
  32. ksadk/api/client.py +233 -191
  33. ksadk/builders/__init__.py +2 -0
  34. ksadk/builders/base.py +16 -14
  35. ksadk/builders/code_builder.py +318 -236
  36. ksadk/builders/container_builder.py +187 -167
  37. ksadk/builders/framework_requirements.py +29 -11
  38. ksadk/builders/ks3_uploader.py +58 -27
  39. ksadk/builders/managed_runtime_builder.py +145 -0
  40. ksadk/builders/mcp_builder.py +91 -92
  41. ksadk/builders/requirements_utils.py +1 -5
  42. ksadk/cli/__init__.py +89 -171
  43. ksadk/cli/cmd_a2a.py +254 -70
  44. ksadk/cli/cmd_agent.py +19 -5
  45. ksadk/cli/cmd_build.py +158 -29
  46. ksadk/cli/cmd_completion.py +47 -35
  47. ksadk/cli/cmd_config.py +267 -198
  48. ksadk/cli/cmd_create.py +500 -720
  49. ksadk/cli/cmd_dashboard.py +120 -45
  50. ksadk/cli/cmd_deploy.py +117 -58
  51. ksadk/cli/cmd_destroy.py +44 -14
  52. ksadk/cli/cmd_files.py +63 -24
  53. ksadk/cli/cmd_hermes.py +168 -89
  54. ksadk/cli/cmd_invoke.py +184 -122
  55. ksadk/cli/cmd_launch.py +64 -28
  56. ksadk/cli/cmd_mcp.py +98 -64
  57. ksadk/cli/cmd_model.py +14 -5
  58. ksadk/cli/cmd_openclaw.py +483 -227
  59. ksadk/cli/cmd_replay.py +71 -0
  60. ksadk/cli/cmd_run.py +33 -10
  61. ksadk/cli/cmd_status.py +80 -31
  62. ksadk/cli/cmd_version.py +20 -13
  63. ksadk/cli/cmd_web.py +89 -13
  64. ksadk/cli/deploy_utils.py +20 -20
  65. ksadk/cli/dry_run.py +5 -3
  66. ksadk/cli/error_utils.py +37 -12
  67. ksadk/cli/global_options.py +1 -2
  68. ksadk/cli/local_runtime.py +1 -2
  69. ksadk/cli/model_catalog.py +6 -2
  70. ksadk/cli/network_options.py +34 -14
  71. ksadk/cli/resource_common.py +6 -2
  72. ksadk/cli/storage.py +0 -1
  73. ksadk/cli/ui.py +5 -3
  74. ksadk/cli/workflow_common.py +51 -17
  75. ksadk/codex/__init__.py +12 -0
  76. ksadk/codex/client.py +408 -0
  77. ksadk/codex/phase.py +143 -0
  78. ksadk/codex/runtime.py +449 -0
  79. ksadk/common/aicp_env.py +0 -1
  80. ksadk/common/auth.py +2 -2
  81. ksadk/common/constants.py +1 -3
  82. ksadk/common/llm_utils.py +17 -13
  83. ksadk/compat/__init__.py +5 -0
  84. ksadk/compat/adk_compat.py +200 -0
  85. ksadk/compat/copilotkit_a2ui.py +330 -0
  86. ksadk/configs/__init__.py +12 -12
  87. ksadk/configs/env_registry.py +500 -100
  88. ksadk/configs/global_config.py +2 -1
  89. ksadk/configs/settings.py +151 -124
  90. ksadk/conversations/__init__.py +7 -5
  91. ksadk/conversations/attachment_storage.py +16 -11
  92. ksadk/conversations/attachments.py +44 -36
  93. ksadk/conversations/compaction_pipeline.py +12 -12
  94. ksadk/conversations/compaction_prompt.py +9 -5
  95. ksadk/conversations/context.py +221 -6
  96. ksadk/conversations/message_projection.py +438 -51
  97. ksadk/conversations/model_context.py +12 -6
  98. ksadk/conversations/model_options.py +0 -1
  99. ksadk/conversations/normalize.py +20 -16
  100. ksadk/conversations/reasoning_markup.py +1 -1
  101. ksadk/conversations/runtime.py +339 -5255
  102. ksadk/conversations/runtime_compaction.py +333 -0
  103. ksadk/conversations/runtime_constants.py +27 -0
  104. ksadk/conversations/runtime_governance.py +185 -0
  105. ksadk/conversations/runtime_input.py +652 -0
  106. ksadk/conversations/runtime_invocation.py +395 -0
  107. ksadk/conversations/runtime_metadata.py +475 -0
  108. ksadk/conversations/runtime_observability.py +355 -0
  109. ksadk/conversations/runtime_payloads.py +272 -0
  110. ksadk/conversations/runtime_persistence.py +440 -0
  111. ksadk/conversations/runtime_preparation.py +418 -0
  112. ksadk/conversations/runtime_resume.py +816 -0
  113. ksadk/conversations/runtime_stream_events.py +902 -0
  114. ksadk/conversations/runtime_streaming.py +547 -0
  115. ksadk/conversations/semantic_summary.py +17 -5
  116. ksadk/conversations/session_title.py +6 -3
  117. ksadk/deployment/__init__.py +15 -16
  118. ksadk/deployment/agent_access.py +12 -23
  119. ksadk/deployment/base.py +51 -38
  120. ksadk/deployment/manager.py +63 -65
  121. ksadk/deployment/providers/serverless.py +309 -202
  122. ksadk/deployment/registry.py +38 -32
  123. ksadk/deployment/state.py +11 -11
  124. ksadk/deployment/ui_config.py +1 -1
  125. ksadk/detection/__init__.py +1 -1
  126. ksadk/detection/detector.py +146 -83
  127. ksadk/detection/mcp_detector.py +9 -6
  128. ksadk/events/__init__.py +25 -0
  129. ksadk/events/parser.py +191 -0
  130. ksadk/events/replay.py +37 -0
  131. ksadk/events/runtime_event.py +264 -0
  132. ksadk/events/store.py +317 -0
  133. ksadk/harness/__init__.py +34 -0
  134. ksadk/harness/app.py +278 -0
  135. ksadk/harness/config.py +181 -0
  136. ksadk/harness/reasoner.py +105 -0
  137. ksadk/harness/runner.py +211 -0
  138. ksadk/harness/sandbox.py +141 -0
  139. ksadk/harness/tools.py +222 -0
  140. ksadk/hermes_terminal.py +23 -12
  141. ksadk/identity/resolver.py +15 -9
  142. ksadk/ids.py +32 -0
  143. ksadk/knowledge_base/adk_tool.py +1 -1
  144. ksadk/knowledge_base/client.py +23 -29
  145. ksadk/managed_runtime.py +188 -0
  146. ksadk/markdown.py +5 -2
  147. ksadk/mcp_runtime/__init__.py +9 -6
  148. ksadk/memory/__init__.py +1 -1
  149. ksadk/memory/adk/__init__.py +2 -0
  150. ksadk/memory/adk/backends/base_ltm_backend.py +2 -6
  151. ksadk/memory/adk/backends/http_ltm_backend.py +13 -21
  152. ksadk/memory/adk/backends/inmemory_ltm_backend.py +7 -13
  153. ksadk/memory/adk/backends/sdk_ltm_backend.py +26 -33
  154. ksadk/memory/adk/long_term_memory.py +31 -35
  155. ksadk/memory/adk/resilient_session_service.py +4 -5
  156. ksadk/memory/adk/short_term_memory.py +12 -21
  157. ksadk/memory/adk_tool.py +3 -2
  158. ksadk/memory/backends/base.py +19 -19
  159. ksadk/memory/backends/memory.py +24 -25
  160. ksadk/memory/backends/redis.py +31 -30
  161. ksadk/memory/langchain_tool.py +2 -1
  162. ksadk/memory/manager.py +52 -47
  163. ksadk/memory/service.py +10 -8
  164. ksadk/model_policy.py +15 -7
  165. ksadk/model_proxy/__init__.py +51 -0
  166. ksadk/model_proxy/bootstrap.py +80 -0
  167. ksadk/model_proxy/cache.py +165 -0
  168. ksadk/model_proxy/config.py +45 -0
  169. ksadk/model_proxy/demo_webui.py +115 -0
  170. ksadk/model_proxy/detect.py +145 -0
  171. ksadk/model_proxy/gate.py +68 -0
  172. ksadk/model_proxy/namespace.py +173 -0
  173. ksadk/model_proxy/protocol_proxy.py +22 -0
  174. ksadk/model_proxy/server.py +300 -0
  175. ksadk/model_proxy/transform.py +691 -0
  176. ksadk/openclaw_gateway.py +29 -14
  177. ksadk/runners/adk_runner.py +345 -120
  178. ksadk/runners/base_runner.py +46 -29
  179. ksadk/runners/codex_runner.py +132 -0
  180. ksadk/runners/deepagents_runner.py +0 -1
  181. ksadk/runners/factory.py +17 -5
  182. ksadk/runners/langchain_runner.py +29 -742
  183. ksadk/runners/langgraph_runner.py +352 -90
  184. ksadk/runners/patch_langchain.py +16 -16
  185. ksadk/runners/remote_runner.py +134 -33
  186. ksadk/runners/usage_accumulator.py +1 -0
  187. ksadk/runners/utils/langfuse.py +3 -3
  188. ksadk/runners/utils/loader.py +7 -7
  189. ksadk/runtime/__init__.py +41 -0
  190. ksadk/runtime/adapter.py +345 -0
  191. ksadk/runtime/framework_adapters.py +124 -0
  192. ksadk/runtime/preprocessing.py +118 -0
  193. ksadk/runtime/runner_adapter.py +873 -0
  194. ksadk/runtime_context.py +18 -3
  195. ksadk/runtime_state.py +0 -1
  196. ksadk/sandbox/__init__.py +4 -1
  197. ksadk/sandbox/backends/__init__.py +4 -1
  198. ksadk/sandbox/backends/e2b.py +13 -5
  199. ksadk/sandbox/backends/local_process.py +11 -3
  200. ksadk/sandbox/base.py +10 -15
  201. ksadk/sandbox/factory.py +14 -4
  202. ksadk/sandbox/registry.py +57 -6
  203. ksadk/server/api_models.py +15 -5
  204. ksadk/server/app.py +455 -3885
  205. ksadk/server/composition.py +21 -0
  206. ksadk/server/factory.py +624 -0
  207. ksadk/server/routes/__init__.py +1 -0
  208. ksadk/server/routes/checkpoint_resolution.py +116 -0
  209. ksadk/server/routes/common.py +713 -0
  210. ksadk/server/routes/control.py +327 -0
  211. ksadk/server/routes/dependencies.py +98 -0
  212. ksadk/server/routes/misc.py +448 -0
  213. ksadk/server/routes/models.py +443 -0
  214. ksadk/server/routes/openai_compat.py +207 -0
  215. ksadk/server/routes/projection.py +795 -0
  216. ksadk/server/routes/routers.py +52 -0
  217. ksadk/server/routes/run.py +726 -0
  218. ksadk/server/routes/sessions.py +649 -0
  219. ksadk/server/routes/streaming.py +223 -0
  220. ksadk/server/routes/workspace.py +381 -0
  221. ksadk/server/static/assets/{ArtifactsPanel-D-SSn2ee.js → ArtifactsPanel-Cjnqt-8W.js} +1 -1
  222. ksadk/server/static/assets/CodeBlock-BqyqZfuB.js +9 -0
  223. ksadk/server/static/assets/MathMessageMarkdown-BpH7jiFM.js +8 -0
  224. ksadk/server/static/assets/MermaidBlock-DWuxETaJ.js +303 -0
  225. ksadk/server/static/assets/NativeTerminalPanel-MDTopWMO.js +1 -0
  226. ksadk/server/static/assets/{arc-BA13sHc9.js → arc-CFKwSk_B.js} +1 -1
  227. ksadk/server/static/assets/architecture-7EHR7CIX-CynqOWjZ.js +1 -0
  228. ksadk/server/static/assets/{architectureDiagram-3BPJPVTR-DzJzgVoL.js → architectureDiagram-3BPJPVTR-Dej8jX8c.js} +1 -1
  229. ksadk/server/static/assets/{blockDiagram-GPEHLZMM-UTdVcZhn.js → blockDiagram-GPEHLZMM-1F64jqvy.js} +1 -1
  230. ksadk/server/static/assets/{c4Diagram-AAUBKEIU-Dix0GD4m.js → c4Diagram-AAUBKEIU-9q7AUAKb.js} +1 -1
  231. ksadk/server/static/assets/channel-iUGv2N24.js +1 -0
  232. ksadk/server/static/assets/{chunk-2J33WTMH-C2JxuZ42.js → chunk-2J33WTMH-6qgwJm7Q.js} +1 -1
  233. ksadk/server/static/assets/{chunk-4BX2VUAB-Be57QPgD.js → chunk-4BX2VUAB-CsWIQRhc.js} +1 -1
  234. ksadk/server/static/assets/{chunk-55IACEB6-WjSuy4nv.js → chunk-55IACEB6-BK8paA20.js} +1 -1
  235. ksadk/server/static/assets/{chunk-727SXJPM-BOovP-b5.js → chunk-727SXJPM-B-JEhy7h.js} +1 -1
  236. ksadk/server/static/assets/{chunk-AQP2D5EJ-DOmZNmWj.js → chunk-AQP2D5EJ-DYBvMHAa.js} +1 -1
  237. ksadk/server/static/assets/{chunk-FMBD7UC4-DzwlodkU.js → chunk-FMBD7UC4-BGhvzDYt.js} +1 -1
  238. ksadk/server/static/assets/{chunk-ND2GUHAM-DMqAikEU.js → chunk-ND2GUHAM-D98vPd-E.js} +1 -1
  239. ksadk/server/static/assets/chunk-QZHKN3VN-YQIEXeF6.js +1 -0
  240. ksadk/server/static/assets/classDiagram-4FO5ZUOK-CDAUuoXK.js +1 -0
  241. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-CDAUuoXK.js +1 -0
  242. ksadk/server/static/assets/{cose-bilkent-S5V4N54A-Zhy2GBnP.js → cose-bilkent-S5V4N54A-CX3yotHq.js} +1 -1
  243. ksadk/server/static/assets/{dagre-BM42HDAG-CbKrtIUz.js → dagre-BM42HDAG-C7TguAWo.js} +1 -1
  244. ksadk/server/static/assets/{diagram-2AECGRRQ-BRApgQRK.js → diagram-2AECGRRQ-Dd17_kws.js} +1 -1
  245. ksadk/server/static/assets/{diagram-5GNKFQAL-D0xbnDiK.js → diagram-5GNKFQAL-DVIClIil.js} +1 -1
  246. ksadk/server/static/assets/{diagram-KO2AKTUF-CVugVI9L.js → diagram-KO2AKTUF-Df_3gYQa.js} +1 -1
  247. ksadk/server/static/assets/{diagram-LMA3HP47-DozUGgee.js → diagram-LMA3HP47-BhLk6ZtA.js} +1 -1
  248. ksadk/server/static/assets/{diagram-OG6HWLK6-ZOYsKlru.js → diagram-OG6HWLK6-D4GNGvuu.js} +1 -1
  249. ksadk/server/static/assets/{dist-DmFaq_Iy.js → dist-6CVKuTAe.js} +1 -1
  250. ksadk/server/static/assets/{dist-8EEyGgDx.js → dist-BUHRxvDG.js} +1 -1
  251. ksadk/server/static/assets/{dist-B0NP_Z0z.js → dist-BZ9n9AjO.js} +1 -1
  252. ksadk/server/static/assets/{dist-DMezvBGJ.js → dist-BibcG1V9.js} +1 -1
  253. ksadk/server/static/assets/{dist-C3HIIaN5.js → dist-Bs-jQcRX.js} +1 -1
  254. ksadk/server/static/assets/{dist-BrCcQ47T.js → dist-C2xjE7cO.js} +1 -1
  255. ksadk/server/static/assets/{dist-Dp0k7bWI.js → dist-C7-3jInC.js} +1 -1
  256. ksadk/server/static/assets/{dist-D-xOD048.js → dist-C99THtIA.js} +1 -1
  257. ksadk/server/static/assets/{dist-CkEKJFtk.js → dist-CGcp2ex8.js} +1 -1
  258. ksadk/server/static/assets/{dist-DyOkZmze.js → dist-CVQRZjPu.js} +1 -1
  259. ksadk/server/static/assets/{dist-BssVmjIo.js → dist-Cf23NY4L.js} +1 -1
  260. ksadk/server/static/assets/{dist-BIJVDMuB.js → dist-CgF3fj15.js} +1 -1
  261. ksadk/server/static/assets/{dist-2hInLS_J.js → dist-Cwt7koer.js} +1 -1
  262. ksadk/server/static/assets/{dist-DyWsb78Q.js → dist-D82mtD2s.js} +1 -1
  263. ksadk/server/static/assets/{dist-D-JMdWPQ.js → dist-DF06ORQo.js} +1 -1
  264. ksadk/server/static/assets/{dist-BmlMPsCc.js → dist-DHn6nBzr.js} +1 -1
  265. ksadk/server/static/assets/{dist-gX6GOLKq.js → dist-Djgl2wVZ.js} +1 -1
  266. ksadk/server/static/assets/{dist-DpKtt4Bo.js → dist-DlzCRy0S.js} +1 -1
  267. ksadk/server/static/assets/{dist-8_SfK1IP.js → dist-DqNnNFrw.js} +1 -1
  268. ksadk/server/static/assets/{dist-D57wnGWd.js → dist-DyvYLMW9.js} +1 -1
  269. ksadk/server/static/assets/{dist-CPBtqRTW.js → dist-eoW6tZXA.js} +1 -1
  270. ksadk/server/static/assets/{dist-DL_NKc_z.js → dist-ivOya1LD.js} +1 -1
  271. ksadk/server/static/assets/{erDiagram-TEJ5UH35-Bk-9bgE5.js → erDiagram-TEJ5UH35-CnfRcY2M.js} +1 -1
  272. ksadk/server/static/assets/eventmodeling-FCH6USID-ChYO-ijM.js +1 -0
  273. ksadk/server/static/assets/{flowDiagram-I6XJVG4X-Dn9kZVuZ.js → flowDiagram-I6XJVG4X-DGaJjGNJ.js} +1 -1
  274. ksadk/server/static/assets/{ganttDiagram-6RSMTGT7-BGxXlJqm.js → ganttDiagram-6RSMTGT7-DpCoB2g9.js} +1 -1
  275. ksadk/server/static/assets/gitGraph-WXDBUCRP-BN_0Fk-j.js +1 -0
  276. ksadk/server/static/assets/{gitGraphDiagram-PVQCEYII-C7Q0X-wi.js → gitGraphDiagram-PVQCEYII-9IKVFBVT.js} +1 -1
  277. ksadk/server/static/assets/index-QSwCHuB8.js +177 -0
  278. ksadk/server/static/assets/index-jOPmTOZH.css +2 -0
  279. ksadk/server/static/assets/info-J43DQDTF-Cp6o3vId.js +1 -0
  280. ksadk/server/static/assets/{infoDiagram-5YYISTIA-BO_CSqq5.js → infoDiagram-5YYISTIA-CYIIsb8y.js} +1 -1
  281. ksadk/server/static/assets/{ishikawaDiagram-YF4QCWOH-eYLPLd46.js → ishikawaDiagram-YF4QCWOH-DLOHGvWw.js} +1 -1
  282. ksadk/server/static/assets/{journeyDiagram-JHISSGLW-De9geSb0.js → journeyDiagram-JHISSGLW-BIzKeejT.js} +1 -1
  283. ksadk/server/static/assets/{kanban-definition-UN3LZRKU-Cs80kQto.js → kanban-definition-UN3LZRKU-BWHoFSw2.js} +1 -1
  284. ksadk/server/static/assets/{katex-DSrCFD8n.js → katex-DATssjp1.js} +1 -1
  285. ksadk/server/static/assets/{linear-CN9sbKTF.js → linear-CvMBw9cA.js} +1 -1
  286. ksadk/server/static/assets/{mermaid-parser.core-DlgSBU8l.js → mermaid-parser.core-mGAcEwcq.js} +2 -2
  287. ksadk/server/static/assets/{mindmap-definition-RKZ34NQL-9afz7Oug.js → mindmap-definition-RKZ34NQL-CSAQxEAe.js} +1 -1
  288. ksadk/server/static/assets/packet-YPE3B663-wQzct3cT.js +1 -0
  289. ksadk/server/static/assets/pie-LRSECV5Y-BgTQiv-9.js +1 -0
  290. ksadk/server/static/assets/{pieDiagram-4H26LBE5-DPv_VstN.js → pieDiagram-4H26LBE5-By-ra07M.js} +1 -1
  291. ksadk/server/static/assets/{quadrantDiagram-W4KKPZXB-o77wZ1XK.js → quadrantDiagram-W4KKPZXB-CxIR4JXI.js} +1 -1
  292. ksadk/server/static/assets/radar-GUYGQ44K-BIq5fXsn.js +1 -0
  293. ksadk/server/static/assets/{requirementDiagram-4Y6WPE33-BYVw81VC.js → requirementDiagram-4Y6WPE33-DpW90iu3.js} +1 -1
  294. ksadk/server/static/assets/{sankeyDiagram-5OEKKPKP-B7nZFMKT.js → sankeyDiagram-5OEKKPKP-DpGa6EAV.js} +1 -1
  295. ksadk/server/static/assets/{sequenceDiagram-3UESZ5HK-BGRRrFw5.js → sequenceDiagram-3UESZ5HK-NTKNGGe5.js} +1 -1
  296. ksadk/server/static/assets/{stateDiagram-AJRCARHV-BUfHCoPs.js → stateDiagram-AJRCARHV-DGpd9yFG.js} +1 -1
  297. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-B3o579IQ.js +1 -0
  298. ksadk/server/static/assets/{timeline-definition-PNZ67QCA-FbCTGrf9.js → timeline-definition-PNZ67QCA-jqoYs3jQ.js} +1 -1
  299. ksadk/server/static/assets/treeView-BLDUP644-Dqi-E0EM.js +1 -0
  300. ksadk/server/static/assets/treemap-LRROVOQU-ClQP9CJ9.js +1 -0
  301. ksadk/server/static/assets/{vennDiagram-CIIHVFJN-DWgwtPsJ.js → vennDiagram-CIIHVFJN-l3Z7-wbP.js} +1 -1
  302. ksadk/server/static/assets/wardley-L42UT6IY-8XLvnNIs.js +1 -0
  303. ksadk/server/static/assets/{wardleyDiagram-YWT4CUSO-2x8G-tTM.js → wardleyDiagram-YWT4CUSO-BR54GPmr.js} +1 -1
  304. ksadk/server/static/assets/{xychartDiagram-2RQKCTM6-Drma3AYl.js → xychartDiagram-2RQKCTM6-SkiH8GsK.js} +1 -1
  305. ksadk/server/static/index.html +2 -2
  306. ksadk/server/terminal_sessions.py +111 -58
  307. ksadk/sessions/__init__.py +69 -19
  308. ksadk/sessions/base.py +31 -11
  309. ksadk/sessions/continuity.py +2 -3
  310. ksadk/sessions/in_memory.py +46 -2
  311. ksadk/sessions/local_service.py +148 -17
  312. ksadk/sessions/postgres_service.py +143 -25
  313. ksadk/sessions/resilient.py +36 -8
  314. ksadk/skills/models.py +17 -5
  315. ksadk/skills/package_store.py +5 -2
  316. ksadk/skills/runtime/agent.py +20 -5
  317. ksadk/skills/runtime/artifacts.py +1 -5
  318. ksadk/skills/runtime/backends/e2b.py +10 -4
  319. ksadk/skills/runtime/backends/local.py +15 -3
  320. ksadk/skills/runtime/base.py +1 -2
  321. ksadk/skills/runtime/executor.py +10 -3
  322. ksadk/skills/runtime/factory.py +4 -2
  323. ksadk/skills/runtime/loader.py +1 -2
  324. ksadk/skills/runtime/registry.py +15 -10
  325. ksadk/skills/runtime/request.py +3 -1
  326. ksadk/skills/service_client.py +38 -17
  327. ksadk/skills/tool_defs.py +15 -10
  328. ksadk/terminal_exec_policy.py +3 -4
  329. ksadk/tools/gateway.py +92 -15
  330. ksadk/tools/result_budget.py +12 -4
  331. ksadk/toolsets/__init__.py +134 -36
  332. ksadk/toolsets/platform.py +21 -5
  333. ksadk/toolsets/sandbox.py +82 -16
  334. ksadk/toolsets/skills.py +200 -39
  335. ksadk/toolsets/web.py +123 -26
  336. ksadk/toolsets/workspace.py +212 -101
  337. ksadk/tracing/exporters/inmemory_exporter.py +62 -51
  338. ksadk/tracing/exporters/langfuse_exporter.py +91 -76
  339. ksadk/tracing/setup.py +69 -53
  340. ksadk/tracing/span_utils.py +5 -2
  341. ksadk/tui/loop.py +78 -30
  342. ksadk/tui/stream_render.py +1 -0
  343. ksadk/ui_config.py +5 -3
  344. ksadk/version.py +1 -1
  345. ksadk_runtime_common/schemas/runtime_event_v1.json +95 -0
  346. agentengine_sdk_python-0.7.0.dist-info/RECORD +0 -482
  347. ksadk/server/static/assets/CodeBlock-P16VOLYi.js +0 -9
  348. ksadk/server/static/assets/MathMessageMarkdown-CdGiQWHR.js +0 -8
  349. ksadk/server/static/assets/MermaidBlock-IOcal8cm.js +0 -303
  350. ksadk/server/static/assets/NativeTerminalPanel-DGSDWsei.js +0 -1
  351. ksadk/server/static/assets/architecture-7EHR7CIX-BvUlsA6l.js +0 -1
  352. ksadk/server/static/assets/channel-CTuydARX.js +0 -1
  353. ksadk/server/static/assets/chunk-QZHKN3VN-BnCydivS.js +0 -1
  354. ksadk/server/static/assets/classDiagram-4FO5ZUOK-BNHg45Be.js +0 -1
  355. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-BNHg45Be.js +0 -1
  356. ksadk/server/static/assets/eventmodeling-FCH6USID-DsAgWnlf.js +0 -1
  357. ksadk/server/static/assets/gitGraph-WXDBUCRP-BIao9Yjg.js +0 -1
  358. ksadk/server/static/assets/index-C00Lwg3L.js +0 -165
  359. ksadk/server/static/assets/index-DAURbCsP.css +0 -1
  360. ksadk/server/static/assets/info-J43DQDTF-CyipqGxU.js +0 -1
  361. ksadk/server/static/assets/packet-YPE3B663-CGkyRxlg.js +0 -1
  362. ksadk/server/static/assets/pie-LRSECV5Y-M0uWAf4n.js +0 -1
  363. ksadk/server/static/assets/radar-GUYGQ44K-Bdbm24-x.js +0 -1
  364. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-8xBN_gLM.js +0 -1
  365. ksadk/server/static/assets/treeView-BLDUP644-npMo0ak1.js +0 -1
  366. ksadk/server/static/assets/treemap-LRROVOQU-CHdzrrdo.js +0 -1
  367. ksadk/server/static/assets/wardley-L42UT6IY-BEQz7wyy.js +0 -1
  368. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/WHEEL +0 -0
  369. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/entry_points.txt +0 -0
  370. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/licenses/LICENSE +0 -0
  371. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/top_level.txt +0 -0
ksadk/cli/cmd_invoke.py CHANGED
@@ -4,16 +4,18 @@ agentengine invoke - 与已部署的 Agent 进行交互
4
4
  支持 OpenAI 兼容格式调用,支持流式输出
5
5
  """
6
6
 
7
- import click
8
7
  import asyncio
9
8
  import io
10
9
  import json
11
10
  import os
11
+ import time
12
+ import uuid
12
13
  from datetime import datetime
13
14
  from pathlib import Path
14
15
  from typing import Any, Callable, Dict, Optional
15
- import time
16
- import uuid
16
+
17
+ import click
18
+
17
19
  from ksadk.api import AgentEngineAPIError, AgentEngineClient
18
20
  from ksadk.cli.agent_ref import merge_agent_inputs, resolve_agent_ref, resolve_openclaw_ref
19
21
  from ksadk.cli.cmd_files import (
@@ -24,20 +26,28 @@ from ksadk.cli.cmd_files import (
24
26
  _normalize_workspace_dir,
25
27
  _push_workspace_files,
26
28
  )
27
- from ksadk.cli.resource_common import CONTEXT_SETTINGS, CompatibilityAliasCommand, print_compatibility_hint
29
+ from ksadk.cli.resource_common import (
30
+ CONTEXT_SETTINGS,
31
+ CompatibilityAliasCommand,
32
+ print_compatibility_hint,
33
+ )
28
34
  from ksadk.hermes_terminal import run_hermes_terminal_session
29
35
  from ksadk.terminal_client import run_terminal_session
30
36
  from ksadk_runtime_common.workspace_files.constants import DEFAULT_WORKSPACE_MAX_UPLOAD_BYTES
31
37
 
38
+ console: Any = None
39
+ Markdown: Any = None
40
+ Live: Any = None
32
41
  try:
33
- from rich.console import Console
34
- from rich.markdown import Markdown
35
- from rich.live import Live
36
- console = Console()
42
+ from rich.console import Console as RichConsole
43
+ from rich.live import Live as RichLive
44
+ from rich.markdown import Markdown as RichMarkdown
45
+
46
+ console = RichConsole()
47
+ Markdown = RichMarkdown
48
+ Live = RichLive
37
49
  except ImportError:
38
- console = None
39
- Markdown = None
40
- Live = None
50
+ pass
41
51
 
42
52
 
43
53
  @click.command(
@@ -147,9 +157,9 @@ def _resolve_remote_workspace_seed_path(
147
157
  remote_workspace_path: str | None,
148
158
  ) -> str:
149
159
  if remote_workspace_path:
150
- return _normalize_workspace_dir(remote_workspace_path)
160
+ return str(_normalize_workspace_dir(remote_workspace_path))
151
161
  default_name = local_workspace.resolve().name or local_workspace.name or "workspace"
152
- return _normalize_workspace_dir(default_name)
162
+ return str(_normalize_workspace_dir(default_name))
153
163
 
154
164
 
155
165
  def _summarize_local_workspace_dir(
@@ -200,10 +210,12 @@ def _describe_workspace_sync_phase(event: dict[str, Any] | None) -> str:
200
210
  return "同步 workspace"
201
211
 
202
212
 
203
- def _render_workspace_sync_progress_bar(current: object | None, total: object | None, *, width: int = 20) -> str:
213
+ def _render_workspace_sync_progress_bar(
214
+ current: object | None, total: object | None, *, width: int = 20
215
+ ) -> str:
204
216
  try:
205
- current_value = int(current or 0)
206
- total_value = max(int(total or 0), 1)
217
+ current_value = int(str(current or 0))
218
+ total_value = max(int(str(total or 0)), 1)
207
219
  except (TypeError, ValueError):
208
220
  current_value = 0
209
221
  total_value = 1
@@ -214,8 +226,8 @@ def _render_workspace_sync_progress_bar(current: object | None, total: object |
214
226
 
215
227
  def _format_workspace_sync_percent(current: object | None, total: object | None) -> str:
216
228
  try:
217
- current_value = float(current or 0)
218
- total_value = max(float(total or 0), 1.0)
229
+ current_value = float(str(current or 0))
230
+ total_value = max(float(str(total or 0)), 1.0)
219
231
  except (TypeError, ValueError):
220
232
  current_value = 0.0
221
233
  total_value = 1.0
@@ -244,7 +256,8 @@ def _build_workspace_sync_progress_emitter(*, verbose: bool) -> Callable[[dict[s
244
256
  click.secho(
245
257
  "📂 准备同步 workspace: "
246
258
  f"{event.get('total_files', 0)} 个文件,"
247
- f"{_format_size(event.get('total_bytes', 0))} -> workspace:/{event.get('remote_path', '.')}",
259
+ f"{_format_size(event.get('total_bytes', 0))} -> "
260
+ f"workspace:/{event.get('remote_path', '.')}",
248
261
  fg="blue",
249
262
  )
250
263
  ignored_artifacts = list(event.get("ignored_artifacts") or [])
@@ -324,7 +337,7 @@ def _extract_workspace_upload_limit(bootstrap: dict[str, Any] | None) -> int | N
324
337
  return None
325
338
  raw_limit = workspace.get("max_upload_bytes") or workspace.get("MaxUploadBytes")
326
339
  try:
327
- limit = int(raw_limit)
340
+ limit = int(str(raw_limit))
328
341
  except (TypeError, ValueError):
329
342
  return None
330
343
  return limit if limit > 0 else None
@@ -336,7 +349,7 @@ async def _lookup_workspace_upload_limit(
336
349
  region: str,
337
350
  ) -> int:
338
351
  if not agent_ref:
339
- return DEFAULT_WORKSPACE_MAX_UPLOAD_BYTES
352
+ return int(DEFAULT_WORKSPACE_MAX_UPLOAD_BYTES)
340
353
 
341
354
  try:
342
355
  async with AgentEngineClient(region=region) as client:
@@ -345,9 +358,9 @@ async def _lookup_workspace_upload_limit(
345
358
  else:
346
359
  payload = await client.get_agent_ui_bootstrap(name=agent_ref)
347
360
  except Exception:
348
- return DEFAULT_WORKSPACE_MAX_UPLOAD_BYTES
361
+ return int(DEFAULT_WORKSPACE_MAX_UPLOAD_BYTES)
349
362
 
350
- return _extract_workspace_upload_limit(payload) or DEFAULT_WORKSPACE_MAX_UPLOAD_BYTES
363
+ return int(_extract_workspace_upload_limit(payload) or DEFAULT_WORKSPACE_MAX_UPLOAD_BYTES)
351
364
 
352
365
 
353
366
  async def _sync_local_workspace_for_hermes_invoke(
@@ -394,7 +407,8 @@ async def _sync_local_workspace_for_hermes_invoke(
394
407
  if item["size_bytes"] > max_upload_bytes:
395
408
  raise click.ClickException(
396
409
  "本地目录中存在超过远端 workspace 上传上限的文件:"
397
- f"{item['path']}({_format_size(item['size_bytes'])} > {_format_size(max_upload_bytes)})"
410
+ f"{item['path']}({_format_size(item['size_bytes'])} > "
411
+ f"{_format_size(max_upload_bytes)})"
398
412
  )
399
413
 
400
414
  if summary["total_bytes"] > max_upload_bytes:
@@ -412,7 +426,7 @@ async def _sync_local_workspace_for_hermes_invoke(
412
426
  progress_callback(event)
413
427
 
414
428
  try:
415
- return await _push_workspace_files(
429
+ result = await _push_workspace_files(
416
430
  agent_ref=agent_ref,
417
431
  local_dir=local_dir,
418
432
  remote_path=remote_path,
@@ -424,11 +438,12 @@ async def _sync_local_workspace_for_hermes_invoke(
424
438
  ignore_dev_artifacts=True,
425
439
  ignore_git_artifacts=".git" in list(summary.get("ignored_artifacts") or []),
426
440
  )
441
+ if not isinstance(result, dict):
442
+ raise click.ClickException("同步远端 workspace 返回了无效响应")
443
+ return result
427
444
  except AgentEngineAPIError as exc:
428
445
  phase = _describe_workspace_sync_phase(last_progress)
429
- raise click.ClickException(
430
- f"同步远端 workspace 失败({phase}):{exc.message}"
431
- ) from exc
446
+ raise click.ClickException(f"同步远端 workspace 失败({phase}):{exc.message}") from exc
432
447
 
433
448
 
434
449
  def run_invoke_command(
@@ -479,7 +494,7 @@ def run_invoke_command(
479
494
  state = _load_state()
480
495
  latest_access: dict[str, Any] = {}
481
496
  target_agent: str | None = None
482
-
497
+
483
498
  normalized_transport = (transport or "auto").strip().lower() or "auto"
484
499
 
485
500
  # 确定 Endpoint
@@ -518,7 +533,7 @@ def run_invoke_command(
518
533
  endpoint = latest_access["endpoint"]
519
534
  elif not agent_input or _state_matches_target(state, target_agent):
520
535
  endpoint = state.get("endpoint")
521
-
536
+
522
537
  if not endpoint:
523
538
  # 自动获取
524
539
  endpoint = _get_endpoint(target_agent, region)
@@ -548,7 +563,7 @@ def run_invoke_command(
548
563
  latest_access=latest_access,
549
564
  )
550
565
 
551
- click.secho(f"🤖 连接到 Agent", fg="blue", bold=True)
566
+ click.secho("🤖 连接到 Agent", fg="blue", bold=True)
552
567
  click.echo(f" Endpoint: {endpoint}")
553
568
  if _is_openclaw_target(next_state, latest_access):
554
569
  if runtime_api_key:
@@ -561,7 +576,7 @@ def run_invoke_command(
561
576
  click.echo(f" Auth: Bearer {_mask_secret(api_key)}")
562
577
  else:
563
578
  click.secho(" ⚠️ 未发现 API Key,尝试匿名调用", fg="yellow")
564
-
579
+
565
580
  if insecure:
566
581
  click.secho(" ⚠️ SSL 证书验证已禁用", fg="yellow")
567
582
 
@@ -592,7 +607,6 @@ def run_invoke_command(
592
607
  )
593
608
  else:
594
609
  is_hermes_target = _is_hermes_target(next_state, latest_access)
595
- is_openclaw_target = _is_openclaw_target(next_state, latest_access)
596
610
  if normalized_transport == "chat" and is_hermes_target:
597
611
  click.secho("❌ Hermes 不再支持 ksadk 通用 chat TUI。", fg="red")
598
612
  click.echo(" 浏览器聊天页请改用: agentengine hermes open --chat")
@@ -691,7 +705,9 @@ def run_invoke_command(
691
705
  show_thinking,
692
706
  api_format=api_format_resolved,
693
707
  responses_session_header=(
694
- "x-openclaw-session-key" if _is_openclaw_target(next_state, latest_access) else None
708
+ "x-openclaw-session-key"
709
+ if _is_openclaw_target(next_state, latest_access)
710
+ else None
695
711
  ),
696
712
  no_alt_screen=no_alt_screen,
697
713
  region=region,
@@ -699,14 +715,12 @@ def run_invoke_command(
699
715
  )
700
716
 
701
717
 
702
-
703
-
704
718
  def _invoke_tui(
705
719
  endpoint: str,
706
- api_key: str = None,
707
- session_id: str = None,
720
+ api_key: Optional[str] = None,
721
+ session_id: Optional[str] = None,
708
722
  insecure: bool = False,
709
- model: str = None,
723
+ model: Optional[str] = None,
710
724
  show_thinking: bool = False,
711
725
  api_format: str = "chat_completions",
712
726
  responses_session_header: str | None = None,
@@ -740,7 +754,7 @@ def _invoke_tui(
740
754
  if matched is None and runner.available_models:
741
755
  matched = runner.available_models[0]
742
756
  if matched:
743
- runner.model_metadata = matched
757
+ setattr(runner, "model_metadata", matched)
744
758
  # 用户未指定 --model 时,用 ListAgentModels 的 current 作为 runner.model,
745
759
  # 让 TUI 启动即显示真实模型名(而非 unknown)。
746
760
  if not runner.model and matched.get("id"):
@@ -751,7 +765,7 @@ def _invoke_tui(
751
765
  _fetch_tui_model_metadata(endpoint=endpoint, api_key=api_key, model=model)
752
766
  )
753
767
  if model_metadata:
754
- runner.model_metadata = model_metadata
768
+ setattr(runner, "model_metadata", model_metadata)
755
769
 
756
770
  run_tui(runner, show_thinking=show_thinking, project_dir=".", no_alt_screen=no_alt_screen)
757
771
 
@@ -772,7 +786,8 @@ async def _fetch_tui_model_list(
772
786
  from ksadk.api.client import AgentEngineClient
773
787
 
774
788
  async with AgentEngineClient(region=region) as client:
775
- return await client.list_agent_models(agent_id=agent_id)
789
+ payload = await client.list_agent_models(agent_id=agent_id)
790
+ return payload if isinstance(payload, dict) else None
776
791
  except Exception:
777
792
  return None
778
793
 
@@ -803,7 +818,8 @@ async def _fetch_tui_model_metadata(
803
818
  raw_models = [item.get("_provider_raw_model") or item for item in catalog]
804
819
  matched = find_model_in_catalog(raw_models, model)
805
820
  if matched is not None:
806
- return normalize_model_metadata(matched)
821
+ metadata = normalize_model_metadata(matched)
822
+ return metadata if isinstance(metadata, dict) else None
807
823
  if model:
808
824
  return None
809
825
  if len(catalog) == 1:
@@ -816,10 +832,11 @@ async def _fetch_tui_model_metadata(
816
832
  def _load_state() -> dict:
817
833
  """从 .agentengine.state 加载状态"""
818
834
  import yaml
835
+
819
836
  state_file = Path(".") / ".agentengine.state"
820
837
  if state_file.exists():
821
838
  try:
822
- with open(state_file, 'r', encoding='utf-8') as f:
839
+ with open(state_file, "r", encoding="utf-8") as f:
823
840
  return yaml.safe_load(f) or {}
824
841
  except Exception:
825
842
  pass
@@ -847,15 +864,13 @@ def _extract_remote_access(detail: Dict[str, Any]) -> Dict[str, Any]:
847
864
  if not isinstance(detail, dict):
848
865
  return {}
849
866
 
850
- basic = detail.get("basic") if isinstance(detail.get("basic"), dict) else {}
851
- quick = detail.get("quick_access") if isinstance(detail.get("quick_access"), dict) else {}
852
-
853
- deployment = detail.get("deployment") if isinstance(detail.get("deployment"), dict) else {}
854
- framework = (
855
- deployment.get("framework")
856
- or basic.get("framework")
857
- or detail.get("framework")
858
- )
867
+ basic_value = detail.get("basic")
868
+ quick_value = detail.get("quick_access")
869
+ deployment_value = detail.get("deployment")
870
+ basic: Dict[str, Any] = basic_value if isinstance(basic_value, dict) else {}
871
+ quick: Dict[str, Any] = quick_value if isinstance(quick_value, dict) else {}
872
+ deployment: Dict[str, Any] = deployment_value if isinstance(deployment_value, dict) else {}
873
+ framework = deployment.get("framework") or basic.get("framework") or detail.get("framework")
859
874
 
860
875
  return {
861
876
  "agent_id": basic.get("agent_id") or detail.get("agent_id"),
@@ -873,9 +888,13 @@ async def _fetch_remote_access(target_agent: str, region: str) -> Dict[str, Any]
873
888
 
874
889
  async with AgentEngineClient(region=region) as client:
875
890
  try:
876
- return _extract_remote_access(await client.get_agent(agent_id=target_agent, include_api_key=True))
891
+ return _extract_remote_access(
892
+ await client.get_agent(agent_id=target_agent, include_api_key=True)
893
+ )
877
894
  except Exception:
878
- return _extract_remote_access(await client.get_agent(name=target_agent, include_api_key=True))
895
+ return _extract_remote_access(
896
+ await client.get_agent(name=target_agent, include_api_key=True)
897
+ )
879
898
 
880
899
 
881
900
  def _refresh_remote_access(
@@ -904,22 +923,20 @@ def _refresh_remote_access(
904
923
 
905
924
 
906
925
  def _is_hermes_target(state: dict, latest_access: dict) -> bool:
907
- framework = str(
908
- latest_access.get("framework")
909
- or state.get("framework")
910
- or state.get("type")
911
- or ""
912
- ).strip().lower()
926
+ framework = (
927
+ str(latest_access.get("framework") or state.get("framework") or state.get("type") or "")
928
+ .strip()
929
+ .lower()
930
+ )
913
931
  return framework == "hermes"
914
932
 
915
933
 
916
934
  def _is_openclaw_target(state: dict, latest_access: dict) -> bool:
917
- framework = str(
918
- latest_access.get("framework")
919
- or state.get("framework")
920
- or state.get("type")
921
- or ""
922
- ).strip().lower()
935
+ framework = (
936
+ str(latest_access.get("framework") or state.get("framework") or state.get("type") or "")
937
+ .strip()
938
+ .lower()
939
+ )
923
940
  return framework == "openclaw"
924
941
 
925
942
 
@@ -933,13 +950,17 @@ def _mask_secret(secret: str | None) -> str:
933
950
 
934
951
 
935
952
  def _openclaw_auth_mode(state: dict, latest_access: dict) -> str:
936
- return str(
937
- latest_access.get("openclaw_auth_mode")
938
- or latest_access.get("gateway_auth_mode")
939
- or state.get("openclaw_auth_mode")
940
- or state.get("gateway_auth_mode")
941
- or ""
942
- ).strip().lower()
953
+ return (
954
+ str(
955
+ latest_access.get("openclaw_auth_mode")
956
+ or latest_access.get("gateway_auth_mode")
957
+ or state.get("openclaw_auth_mode")
958
+ or state.get("gateway_auth_mode")
959
+ or ""
960
+ )
961
+ .strip()
962
+ .lower()
963
+ )
943
964
 
944
965
 
945
966
  def _select_runtime_api_key(
@@ -967,11 +988,14 @@ def _select_runtime_api_key(
967
988
  auth_mode = _openclaw_auth_mode(state, latest_access)
968
989
  if auth_mode in {"token", "password"}:
969
990
  raise click.ClickException(
970
- "当前 OpenClaw Gateway 为 token/password 模式,agentengine invoke 需要 OpenClaw Gateway token。\n"
991
+ "当前 OpenClaw Gateway 为 token/password 模式,"
992
+ "agentengine invoke 需要 OpenClaw Gateway token。\n"
971
993
  "请使用: agentengine invoke --gateway-token <token>\n"
972
994
  "或设置: OPENCLAW_GATEWAY_TOKEN=<token> agentengine invoke\n"
973
- "如果部署时传过 OPENCLAW_GATEWAY_TOKEN,请重新运行部署让本地 .agentengine.state 记录该 token。\n"
974
- "注意:这里不是 AgentEngine API Key(ak-*),而是 OPENCLAW_GATEWAY_TOKEN/OPENCLAW_GATEWAY_PASSWORD。"
995
+ "如果部署时传过 OPENCLAW_GATEWAY_TOKEN,请重新运行部署让本地 "
996
+ ".agentengine.state 记录该 token。\n"
997
+ "注意:这里不是 AgentEngine API Key(ak-*),而是 "
998
+ "OPENCLAW_GATEWAY_TOKEN/OPENCLAW_GATEWAY_PASSWORD。"
975
999
  )
976
1000
 
977
1001
  return api_key
@@ -1084,7 +1108,9 @@ async def _probe_responses_route(
1084
1108
  return available
1085
1109
 
1086
1110
 
1087
- def _should_use_hermes_native_tui(*, transport: str, local: bool, state: dict, latest_access: dict) -> bool:
1111
+ def _should_use_hermes_native_tui(
1112
+ *, transport: str, local: bool, state: dict, latest_access: dict
1113
+ ) -> bool:
1088
1114
  if transport == "chat":
1089
1115
  return False
1090
1116
  if transport == "native":
@@ -1094,7 +1120,9 @@ def _should_use_hermes_native_tui(*, transport: str, local: bool, state: dict, l
1094
1120
  return _is_hermes_target(state, latest_access)
1095
1121
 
1096
1122
 
1097
- def _should_use_openclaw_native_tui(*, transport: str, local: bool, state: dict, latest_access: dict) -> bool:
1123
+ def _should_use_openclaw_native_tui(
1124
+ *, transport: str, local: bool, state: dict, latest_access: dict
1125
+ ) -> bool:
1098
1126
  if transport == "chat":
1099
1127
  return False
1100
1128
  if transport == "native":
@@ -1106,14 +1134,16 @@ def _should_use_openclaw_native_tui(*, transport: str, local: bool, state: dict,
1106
1134
 
1107
1135
  def _invoke_hermes_terminal_tui(
1108
1136
  endpoint: str,
1109
- api_key: str = None,
1110
- session_id: str = None,
1137
+ api_key: Optional[str] = None,
1138
+ session_id: Optional[str] = None,
1111
1139
  insecure: bool = False,
1112
1140
  cwd: str | None = None,
1113
1141
  ):
1114
1142
  click.secho("🖥️ Hermes Native Remote TUI", fg="blue", bold=True)
1115
1143
  click.echo(" 退出: Ctrl-D 或 Ctrl-C")
1116
- click.echo(" 新 Pod 首次启动会加载 Hermes tools/skills,可能需要几十秒到 1 分钟;后续进入会更快。")
1144
+ click.echo(
1145
+ " 新 Pod 首次启动会加载 Hermes tools/skills,可能需要几十秒到 1 分钟;后续进入会更快。"
1146
+ )
1117
1147
  try:
1118
1148
  _warmup_hermes_terminal(
1119
1149
  endpoint=endpoint,
@@ -1172,8 +1202,8 @@ def _warmup_hermes_terminal(
1172
1202
 
1173
1203
  def _invoke_openclaw_terminal_tui(
1174
1204
  endpoint: str,
1175
- api_key: str = None,
1176
- session_id: str = None,
1205
+ api_key: Optional[str] = None,
1206
+ session_id: Optional[str] = None,
1177
1207
  insecure: bool = False,
1178
1208
  ):
1179
1209
  click.secho("🖥️ OpenClaw Native Remote TUI", fg="blue", bold=True)
@@ -1206,15 +1236,16 @@ def _get_api_key() -> Optional[str]:
1206
1236
 
1207
1237
  def _get_endpoint(agent_ref: str, region: str) -> str:
1208
1238
  """获取 Agent Endpoint(先按 ID,再按名称)"""
1209
- from ksadk.api import AgentEngineClient
1210
1239
  import asyncio
1211
1240
 
1212
- async def _get():
1241
+ from ksadk.api import AgentEngineClient
1242
+
1243
+ async def _get() -> str:
1213
1244
  async with AgentEngineClient(region=region) as client:
1214
1245
  # 1) 优先按 ID 查询
1215
1246
  try:
1216
1247
  res = await client.get_agent(agent_id=agent_ref)
1217
- endpoint = _extract_remote_access(res).get("endpoint", "")
1248
+ endpoint = str(_extract_remote_access(res).get("endpoint") or "").strip()
1218
1249
  if endpoint:
1219
1250
  return endpoint
1220
1251
  except Exception:
@@ -1222,13 +1253,14 @@ def _get_endpoint(agent_ref: str, region: str) -> str:
1222
1253
 
1223
1254
  # 2) 回退按名称查询
1224
1255
  res = await client.get_agent(name=agent_ref)
1225
- endpoint = _extract_remote_access(res).get("endpoint", "")
1256
+ endpoint = str(_extract_remote_access(res).get("endpoint") or "").strip()
1226
1257
  if endpoint:
1227
1258
  return endpoint
1228
1259
 
1229
1260
  # endpoint 为空时,尽量提取真实 ID 供默认域名拼接
1230
- basic = res.get("basic", {})
1231
- return basic.get("agent_id") or res.get("agent_id") or ""
1261
+ basic_value = res.get("basic")
1262
+ basic = basic_value if isinstance(basic_value, dict) else {}
1263
+ return str(basic.get("agent_id") or res.get("agent_id") or "")
1232
1264
 
1233
1265
  try:
1234
1266
  resolved = asyncio.run(_get())
@@ -1248,16 +1280,16 @@ def _get_endpoint(agent_ref: str, region: str) -> str:
1248
1280
  async def _invoke_once(
1249
1281
  endpoint: str,
1250
1282
  message: str,
1251
- api_key: str = None,
1252
- session_id: str = None,
1283
+ api_key: Optional[str] = None,
1284
+ session_id: Optional[str] = None,
1253
1285
  stream: bool = True,
1254
1286
  insecure: bool = False,
1255
- model: str = None,
1287
+ model: Optional[str] = None,
1256
1288
  api_format: str = "chat_completions",
1257
1289
  ):
1258
1290
  """单次调用"""
1259
1291
  click.echo(f"\n👤 你: {message}")
1260
- click.echo(f"🤖 Agent: ", nl=False)
1292
+ click.echo("🤖 Agent: ", nl=False)
1261
1293
 
1262
1294
  try:
1263
1295
  if stream:
@@ -1265,12 +1297,19 @@ async def _invoke_once(
1265
1297
  if Live and Markdown:
1266
1298
  # 降低刷新率减少闪烁,vertical_overflow="visible"防止回滚丢失
1267
1299
  # 手动控制刷新以减少闪烁
1268
- with Live(Markdown("", justify="left"), console=console, auto_refresh=False, vertical_overflow="visible") as live:
1269
- last_refresh_time = 0
1300
+ with Live(
1301
+ Markdown("", justify="left"),
1302
+ console=console,
1303
+ auto_refresh=False,
1304
+ vertical_overflow="visible",
1305
+ ) as live:
1306
+ last_refresh_time = 0.0
1270
1307
  full_reasoning = ""
1271
- async for chunk in _stream_chat(endpoint, message, api_key, session_id, True, insecure, model, api_format):
1308
+ async for chunk in _stream_chat(
1309
+ endpoint, message, api_key, session_id, True, insecure, model, api_format
1310
+ ):
1272
1311
  content, reasoning = _extract_content(chunk)
1273
-
1312
+
1274
1313
  updated = False
1275
1314
  if reasoning:
1276
1315
  full_reasoning += reasoning
@@ -1278,25 +1317,27 @@ async def _invoke_once(
1278
1317
  if content:
1279
1318
  full_response += content
1280
1319
  updated = True
1281
-
1320
+
1282
1321
  if updated:
1283
1322
  # 构造显示文本
1284
1323
  display_text = ""
1285
1324
  if full_reasoning:
1286
- formatted_reasoning = full_reasoning.replace('\n', '\n> ')
1325
+ formatted_reasoning = full_reasoning.replace("\n", "\n> ")
1287
1326
  display_text += f"> 🧠 **Thinking:**\n> {formatted_reasoning}\n\n"
1288
1327
  display_text += full_response
1289
-
1328
+
1290
1329
  live.update(Markdown(display_text, justify="left"))
1291
-
1330
+
1292
1331
  # 基于时间限流刷新 (每0.2秒一次 = 5 FPS)
1293
1332
  now = time.time()
1294
1333
  if now - last_refresh_time > 0.2:
1295
1334
  live.refresh()
1296
1335
  last_refresh_time = now
1297
- live.refresh() # 确保最后一次刷新
1336
+ live.refresh() # 确保最后一次刷新
1298
1337
  else:
1299
- async for chunk in _stream_chat(endpoint, message, api_key, session_id, True, insecure, model, api_format):
1338
+ async for chunk in _stream_chat(
1339
+ endpoint, message, api_key, session_id, True, insecure, model, api_format
1340
+ ):
1300
1341
  content, reasoning = _extract_content(chunk)
1301
1342
  if reasoning:
1302
1343
  click.secho(reasoning, fg="bright_black", nl=False)
@@ -1304,7 +1345,9 @@ async def _invoke_once(
1304
1345
  print(content, end="", flush=True)
1305
1346
  click.echo() # 换行
1306
1347
  else:
1307
- response = await _chat(endpoint, message, api_key, session_id, insecure, model, api_format)
1348
+ response = await _chat(
1349
+ endpoint, message, api_key, session_id, insecure, model, api_format
1350
+ )
1308
1351
  content = _extract_response_content(response)
1309
1352
  if console and Markdown:
1310
1353
  console.print(Markdown(content))
@@ -1314,16 +1357,15 @@ async def _invoke_once(
1314
1357
  click.secho(f"\n❌ 调用失败: {e}", fg="red")
1315
1358
 
1316
1359
 
1317
-
1318
1360
  async def _chat(
1319
1361
  endpoint: str,
1320
1362
  message: str,
1321
- api_key: str = None,
1322
- session_id: str = None,
1363
+ api_key: Optional[str] = None,
1364
+ session_id: Optional[str] = None,
1323
1365
  insecure: bool = False,
1324
- model: str = None,
1366
+ model: Optional[str] = None,
1325
1367
  api_format: str = "chat_completions",
1326
- ) -> dict:
1368
+ ) -> dict[str, Any]:
1327
1369
  """非流式调用 (OpenAI 兼容格式)"""
1328
1370
  try:
1329
1371
  import httpx
@@ -1334,10 +1376,16 @@ async def _chat(
1334
1376
  normalized_api_format = str(api_format or "chat_completions").strip().lower()
1335
1377
  if normalized_api_format == "responses":
1336
1378
  url = f"{endpoint.rstrip('/')}/v1/responses"
1337
- payload = {"input": [{"role": "user", "content": message}], "stream": False}
1379
+ payload: dict[str, Any] = {
1380
+ "input": [{"role": "user", "content": message}],
1381
+ "stream": False,
1382
+ }
1338
1383
  else:
1339
1384
  url = f"{endpoint.rstrip('/')}/v1/chat/completions"
1340
- payload = {"messages": [{"role": "user", "content": message}], "stream": False}
1385
+ payload = {
1386
+ "messages": [{"role": "user", "content": message}],
1387
+ "stream": False,
1388
+ }
1341
1389
 
1342
1390
  if session_id:
1343
1391
  payload["session_id"] = session_id
@@ -1351,31 +1399,37 @@ async def _chat(
1351
1399
  is_local = "localhost" in url or "127.0.0.1" in url or "0.0.0.0" in url
1352
1400
 
1353
1401
  # 构造 httpx client 配置
1354
- client_kwargs = {"timeout": 60, "trust_env": not is_local}
1402
+ client_kwargs: dict[str, Any] = {
1403
+ "timeout": 60,
1404
+ "trust_env": not is_local,
1405
+ }
1355
1406
 
1356
1407
  # 如果指定了 --insecure 参数,跳过 SSL 证书验证(类似 curl -k)
1357
1408
  if insecure:
1358
1409
  client_kwargs["verify"] = False
1359
1410
 
1360
1411
  # 构造 Headers
1361
- headers = {}
1412
+ headers: dict[str, str] = {}
1362
1413
  if api_key:
1363
1414
  headers["Authorization"] = f"Bearer {api_key}"
1364
1415
 
1365
1416
  async with httpx.AsyncClient(**client_kwargs) as client:
1366
1417
  response = await client.post(url, json=payload, headers=headers)
1367
1418
  response.raise_for_status()
1368
- return response.json()
1419
+ response_payload = response.json()
1420
+ if not isinstance(response_payload, dict):
1421
+ raise ValueError("Agent response must be a JSON object")
1422
+ return response_payload
1369
1423
 
1370
1424
 
1371
1425
  async def _stream_chat(
1372
1426
  endpoint: str,
1373
1427
  message: str,
1374
- api_key: str = None,
1375
- session_id: str = None,
1428
+ api_key: Optional[str] = None,
1429
+ session_id: Optional[str] = None,
1376
1430
  is_once: bool = False,
1377
1431
  insecure: bool = False,
1378
- model: str = None,
1432
+ model: Optional[str] = None,
1379
1433
  api_format: str = "chat_completions",
1380
1434
  ):
1381
1435
  """流式调用 (SSE)"""
@@ -1388,7 +1442,10 @@ async def _stream_chat(
1388
1442
  normalized_api_format = str(api_format or "chat_completions").strip().lower()
1389
1443
  if normalized_api_format == "responses":
1390
1444
  url = f"{endpoint.rstrip('/')}/v1/responses"
1391
- payload = {"input": [{"role": "user", "content": message}], "stream": True}
1445
+ payload: dict[str, Any] = {
1446
+ "input": [{"role": "user", "content": message}],
1447
+ "stream": True,
1448
+ }
1392
1449
  else:
1393
1450
  url = f"{endpoint.rstrip('/')}/v1/chat/completions"
1394
1451
  payload = {"messages": [{"role": "user", "content": message}], "stream": True}
@@ -1405,14 +1462,17 @@ async def _stream_chat(
1405
1462
  is_local = "localhost" in url or "127.0.0.1" in url or "0.0.0.0" in url
1406
1463
 
1407
1464
  # 构造 httpx client 配置
1408
- client_kwargs = {"timeout": 60, "trust_env": not is_local}
1465
+ client_kwargs: dict[str, Any] = {
1466
+ "timeout": 60,
1467
+ "trust_env": not is_local,
1468
+ }
1409
1469
 
1410
1470
  # 如果指定了 --insecure 参数,跳过 SSL 证书验证(类似 curl -k)
1411
1471
  if insecure:
1412
1472
  client_kwargs["verify"] = False
1413
1473
 
1414
1474
  # 构造 Headers
1415
- headers = {}
1475
+ headers: dict[str, str] = {}
1416
1476
  if api_key:
1417
1477
  headers["Authorization"] = f"Bearer {api_key}"
1418
1478
 
@@ -1437,6 +1497,8 @@ async def _stream_chat(
1437
1497
 
1438
1498
  try:
1439
1499
  data = json.loads(data_str)
1500
+ if not isinstance(data, dict):
1501
+ continue
1440
1502
  if current_event and isinstance(data, dict):
1441
1503
  data = {**data, "_event": current_event}
1442
1504
  # 直接 yield 解析后的 JSON 数据,让 _extract_content 处理
@@ -1497,7 +1559,7 @@ def _extract_response_content(response: dict) -> str:
1497
1559
  choices = response.get("choices", [])
1498
1560
  if choices:
1499
1561
  message = choices[0].get("message", {})
1500
- return message.get("content", "")
1562
+ return str(message.get("content") or "")
1501
1563
  except (KeyError, IndexError):
1502
1564
  pass
1503
1565
  return str(response)