agentengine-sdk-python 0.6.2__py3-none-any.whl → 0.6.9__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 (490) hide show
  1. agentengine_sdk_python-0.6.9.dist-info/METADATA +179 -0
  2. agentengine_sdk_python-0.6.9.dist-info/RECORD +487 -0
  3. {agentengine_sdk_python-0.6.2.dist-info → agentengine_sdk_python-0.6.9.dist-info}/WHEEL +1 -1
  4. agentengine_sdk_python-0.6.9.dist-info/entry_points.txt +3 -0
  5. agentengine_sdk_python-0.6.9.dist-info/licenses/LICENSE +175 -0
  6. agentengine_sdk_python-0.6.9.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 +2227 -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 +2277 -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 +1259 -0
  46. ksadk/cli/cmd_invoke.py +1336 -0
  47. ksadk/cli/cmd_launch.py +564 -0
  48. ksadk/cli/cmd_mcp.py +1174 -0
  49. ksadk/cli/cmd_model.py +302 -0
  50. ksadk/cli/cmd_openclaw.py +3918 -0
  51. ksadk/cli/cmd_run.py +232 -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 +410 -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 +342 -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/model_context.py +360 -0
  83. ksadk/conversations/model_options.py +136 -0
  84. ksadk/conversations/normalize.py +446 -0
  85. ksadk/conversations/reasoning_markup.py +91 -0
  86. ksadk/conversations/run_kinds.py +61 -0
  87. ksadk/conversations/run_status.py +53 -0
  88. ksadk/conversations/runtime.py +5208 -0
  89. ksadk/conversations/semantic_summary.py +359 -0
  90. ksadk/conversations/session_title.py +254 -0
  91. ksadk/deployment/__init__.py +83 -0
  92. ksadk/deployment/agent_access.py +226 -0
  93. ksadk/deployment/base.py +229 -0
  94. ksadk/deployment/manager.py +332 -0
  95. ksadk/deployment/providers/__init__.py +10 -0
  96. ksadk/deployment/providers/serverless.py +1105 -0
  97. ksadk/deployment/registry.py +120 -0
  98. ksadk/deployment/state.py +78 -0
  99. ksadk/deployment/ui_config.py +21 -0
  100. ksadk/detection/__init__.py +7 -0
  101. ksadk/detection/detector.py +431 -0
  102. ksadk/detection/mcp_detector.py +250 -0
  103. ksadk/hermes_terminal.py +467 -0
  104. ksadk/identity/__init__.py +17 -0
  105. ksadk/identity/resolver.py +385 -0
  106. ksadk/knowledge_base/__init__.py +62 -0
  107. ksadk/knowledge_base/adk_tool.py +47 -0
  108. ksadk/knowledge_base/client.py +297 -0
  109. ksadk/knowledge_base/langchain_tool.py +55 -0
  110. ksadk/knowledge_base/service.py +66 -0
  111. ksadk/knowledge_base/tool.py +50 -0
  112. ksadk/markdown.py +169 -0
  113. ksadk/mcp_runtime/__init__.py +231 -0
  114. ksadk/memory/__init__.py +57 -0
  115. ksadk/memory/adk/__init__.py +51 -0
  116. ksadk/memory/adk/backends/__init__.py +5 -0
  117. ksadk/memory/adk/backends/base_ltm_backend.py +52 -0
  118. ksadk/memory/adk/backends/http_ltm_backend.py +183 -0
  119. ksadk/memory/adk/backends/inmemory_ltm_backend.py +96 -0
  120. ksadk/memory/adk/backends/sdk_ltm_backend.py +456 -0
  121. ksadk/memory/adk/long_term_memory.py +273 -0
  122. ksadk/memory/adk/short_term_memory.py +289 -0
  123. ksadk/memory/adk_tool.py +31 -0
  124. ksadk/memory/backends/__init__.py +6 -0
  125. ksadk/memory/backends/base.py +103 -0
  126. ksadk/memory/backends/memory.py +112 -0
  127. ksadk/memory/backends/redis.py +146 -0
  128. ksadk/memory/langchain_tool.py +39 -0
  129. ksadk/memory/ltm_backend_factory.py +24 -0
  130. ksadk/memory/manager.py +215 -0
  131. ksadk/memory/service.py +172 -0
  132. ksadk/memory/tool.py +96 -0
  133. ksadk/model_policy.py +223 -0
  134. ksadk/openclaw_gateway.py +378 -0
  135. ksadk/runners/__init__.py +8 -0
  136. ksadk/runners/adk_runner.py +1135 -0
  137. ksadk/runners/base_runner.py +305 -0
  138. ksadk/runners/deepagents_runner.py +13 -0
  139. ksadk/runners/factory.py +73 -0
  140. ksadk/runners/langchain_runner.py +539 -0
  141. ksadk/runners/langgraph_runner.py +852 -0
  142. ksadk/runners/patch_langchain.py +187 -0
  143. ksadk/runners/remote_runner.py +667 -0
  144. ksadk/runners/usage_accumulator.py +38 -0
  145. ksadk/runners/utils/__init__.py +19 -0
  146. ksadk/runners/utils/langfuse.py +230 -0
  147. ksadk/runners/utils/loader.py +62 -0
  148. ksadk/runtime_context.py +166 -0
  149. ksadk/runtime_state.py +25 -0
  150. ksadk/sandbox/__init__.py +28 -0
  151. ksadk/sandbox/backends/__init__.py +9 -0
  152. ksadk/sandbox/backends/e2b.py +154 -0
  153. ksadk/sandbox/backends/local_process.py +131 -0
  154. ksadk/sandbox/base.py +101 -0
  155. ksadk/sandbox/factory.py +53 -0
  156. ksadk/sandbox/registry.py +187 -0
  157. ksadk/server/__init__.py +7 -0
  158. ksadk/server/api_models.py +73 -0
  159. ksadk/server/app.py +3789 -0
  160. ksadk/server/static/assets/ArtifactsPanel-C0meuOdi.js +1 -0
  161. ksadk/server/static/assets/CodeBlock-BbI4HPtJ.js +9 -0
  162. ksadk/server/static/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  163. ksadk/server/static/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  164. ksadk/server/static/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  165. ksadk/server/static/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  166. ksadk/server/static/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  167. ksadk/server/static/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  168. ksadk/server/static/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  169. ksadk/server/static/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  170. ksadk/server/static/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  171. ksadk/server/static/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  172. ksadk/server/static/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  173. ksadk/server/static/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  174. ksadk/server/static/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  175. ksadk/server/static/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  176. ksadk/server/static/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  177. ksadk/server/static/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  178. ksadk/server/static/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  179. ksadk/server/static/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  180. ksadk/server/static/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  181. ksadk/server/static/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  182. ksadk/server/static/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  183. ksadk/server/static/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  184. ksadk/server/static/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  185. ksadk/server/static/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  186. ksadk/server/static/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  187. ksadk/server/static/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  188. ksadk/server/static/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  189. ksadk/server/static/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  190. ksadk/server/static/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  191. ksadk/server/static/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  192. ksadk/server/static/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  193. ksadk/server/static/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  194. ksadk/server/static/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  195. ksadk/server/static/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  196. ksadk/server/static/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  197. ksadk/server/static/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  198. ksadk/server/static/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  199. ksadk/server/static/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  200. ksadk/server/static/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  201. ksadk/server/static/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  202. ksadk/server/static/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  203. ksadk/server/static/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  204. ksadk/server/static/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  205. ksadk/server/static/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  206. ksadk/server/static/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  207. ksadk/server/static/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  208. ksadk/server/static/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  209. ksadk/server/static/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  210. ksadk/server/static/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  211. ksadk/server/static/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  212. ksadk/server/static/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  213. ksadk/server/static/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  214. ksadk/server/static/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  215. ksadk/server/static/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  216. ksadk/server/static/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  217. ksadk/server/static/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  218. ksadk/server/static/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  219. ksadk/server/static/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  220. ksadk/server/static/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  221. ksadk/server/static/assets/MathMessageMarkdown-DMLQYoLp.js +8 -0
  222. ksadk/server/static/assets/MathMessageMarkdown-DeYh8QPr.css +1 -0
  223. ksadk/server/static/assets/MermaidBlock-DCR8WZ17.js +303 -0
  224. ksadk/server/static/assets/NativeTerminalPanel-CHOd7Rch.css +1 -0
  225. ksadk/server/static/assets/NativeTerminalPanel-CKUvWhUz.js +1 -0
  226. ksadk/server/static/assets/addon-fit-DthTIhi3.js +1 -0
  227. ksadk/server/static/assets/apl-CnwPGSsG.js +1 -0
  228. ksadk/server/static/assets/arc-bj2rZnP5.js +1 -0
  229. ksadk/server/static/assets/architecture-7EHR7CIX-Cr6Xz1_c.js +1 -0
  230. ksadk/server/static/assets/architectureDiagram-3BPJPVTR-2u1ltDIj.js +36 -0
  231. ksadk/server/static/assets/asciiarmor-qTkVPQu6.js +1 -0
  232. ksadk/server/static/assets/asn1-Dr8qZg38.js +1 -0
  233. ksadk/server/static/assets/asterisk-Bja0s6e1.js +1 -0
  234. ksadk/server/static/assets/blockDiagram-GPEHLZMM-D6fvdK20.js +132 -0
  235. ksadk/server/static/assets/brainfuck-D5EjA2JK.js +1 -0
  236. ksadk/server/static/assets/c4Diagram-AAUBKEIU-BK82L5n5.js +10 -0
  237. ksadk/server/static/assets/channel-BSSOwFIb.js +1 -0
  238. ksadk/server/static/assets/chunk-2J33WTMH-DLVdkeyQ.js +1 -0
  239. ksadk/server/static/assets/chunk-4BX2VUAB-BbwsYcbW.js +1 -0
  240. ksadk/server/static/assets/chunk-55IACEB6-DOairxzw.js +1 -0
  241. ksadk/server/static/assets/chunk-727SXJPM-hCO487gs.js +206 -0
  242. ksadk/server/static/assets/chunk-AQP2D5EJ-XU8vDOuG.js +231 -0
  243. ksadk/server/static/assets/chunk-FMBD7UC4-PrapyfMu.js +15 -0
  244. ksadk/server/static/assets/chunk-ND2GUHAM-CboKhTZ3.js +1 -0
  245. ksadk/server/static/assets/chunk-QZHKN3VN-XXpdiwUL.js +1 -0
  246. ksadk/server/static/assets/classDiagram-4FO5ZUOK-C5HvGiyK.js +1 -0
  247. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-C5HvGiyK.js +1 -0
  248. ksadk/server/static/assets/clike-DHH8Ad3s.js +1 -0
  249. ksadk/server/static/assets/clojure-BflJGmDX.js +1 -0
  250. ksadk/server/static/assets/cmake-CyVbuzPu.js +1 -0
  251. ksadk/server/static/assets/cobol-B_OZ4V-R.js +1 -0
  252. ksadk/server/static/assets/coffeescript-B2pKbFk8.js +1 -0
  253. ksadk/server/static/assets/commonlisp-CcllspGY.js +1 -0
  254. ksadk/server/static/assets/cose-bilkent-S5V4N54A-_N8bJ-EU.js +1 -0
  255. ksadk/server/static/assets/crystal-M5-qzICs.js +1 -0
  256. ksadk/server/static/assets/css-CYpP4FRV.js +1 -0
  257. ksadk/server/static/assets/cypher-p9eYesGn.js +1 -0
  258. ksadk/server/static/assets/cytoscape.esm-DelgaX4f.js +321 -0
  259. ksadk/server/static/assets/d-BhMjBjQP.js +1 -0
  260. ksadk/server/static/assets/dagre-BM42HDAG-FoDlo5J2.js +4 -0
  261. ksadk/server/static/assets/dagre-Bx709z4p.js +1 -0
  262. ksadk/server/static/assets/defaultLocale-C8Fc0cco.js +1 -0
  263. ksadk/server/static/assets/diagram-2AECGRRQ-BBp6ebBw.js +43 -0
  264. ksadk/server/static/assets/diagram-5GNKFQAL-CqOvG1PR.js +10 -0
  265. ksadk/server/static/assets/diagram-KO2AKTUF-O9T3t6ba.js +3 -0
  266. ksadk/server/static/assets/diagram-LMA3HP47-CGG8ekBO.js +24 -0
  267. ksadk/server/static/assets/diagram-OG6HWLK6-4BmH1EEg.js +24 -0
  268. ksadk/server/static/assets/diff-ChtP43wD.js +1 -0
  269. ksadk/server/static/assets/dist-6kSZvCZh.js +1 -0
  270. ksadk/server/static/assets/dist-B67uF2uK.js +1 -0
  271. ksadk/server/static/assets/dist-BMKM66B4.js +1 -0
  272. ksadk/server/static/assets/dist-BVzcWa6D.js +1 -0
  273. ksadk/server/static/assets/dist-Bk1l05Ni.js +1 -0
  274. ksadk/server/static/assets/dist-BkJjNih3.js +1 -0
  275. ksadk/server/static/assets/dist-BmuTWcm7.js +9 -0
  276. ksadk/server/static/assets/dist-C2DKRFVK.js +1 -0
  277. ksadk/server/static/assets/dist-CWiTDN_V.js +6 -0
  278. ksadk/server/static/assets/dist-CZ6C3x8B.js +23 -0
  279. ksadk/server/static/assets/dist-CiZHB6ZW.js +1 -0
  280. ksadk/server/static/assets/dist-Cp1_jKwf.js +1 -0
  281. ksadk/server/static/assets/dist-Cwhk4lwI.js +2 -0
  282. ksadk/server/static/assets/dist-D5JGcxBx.js +11 -0
  283. ksadk/server/static/assets/dist-D99wf6_X.js +1 -0
  284. ksadk/server/static/assets/dist-DCpZrjaK.js +1 -0
  285. ksadk/server/static/assets/dist-DI-oVAXw.js +1 -0
  286. ksadk/server/static/assets/dist-DLMjL01k.js +1 -0
  287. ksadk/server/static/assets/dist-DLeM1OCK.js +1 -0
  288. ksadk/server/static/assets/dist-DM0rEQPk.js +1 -0
  289. ksadk/server/static/assets/dist-DbaH3p5h.js +1 -0
  290. ksadk/server/static/assets/dist-S4klkK5W.js +1 -0
  291. ksadk/server/static/assets/dockerfile-BLkNEvjs.js +1 -0
  292. ksadk/server/static/assets/dtd-DTF72YNO.js +1 -0
  293. ksadk/server/static/assets/dylan-C6jEEEk-.js +1 -0
  294. ksadk/server/static/assets/ebnf-D4c0_ac3.js +1 -0
  295. ksadk/server/static/assets/ecl-BSZaIHnp.js +1 -0
  296. ksadk/server/static/assets/eiffel-BEjRio4Q.js +1 -0
  297. ksadk/server/static/assets/elm-Cshzl8qu.js +1 -0
  298. ksadk/server/static/assets/erDiagram-TEJ5UH35-oJhaci7S.js +85 -0
  299. ksadk/server/static/assets/erlang-DaB2Rkuy.js +1 -0
  300. ksadk/server/static/assets/eventmodeling-FCH6USID-CIgwHJLL.js +1 -0
  301. ksadk/server/static/assets/factor-D7LVTn2l.js +1 -0
  302. ksadk/server/static/assets/fcl-ClOhbFR7.js +1 -0
  303. ksadk/server/static/assets/flowDiagram-I6XJVG4X-DtTmUan-.js +162 -0
  304. ksadk/server/static/assets/forth-Cezjo90N.js +1 -0
  305. ksadk/server/static/assets/fortran-Bt6PBEDR.js +1 -0
  306. ksadk/server/static/assets/ganttDiagram-6RSMTGT7-BSsb_eij.js +292 -0
  307. ksadk/server/static/assets/gas-BHEdbvp9.js +1 -0
  308. ksadk/server/static/assets/gherkin-oBAE_ms0.js +1 -0
  309. ksadk/server/static/assets/gitGraph-WXDBUCRP-BVAJ7uo0.js +1 -0
  310. ksadk/server/static/assets/gitGraphDiagram-PVQCEYII-BR5s6Pws.js +106 -0
  311. ksadk/server/static/assets/graphlib-B8gBHxth.js +1 -0
  312. ksadk/server/static/assets/groovy-BC3IOsC8.js +1 -0
  313. ksadk/server/static/assets/haskell-BRsoo5mP.js +1 -0
  314. ksadk/server/static/assets/haxe-DIz0ZZqd.js +1 -0
  315. ksadk/server/static/assets/http-CLVgA2GD.js +1 -0
  316. ksadk/server/static/assets/idl-BUZw3wgd.js +1 -0
  317. ksadk/server/static/assets/index-BH7-pC0B.js +165 -0
  318. ksadk/server/static/assets/index-DAURbCsP.css +1 -0
  319. ksadk/server/static/assets/info-J43DQDTF-MT80V4ge.js +1 -0
  320. ksadk/server/static/assets/infoDiagram-5YYISTIA-DYPc5cvh.js +2 -0
  321. ksadk/server/static/assets/init-D6jRqBbL.js +1 -0
  322. ksadk/server/static/assets/ishikawaDiagram-YF4QCWOH-MoBdALDg.js +70 -0
  323. ksadk/server/static/assets/javascript-9Tg8ixDm.js +1 -0
  324. ksadk/server/static/assets/journeyDiagram-JHISSGLW-DgLiQT8l.js +139 -0
  325. ksadk/server/static/assets/julia-CQfgDRfP.js +1 -0
  326. ksadk/server/static/assets/kanban-definition-UN3LZRKU-CsFx112F.js +89 -0
  327. ksadk/server/static/assets/katex-DRsiwpM2.js +265 -0
  328. ksadk/server/static/assets/linear-TNRQ5Orv.js +1 -0
  329. ksadk/server/static/assets/livescript-BXxG0Yva.js +1 -0
  330. ksadk/server/static/assets/lua-CiA1ziua.js +1 -0
  331. ksadk/server/static/assets/mathematica-u8YMmbU0.js +1 -0
  332. ksadk/server/static/assets/mbox-BEMVcqjs.js +1 -0
  333. ksadk/server/static/assets/mermaid-parser.core-D2eMVOgo.js +161 -0
  334. ksadk/server/static/assets/mindmap-definition-RKZ34NQL-BtByYFhL.js +96 -0
  335. ksadk/server/static/assets/mirc-C9zpzAZU.js +1 -0
  336. ksadk/server/static/assets/mllike-B45xgp2S.js +1 -0
  337. ksadk/server/static/assets/modelica-CqHI_q-D.js +1 -0
  338. ksadk/server/static/assets/mscgen-qgSLujhx.js +1 -0
  339. ksadk/server/static/assets/mumps-CW_TBmxz.js +1 -0
  340. ksadk/server/static/assets/nginx-BMaDbqW3.js +1 -0
  341. ksadk/server/static/assets/nsis-AQ_alPln.js +1 -0
  342. ksadk/server/static/assets/ntriples-d28e9m0E.js +1 -0
  343. ksadk/server/static/assets/octave-D2Q8cUp1.js +1 -0
  344. ksadk/server/static/assets/ordinal-hYBb2elL.js +1 -0
  345. ksadk/server/static/assets/oz-BwTct_5T.js +1 -0
  346. ksadk/server/static/assets/packet-YPE3B663-BLKhbXZB.js +1 -0
  347. ksadk/server/static/assets/pascal-Dp_KdFgX.js +1 -0
  348. ksadk/server/static/assets/perl-CdEHsPfU.js +1 -0
  349. ksadk/server/static/assets/pie-LRSECV5Y-DFOikjSY.js +1 -0
  350. ksadk/server/static/assets/pieDiagram-4H26LBE5-DPnuCB8c.js +30 -0
  351. ksadk/server/static/assets/pig-AF4Hwhju.js +1 -0
  352. ksadk/server/static/assets/powershell-CzG71I4L.js +1 -0
  353. ksadk/server/static/assets/properties-C357ku5U.js +1 -0
  354. ksadk/server/static/assets/protobuf-D1ij_kNL.js +1 -0
  355. ksadk/server/static/assets/pug-Bugr-47h.js +1 -0
  356. ksadk/server/static/assets/puppet-B4hC2X4m.js +1 -0
  357. ksadk/server/static/assets/python-BqYw9LYJ.js +1 -0
  358. ksadk/server/static/assets/q-B9NhS7L_.js +1 -0
  359. ksadk/server/static/assets/quadrantDiagram-W4KKPZXB-miFpCPv4.js +7 -0
  360. ksadk/server/static/assets/r-DADKenSm.js +1 -0
  361. ksadk/server/static/assets/radar-GUYGQ44K-095b1Ikw.js +1 -0
  362. ksadk/server/static/assets/requirementDiagram-4Y6WPE33-mjB_yYkW.js +84 -0
  363. ksadk/server/static/assets/rpm-gpDK5sbt.js +1 -0
  364. ksadk/server/static/assets/ruby-DsYpTuWg.js +1 -0
  365. ksadk/server/static/assets/sankeyDiagram-5OEKKPKP-D7hSlZZZ.js +40 -0
  366. ksadk/server/static/assets/sas-C2OyD2Y6.js +1 -0
  367. ksadk/server/static/assets/scheme-CyDdOh7e.js +1 -0
  368. ksadk/server/static/assets/sequenceDiagram-3UESZ5HK-D9Cx6hC3.js +162 -0
  369. ksadk/server/static/assets/shell-Du5Qg9im.js +1 -0
  370. ksadk/server/static/assets/sieve-BAxa3IjF.js +1 -0
  371. ksadk/server/static/assets/simple-mode-DRpGK0lJ.js +1 -0
  372. ksadk/server/static/assets/smalltalk-BLp5-jwC.js +1 -0
  373. ksadk/server/static/assets/solr-BBopId9w.js +1 -0
  374. ksadk/server/static/assets/sparql-Dz-mlCAC.js +1 -0
  375. ksadk/server/static/assets/spreadsheet-CTIncYxj.js +1 -0
  376. ksadk/server/static/assets/sql-DcCJ9jop.js +1 -0
  377. ksadk/server/static/assets/stateDiagram-AJRCARHV-D_zrg47o.js +1 -0
  378. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-J9kCb0nC.js +1 -0
  379. ksadk/server/static/assets/stex-sDrdk2BW.js +1 -0
  380. ksadk/server/static/assets/stylus-DLLZ8dgm.js +1 -0
  381. ksadk/server/static/assets/swift-DKB6_1j6.js +1 -0
  382. ksadk/server/static/assets/tcl-BGfruO1u.js +1 -0
  383. ksadk/server/static/assets/textile-DWBqthVk.js +1 -0
  384. ksadk/server/static/assets/tiddlywiki-VlUiK86J.js +1 -0
  385. ksadk/server/static/assets/tiki-CxVlf5KZ.js +1 -0
  386. ksadk/server/static/assets/timeline-definition-PNZ67QCA-CwSec0Wa.js +120 -0
  387. ksadk/server/static/assets/toml-LvoKBwCs.js +1 -0
  388. ksadk/server/static/assets/treeView-BLDUP644-yinfJEY6.js +1 -0
  389. ksadk/server/static/assets/treemap-LRROVOQU-DosUqN1Q.js +1 -0
  390. ksadk/server/static/assets/troff-C2dAgh7P.js +1 -0
  391. ksadk/server/static/assets/ttcn-BePYh-hG.js +1 -0
  392. ksadk/server/static/assets/ttcn-cfg-CY0aot7Q.js +1 -0
  393. ksadk/server/static/assets/turtle-BDLWE2cD.js +1 -0
  394. ksadk/server/static/assets/vb-BthdM_4N.js +1 -0
  395. ksadk/server/static/assets/vbscript-D9f6rSsU.js +1 -0
  396. ksadk/server/static/assets/velocity-CqftRsjg.js +1 -0
  397. ksadk/server/static/assets/vennDiagram-CIIHVFJN-agCVobiF.js +34 -0
  398. ksadk/server/static/assets/verilog-D-x6ne0Z.js +1 -0
  399. ksadk/server/static/assets/vhdl-CMrOq2q1.js +1 -0
  400. ksadk/server/static/assets/wardley-L42UT6IY-Bvp7-5uH.js +1 -0
  401. ksadk/server/static/assets/wardleyDiagram-YWT4CUSO-TmrlhWNt.js +78 -0
  402. ksadk/server/static/assets/webidl-D5jiJvOU.js +1 -0
  403. ksadk/server/static/assets/xquery-fj_R-kMw.js +1 -0
  404. ksadk/server/static/assets/xterm-DooSxjI5.js +36 -0
  405. ksadk/server/static/assets/xychartDiagram-2RQKCTM6-DV71V-ah.js +7 -0
  406. ksadk/server/static/assets/yacas-CXXgtw0p.js +1 -0
  407. ksadk/server/static/assets/z80-CL1naaMV.js +1 -0
  408. ksadk/server/static/favicon.svg +1 -0
  409. ksadk/server/static/icons.svg +24 -0
  410. ksadk/server/static/index.html +14 -0
  411. ksadk/server/terminal_sessions.py +551 -0
  412. ksadk/sessions/__init__.py +283 -0
  413. ksadk/sessions/base.py +354 -0
  414. ksadk/sessions/continuity.py +313 -0
  415. ksadk/sessions/errors.py +7 -0
  416. ksadk/sessions/in_memory.py +273 -0
  417. ksadk/sessions/local_service.py +949 -0
  418. ksadk/sessions/postgres_service.py +838 -0
  419. ksadk/sessions/sqlite_service.py +13 -0
  420. ksadk/skills/__init__.py +9 -0
  421. ksadk/skills/loader.py +46 -0
  422. ksadk/skills/models.py +120 -0
  423. ksadk/skills/package_store.py +104 -0
  424. ksadk/skills/runtime/__init__.py +17 -0
  425. ksadk/skills/runtime/agent.py +183 -0
  426. ksadk/skills/runtime/artifacts.py +39 -0
  427. ksadk/skills/runtime/backends/__init__.py +1 -0
  428. ksadk/skills/runtime/backends/disabled.py +8 -0
  429. ksadk/skills/runtime/backends/e2b.py +168 -0
  430. ksadk/skills/runtime/backends/local.py +95 -0
  431. ksadk/skills/runtime/base.py +103 -0
  432. ksadk/skills/runtime/executor.py +219 -0
  433. ksadk/skills/runtime/factory.py +37 -0
  434. ksadk/skills/runtime/loader.py +131 -0
  435. ksadk/skills/runtime/registry.py +150 -0
  436. ksadk/skills/runtime/request.py +67 -0
  437. ksadk/skills/service_client.py +239 -0
  438. ksadk/skills/service_env.py +58 -0
  439. ksadk/skills/tool_defs.py +221 -0
  440. ksadk/terminal_client.py +69 -0
  441. ksadk/terminal_exec_policy.py +229 -0
  442. ksadk/tools/__init__.py +17 -0
  443. ksadk/tools/gateway.py +230 -0
  444. ksadk/tools/result_budget.py +154 -0
  445. ksadk/toolsets/__init__.py +852 -0
  446. ksadk/toolsets/_langchain.py +11 -0
  447. ksadk/toolsets/platform.py +93 -0
  448. ksadk/toolsets/sandbox.py +310 -0
  449. ksadk/toolsets/skills.py +217 -0
  450. ksadk/toolsets/web.py +266 -0
  451. ksadk/toolsets/workspace.py +878 -0
  452. ksadk/toolsets/workspace_state.py +44 -0
  453. ksadk/tracing/__init__.py +37 -0
  454. ksadk/tracing/exporters/__init__.py +1 -0
  455. ksadk/tracing/exporters/inmemory_exporter.py +116 -0
  456. ksadk/tracing/exporters/langfuse_exporter.py +445 -0
  457. ksadk/tracing/setup.py +829 -0
  458. ksadk/tracing/span_utils.py +114 -0
  459. ksadk/tui/__init__.py +12 -0
  460. ksadk/tui/app.py +400 -0
  461. ksadk/tui/clipboard.py +100 -0
  462. ksadk/tui/widgets/__init__.py +22 -0
  463. ksadk/tui/widgets/assistant.py +89 -0
  464. ksadk/tui/widgets/base.py +54 -0
  465. ksadk/tui/widgets/chat_input.py +246 -0
  466. ksadk/tui/widgets/history.py +156 -0
  467. ksadk/tui/widgets/system.py +87 -0
  468. ksadk/tui/widgets/thinking.py +110 -0
  469. ksadk/tui/widgets/tool_call.py +161 -0
  470. ksadk/tui/widgets/user.py +37 -0
  471. ksadk/ui_config.py +168 -0
  472. ksadk/version.py +4 -0
  473. ksadk_runtime_common/__init__.py +20 -0
  474. ksadk_runtime_common/memory_backend/__init__.py +29 -0
  475. ksadk_runtime_common/memory_backend/manifest.py +79 -0
  476. ksadk_runtime_common/memory_backend/providers/__init__.py +6 -0
  477. ksadk_runtime_common/memory_backend/providers/lancedb.py +151 -0
  478. ksadk_runtime_common/memory_backend/providers/mem0.py +74 -0
  479. ksadk_runtime_common/memory_backend/registry.py +56 -0
  480. ksadk_runtime_common/memory_backend/render.py +71 -0
  481. ksadk_runtime_common/schemas/memory_backend_manifest.schema.json +148 -0
  482. ksadk_runtime_common/workspace_files/__init__.py +29 -0
  483. ksadk_runtime_common/workspace_files/bootstrap.py +56 -0
  484. ksadk_runtime_common/workspace_files/constants.py +9 -0
  485. ksadk_runtime_common/workspace_files/path_utils.py +71 -0
  486. ksadk_runtime_common/workspace_files/preview.py +96 -0
  487. ksadk_runtime_common/workspace_files/router.py +254 -0
  488. agentengine_sdk_python-0.6.2.dist-info/METADATA +0 -46
  489. agentengine_sdk_python-0.6.2.dist-info/RECORD +0 -4
  490. agentengine_sdk_python-0.6.2.dist-info/top_level.txt +0 -1
ksadk/cli/cmd_files.py ADDED
@@ -0,0 +1,1227 @@
1
+ """Workspace file management commands."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ import json
7
+ import os
8
+ from pathlib import Path, PurePosixPath
9
+ from typing import Callable
10
+
11
+ import click
12
+
13
+ from ksadk.api import AgentEngineAPIError, AgentEngineClient
14
+ from ksadk.cli.agent_ref import merge_agent_inputs, resolve_agent_ref, resolve_openclaw_ref
15
+ from ksadk.cli.error_utils import ensure_dry_run_supported
16
+ from ksadk.cli.resource_common import CONTEXT_SETTINGS
17
+ from ksadk.cli.ui import output_option as cli_output_option
18
+ from ksadk.deployment.state import load_state
19
+
20
+ DEFAULT_REGION = "cn-beijing-6"
21
+ DEFAULT_WORKSPACE_ROOT_LABEL = "workspace"
22
+ LOCAL_DEV_ARTIFACT_DIR_NAMES = frozenset(
23
+ {
24
+ ".agentengine",
25
+ ".claude",
26
+ ".codex",
27
+ ".git",
28
+ ".idea",
29
+ ".mypy_cache",
30
+ ".nox",
31
+ ".pytest_cache",
32
+ ".ruff_cache",
33
+ ".svn",
34
+ ".tox",
35
+ ".venv",
36
+ ".vscode",
37
+ "__pycache__",
38
+ "node_modules",
39
+ "venv",
40
+ }
41
+ )
42
+ LOCAL_DEV_ARTIFACT_FILE_NAMES = frozenset(
43
+ {
44
+ ".DS_Store",
45
+ ".agentengine.state",
46
+ ".coverage",
47
+ "Thumbs.db",
48
+ }
49
+ )
50
+ LOCAL_DEV_ARTIFACT_FILE_SUFFIXES = (".pyc", ".pyo", ".swp", ".tmp")
51
+
52
+
53
+ def _format_size(size_bytes: object | None) -> str:
54
+ if size_bytes is None:
55
+ return "-"
56
+ try:
57
+ value = int(size_bytes)
58
+ except (TypeError, ValueError):
59
+ return str(size_bytes)
60
+ if value < 1024:
61
+ return f"{value} B"
62
+ units = ["KB", "MB", "GB", "TB"]
63
+ scaled = float(value)
64
+ for unit in units:
65
+ scaled /= 1024
66
+ if scaled < 1024 or unit == units[-1]:
67
+ text = f"{scaled:.1f}".rstrip("0").rstrip(".")
68
+ return f"{text} {unit}"
69
+ return f"{value} B"
70
+
71
+
72
+ def _workspace_root_label(payload: dict | None = None) -> str:
73
+ candidate = ""
74
+ if isinstance(payload, dict):
75
+ candidate = str(payload.get("workspace_root") or payload.get("root") or "").strip()
76
+ return candidate or DEFAULT_WORKSPACE_ROOT_LABEL
77
+
78
+
79
+ def _workspace_display_path(path: object | None, *, root_label: str | None = None) -> str:
80
+ root = str(root_label or DEFAULT_WORKSPACE_ROOT_LABEL).strip() or DEFAULT_WORKSPACE_ROOT_LABEL
81
+ raw = str(path or ".").strip().replace("\\", "/")
82
+ if raw in {"", ".", "/"}:
83
+ return f"{root}:/"
84
+ normalized = "/".join(part for part in raw.split("/") if part not in {"", "."})
85
+ return f"{root}:/{normalized}"
86
+
87
+
88
+ def _workspace_real_path(path: object | None, *, workspace_root: str | None) -> str | None:
89
+ root = str(workspace_root or "").strip().replace("\\", "/")
90
+ if not root:
91
+ return None
92
+ if root != "/":
93
+ root = root.rstrip("/")
94
+ raw = str(path or ".").strip().replace("\\", "/")
95
+ if raw in {"", ".", "/"}:
96
+ return root
97
+ normalized = "/".join(part for part in raw.lstrip("/").split("/") if part not in {"", "."})
98
+ if not normalized:
99
+ return root
100
+ if root == "/":
101
+ return f"/{normalized}"
102
+ return f"{root}/{normalized}"
103
+
104
+
105
+ def _echo_key_value(label: str, value: str, *, fg: str = "bright_blue", bold: bool = False) -> None:
106
+ click.secho(f"{label}:{value}", fg=fg, bold=bold)
107
+
108
+
109
+ def _echo_section_title(title: str, *, fg: str = "bright_blue") -> None:
110
+ click.secho(title, fg=fg, bold=True)
111
+
112
+
113
+ def _normalize_entry_payload(entry: dict, *, root_label: str, workspace_real_root: str | None = None) -> dict:
114
+ normalized = dict(entry or {})
115
+ path = str(normalized.get("path") or "").strip()
116
+ normalized["display_path"] = _workspace_display_path(path, root_label=root_label)
117
+ normalized["real_path"] = _workspace_real_path(path, workspace_root=workspace_real_root)
118
+ size_bytes = normalized.get("size_bytes")
119
+ if size_bytes is not None:
120
+ normalized["size_human"] = _format_size(size_bytes)
121
+ else:
122
+ normalized["size_human"] = None
123
+ return normalized
124
+
125
+
126
+ def _build_list_payload(payload: dict) -> dict:
127
+ root_label = _workspace_root_label(payload)
128
+ workspace_real_root = str(payload.get("workspace_real_root") or payload.get("workspace_path") or "").strip() or None
129
+ entries = [
130
+ _normalize_entry_payload(
131
+ entry,
132
+ root_label=root_label,
133
+ workspace_real_root=workspace_real_root,
134
+ )
135
+ for entry in payload.get("entries", [])
136
+ ]
137
+ directories = [entry for entry in entries if entry.get("type") == "directory"]
138
+ files = [entry for entry in entries if entry.get("type") != "directory"]
139
+ enriched = dict(payload)
140
+ enriched.update(
141
+ {
142
+ "ok": True,
143
+ "action": "list",
144
+ "workspace_root": root_label,
145
+ "workspace_display_path": _workspace_display_path(payload.get("path", "."), root_label=root_label),
146
+ "workspace_real_root": workspace_real_root,
147
+ "workspace_real_path": _workspace_real_path(
148
+ payload.get("path", "."),
149
+ workspace_root=workspace_real_root,
150
+ ),
151
+ "entry_count": len(entries),
152
+ "directories": directories,
153
+ "files": files,
154
+ "entries": entries,
155
+ "summary": {
156
+ "entry_count": len(entries),
157
+ "directory_count": len(directories),
158
+ "file_count": len(files),
159
+ },
160
+ }
161
+ )
162
+ return enriched
163
+
164
+
165
+ def _build_upload_payload(payload: dict, *, local_path: Path, remote_path: str) -> dict:
166
+ root_label = _workspace_root_label(payload)
167
+ entry = payload.get("entry", {}) if isinstance(payload.get("entry"), dict) else {}
168
+ resolved_remote_path = str(entry.get("path") or remote_path)
169
+ normalized_entry = _normalize_entry_payload(
170
+ {
171
+ **entry,
172
+ "path": resolved_remote_path,
173
+ },
174
+ root_label=root_label,
175
+ )
176
+ enriched = dict(payload)
177
+ enriched.update(
178
+ {
179
+ "ok": True,
180
+ "action": "upload",
181
+ "workspace_root": root_label,
182
+ "local_path": str(local_path),
183
+ "requested_remote_path": remote_path,
184
+ "remote_path": resolved_remote_path,
185
+ "remote_display_path": _workspace_display_path(resolved_remote_path, root_label=root_label),
186
+ "entry": normalized_entry,
187
+ "summary": {
188
+ "uploaded": 1,
189
+ "size_bytes": normalized_entry.get("size_bytes"),
190
+ "size_human": normalized_entry.get("size_human"),
191
+ },
192
+ }
193
+ )
194
+ return enriched
195
+
196
+
197
+ def _build_download_payload(*, remote_path: str, output_path: Path, size_bytes: int) -> dict:
198
+ root_label = DEFAULT_WORKSPACE_ROOT_LABEL
199
+ return {
200
+ "ok": True,
201
+ "action": "download",
202
+ "workspace_root": root_label,
203
+ "remote_path": remote_path,
204
+ "remote_display_path": _workspace_display_path(remote_path, root_label=root_label),
205
+ "output_path": str(output_path),
206
+ "local_path": str(output_path),
207
+ "size_bytes": size_bytes,
208
+ "size_human": _format_size(size_bytes),
209
+ "summary": {
210
+ "downloaded": 1,
211
+ "size_bytes": size_bytes,
212
+ "size_human": _format_size(size_bytes),
213
+ },
214
+ }
215
+
216
+
217
+ def _build_delete_payload(payload: dict, *, remote_path: str) -> dict:
218
+ root_label = _workspace_root_label(payload)
219
+ enriched = dict(payload)
220
+ enriched.update(
221
+ {
222
+ "ok": True,
223
+ "action": "delete",
224
+ "workspace_root": root_label,
225
+ "remote_path": remote_path,
226
+ "remote_display_path": _workspace_display_path(remote_path, root_label=root_label),
227
+ "summary": {
228
+ "deleted": 1 if payload.get("deleted") else 0,
229
+ },
230
+ }
231
+ )
232
+ return enriched
233
+
234
+
235
+ def _build_sync_results(payload: dict) -> dict:
236
+ direction = str(payload.get("direction", "")).strip().lower()
237
+ root_label = _workspace_root_label(payload)
238
+ local_dir = Path(str(payload.get("local_dir", ".")))
239
+ results: dict[str, list[dict]] = {}
240
+ for key in ("created", "overwritten", "skipped"):
241
+ items: list[dict] = []
242
+ for path in payload.get(key, []):
243
+ raw_path = str(path)
244
+ if direction == "push":
245
+ display_path = _workspace_display_path(raw_path, root_label=root_label)
246
+ else:
247
+ display_path = str((local_dir / Path(raw_path)).resolve())
248
+ items.append(
249
+ {
250
+ "path": raw_path,
251
+ "display_path": display_path,
252
+ }
253
+ )
254
+ results[key] = items
255
+ return results
256
+
257
+
258
+ def _build_sync_payload(payload: dict) -> dict:
259
+ root_label = _workspace_root_label(payload)
260
+ transport_mode = str(payload.get("transport_mode") or "").strip().lower()
261
+ transport_hint = {
262
+ "action_proxy": "通过平台 action 代理访问远端 workspace",
263
+ "runtime_direct": "通过 runtime endpoint 直连远端 workspace",
264
+ }.get(transport_mode)
265
+ enriched = dict(payload)
266
+ enriched.update(
267
+ {
268
+ "ok": True,
269
+ "action": str(payload.get("direction", "sync")).strip().lower() or "sync",
270
+ "workspace_root": root_label,
271
+ "remote_display_path": _workspace_display_path(payload.get("remote_path", "."), root_label=root_label),
272
+ "transport_mode": transport_mode or None,
273
+ "transport_hint": transport_hint,
274
+ "summary": {
275
+ "created_count": len(payload.get("created", [])),
276
+ "overwritten_count": len(payload.get("overwritten", [])),
277
+ "skipped_count": len(payload.get("skipped", [])),
278
+ "total_files": payload.get("total_files", 0),
279
+ },
280
+ "results": _build_sync_results(payload),
281
+ }
282
+ )
283
+ return enriched
284
+
285
+
286
+ def _emit_payload(payload, output_mode: str | None) -> None:
287
+ if output_mode == "json":
288
+ click.echo(json.dumps(payload, ensure_ascii=False))
289
+ return
290
+ if isinstance(payload, dict) and "entries" in payload:
291
+ root_label = _workspace_root_label(payload)
292
+ entries = payload.get("entries", [])
293
+ _echo_key_value("工作空间", root_label, fg="bright_blue", bold=True)
294
+ _echo_key_value(
295
+ "当前目录",
296
+ _workspace_display_path(payload.get("path", "."), root_label=root_label),
297
+ fg="cyan",
298
+ bold=True,
299
+ )
300
+ workspace_real_path = str(payload.get("workspace_real_path") or "").strip()
301
+ if workspace_real_path:
302
+ _echo_key_value("实际目录", workspace_real_path, fg="magenta")
303
+ _echo_key_value("条目数量", str(len(entries)), fg="yellow")
304
+ if not entries:
305
+ click.secho("当前目录为空。", fg="bright_black")
306
+ return
307
+ directories = payload.get("directories") or [entry for entry in entries if entry.get("type") == "directory"]
308
+ files = payload.get("files") or [entry for entry in entries if entry.get("type") != "directory"]
309
+ if directories:
310
+ _echo_section_title(f"目录({len(directories)})", fg="cyan")
311
+ for entry in directories:
312
+ click.secho(f" {entry.get('display_path') or _workspace_display_path(entry.get('path', ''), root_label=root_label)}", fg="cyan")
313
+ if files:
314
+ _echo_section_title(f"文件({len(files)})", fg="green")
315
+ for entry in files:
316
+ click.secho(
317
+ f" {entry.get('display_path') or _workspace_display_path(entry.get('path', ''), root_label=root_label)}"
318
+ f" {entry.get('size_human') or _format_size(entry.get('size_bytes'))}",
319
+ fg="green",
320
+ )
321
+ return
322
+ click.echo(str(payload))
323
+
324
+
325
+ def _emit_sync_payload(payload: dict, output_mode: str | None) -> None:
326
+ if output_mode == "json":
327
+ click.echo(json.dumps(payload, ensure_ascii=False))
328
+ return
329
+
330
+ root_label = _workspace_root_label(payload)
331
+ direction = str(payload.get("direction", "sync")).strip().lower()
332
+ title = {
333
+ "push": "推送完成",
334
+ "pull": "拉取完成",
335
+ }.get(direction, "同步完成")
336
+ _echo_section_title(title, fg="green")
337
+ _echo_key_value("本地目录", str(payload.get("local_dir", ".")), fg="bright_blue")
338
+ _echo_key_value(
339
+ "远端目录",
340
+ _workspace_display_path(payload.get("remote_path", "."), root_label=root_label),
341
+ fg="cyan",
342
+ )
343
+ transport_hint = str(payload.get("transport_hint") or "").strip()
344
+ if transport_hint:
345
+ _echo_key_value("访问链路", transport_hint, fg="magenta")
346
+ click.secho(
347
+ "统计:"
348
+ f"新增 {len(payload.get('created', []))},"
349
+ f"覆盖 {len(payload.get('overwritten', []))},"
350
+ f"跳过 {len(payload.get('skipped', []))},"
351
+ f"共 {payload.get('total_files', 0)}",
352
+ fg="yellow",
353
+ )
354
+ for key, label in (
355
+ ("created", "已新增"),
356
+ ("overwritten", "已覆盖"),
357
+ ("skipped", "已跳过"),
358
+ ):
359
+ for item in payload.get(key, []):
360
+ color = {
361
+ "created": "green",
362
+ "overwritten": "yellow",
363
+ "skipped": "bright_black",
364
+ }.get(key, "white")
365
+ click.secho(
366
+ f"{label}:{_workspace_display_path(item, root_label=root_label)}",
367
+ fg=color,
368
+ )
369
+
370
+
371
+ def _normalize(value: object | None) -> str | None:
372
+ if value is None:
373
+ return None
374
+ text = str(value).strip()
375
+ return text or None
376
+
377
+
378
+ def _normalize_workspace_dir(value: str | None) -> str:
379
+ raw = str(value or ".").strip().replace("\\", "/")
380
+ if raw in {"", ".", "/"}:
381
+ return "."
382
+ parts = [part for part in PurePosixPath(raw.lstrip("/")).parts if part not in {"", "."}]
383
+ if any(part == ".." for part in parts):
384
+ raise click.UsageError("workspace 目录路径不能包含 ..")
385
+ return "." if not parts else "/".join(parts)
386
+
387
+
388
+ def _normalize_workspace_file_path(value: str | None) -> str:
389
+ normalized = _normalize_workspace_dir(value)
390
+ if normalized == ".":
391
+ raise click.UsageError("workspace 文件路径不能为空或根目录")
392
+ return normalized
393
+
394
+
395
+ def _relative_remote_path(entry_path: str, base_remote_path: str) -> str:
396
+ normalized_entry = _normalize_workspace_dir(entry_path)
397
+ if base_remote_path == ".":
398
+ return normalized_entry
399
+ prefix = f"{base_remote_path}/"
400
+ if normalized_entry.startswith(prefix):
401
+ return normalized_entry[len(prefix) :]
402
+ return normalized_entry
403
+
404
+
405
+ def _join_remote_path(base_remote_path: str, relative_path: str) -> str:
406
+ relative = str(relative_path).strip().replace("\\", "/")
407
+ if base_remote_path == ".":
408
+ return relative
409
+ return f"{base_remote_path}/{relative}"
410
+
411
+
412
+ def _ignored_local_dev_artifact_label_for_file(filename: str) -> str | None:
413
+ if filename in LOCAL_DEV_ARTIFACT_FILE_NAMES:
414
+ return filename
415
+ for suffix in LOCAL_DEV_ARTIFACT_FILE_SUFFIXES:
416
+ if filename.endswith(suffix):
417
+ return f"*{suffix}"
418
+ return None
419
+
420
+
421
+ def _collect_local_files_report(
422
+ local_dir: Path,
423
+ *,
424
+ ignore_dev_artifacts: bool = False,
425
+ ignore_git_artifacts: bool = True,
426
+ ) -> dict:
427
+ files: list[tuple[str, Path]] = []
428
+ ignored_artifacts: set[str] = set()
429
+ total_bytes = 0
430
+ ignored_dir_names = set(LOCAL_DEV_ARTIFACT_DIR_NAMES)
431
+ if not ignore_git_artifacts:
432
+ ignored_dir_names.discard(".git")
433
+
434
+ for root, dirnames, filenames in os.walk(local_dir, topdown=True):
435
+ root_path = Path(root)
436
+ if ignore_dev_artifacts:
437
+ kept_dirs: list[str] = []
438
+ for dirname in sorted(dirnames):
439
+ if dirname in ignored_dir_names:
440
+ ignored_artifacts.add(dirname)
441
+ continue
442
+ kept_dirs.append(dirname)
443
+ dirnames[:] = kept_dirs
444
+ else:
445
+ dirnames[:] = sorted(dirnames)
446
+
447
+ for filename in sorted(filenames):
448
+ if ignore_dev_artifacts:
449
+ ignored_label = _ignored_local_dev_artifact_label_for_file(filename)
450
+ if ignored_label:
451
+ ignored_artifacts.add(ignored_label)
452
+ continue
453
+ file_path = root_path / filename
454
+ relative = file_path.relative_to(local_dir).as_posix()
455
+ files.append((relative, file_path))
456
+ total_bytes += int(file_path.stat().st_size)
457
+
458
+ return {
459
+ "files": files,
460
+ "total_files": len(files),
461
+ "total_bytes": total_bytes,
462
+ "ignored_artifacts": sorted(ignored_artifacts),
463
+ }
464
+
465
+
466
+ def _collect_local_files(
467
+ local_dir: Path,
468
+ *,
469
+ ignore_dev_artifacts: bool = False,
470
+ ignore_git_artifacts: bool = True,
471
+ ) -> list[tuple[str, Path]]:
472
+ return _collect_local_files_report(
473
+ local_dir,
474
+ ignore_dev_artifacts=ignore_dev_artifacts,
475
+ ignore_git_artifacts=ignore_git_artifacts,
476
+ )["files"]
477
+
478
+
479
+ def _workspace_client_kwargs(
480
+ *,
481
+ agent_ref: str | None,
482
+ endpoint: str | None,
483
+ api_key: str | None,
484
+ ) -> dict:
485
+ kwargs = {"agent_id": agent_ref}
486
+ if endpoint:
487
+ kwargs["endpoint"] = endpoint
488
+ if api_key:
489
+ kwargs["api_key"] = api_key
490
+ return kwargs
491
+
492
+
493
+ def _state_matches_target(state: dict, target_agent: str | None) -> bool:
494
+ if not state or not target_agent:
495
+ return False
496
+ return target_agent == state.get("agent_id") or target_agent == state.get("name")
497
+
498
+
499
+ def _state_prefers_action_proxy(state: dict) -> bool:
500
+ if not isinstance(state, dict):
501
+ return False
502
+ framework = str(state.get("framework") or "").strip().lower()
503
+ state_type = str(state.get("type") or "").strip().lower()
504
+ return framework == "openclaw" or state_type == "openclaw"
505
+
506
+
507
+ def _resolve_workspace_region(region: str | None, state: dict) -> str:
508
+ return _normalize(region) or _normalize(state.get("region")) or os.getenv("KSYUN_REGION") or DEFAULT_REGION
509
+
510
+
511
+ def _resolve_workspace_agent_ref(explicit_ref: str | None, cwd: Path) -> str | None:
512
+ if explicit_ref:
513
+ return explicit_ref
514
+
515
+ state_ref = resolve_agent_ref(
516
+ None,
517
+ cwd=cwd,
518
+ include_state=True,
519
+ include_project_config=False,
520
+ )
521
+ if state_ref:
522
+ return state_ref.value
523
+
524
+ openclaw_state_ref = resolve_openclaw_ref(
525
+ None,
526
+ cwd=cwd,
527
+ include_state=True,
528
+ )
529
+ if openclaw_state_ref:
530
+ return openclaw_state_ref.value
531
+
532
+ config_ref = resolve_agent_ref(
533
+ None,
534
+ cwd=cwd,
535
+ include_state=False,
536
+ include_project_config=True,
537
+ )
538
+ if config_ref:
539
+ return config_ref.value
540
+
541
+ return None
542
+
543
+
544
+ def _resolve_workspace_runtime_access(
545
+ *,
546
+ state: dict,
547
+ target_agent: str | None,
548
+ endpoint: str | None,
549
+ api_key: str | None,
550
+ ) -> tuple[str | None, str | None]:
551
+ endpoint_value = _normalize(endpoint)
552
+ api_key_value = _normalize(api_key)
553
+ if endpoint_value:
554
+ return endpoint_value, api_key_value
555
+ if not _state_matches_target(state, target_agent):
556
+ return None, api_key_value
557
+ state_endpoint = _normalize(state.get("endpoint"))
558
+ state_api_key = api_key_value or _normalize(state.get("api_key"))
559
+ if _state_prefers_action_proxy(state):
560
+ if state_endpoint and state_api_key:
561
+ return state_endpoint, state_api_key
562
+ return None, api_key_value
563
+ return state_endpoint, state_api_key
564
+
565
+
566
+ def _resolve_workspace_command_context(
567
+ *,
568
+ agent_option: str | None,
569
+ positional_agent: str | None,
570
+ endpoint: str | None,
571
+ api_key: str | None,
572
+ region: str | None,
573
+ ) -> tuple[str | None, str, str | None, str | None]:
574
+ try:
575
+ agent_input = merge_agent_inputs(
576
+ agent_option=agent_option,
577
+ positional_agent=positional_agent,
578
+ )
579
+ except ValueError as e:
580
+ raise click.UsageError(str(e)) from e
581
+
582
+ cwd = Path(".").resolve()
583
+ state = load_state(cwd)
584
+ resolved_region = _resolve_workspace_region(region, state)
585
+ target_agent = _resolve_workspace_agent_ref(agent_input, cwd)
586
+ resolved_endpoint, resolved_api_key = _resolve_workspace_runtime_access(
587
+ state=state,
588
+ target_agent=target_agent,
589
+ endpoint=endpoint,
590
+ api_key=api_key,
591
+ )
592
+ if target_agent or resolved_endpoint:
593
+ return target_agent, resolved_region, resolved_endpoint, resolved_api_key
594
+
595
+ raise click.UsageError(
596
+ "请指定 Agent(--agent 或位置参数)、--endpoint,或在当前目录提供可解析的本地配置\n"
597
+ "自动解析顺序: .agentengine.state -> agentengine.yaml/ksadk.yaml"
598
+ )
599
+
600
+
601
+ async def _list_workspace_files(
602
+ *,
603
+ agent_ref: str | None,
604
+ path: str,
605
+ recursive: bool,
606
+ region: str,
607
+ endpoint: str | None,
608
+ api_key: str | None,
609
+ ):
610
+ async with AgentEngineClient(region=region) as client:
611
+ kwargs = {
612
+ "agent_id": agent_ref,
613
+ "path": path,
614
+ "recursive": recursive,
615
+ }
616
+ if endpoint:
617
+ kwargs["endpoint"] = endpoint
618
+ if api_key:
619
+ kwargs["api_key"] = api_key
620
+ payload = await client.list_workspace_files(**kwargs)
621
+ try:
622
+ health = await client.get_workspace_health(
623
+ agent_id=agent_ref,
624
+ endpoint=endpoint,
625
+ api_key=api_key,
626
+ )
627
+ except Exception:
628
+ health = {}
629
+ if health:
630
+ payload = dict(payload)
631
+ if health.get("root") and not payload.get("root"):
632
+ payload["root"] = health["root"]
633
+ if health.get("workspace_path"):
634
+ payload["workspace_real_root"] = health["workspace_path"]
635
+ return payload
636
+
637
+
638
+ async def _upload_workspace_file(
639
+ *,
640
+ agent_ref: str | None,
641
+ remote_path: str,
642
+ local_path: Path,
643
+ region: str,
644
+ endpoint: str | None,
645
+ api_key: str | None,
646
+ ):
647
+ async with AgentEngineClient(region=region) as client:
648
+ kwargs = {
649
+ "agent_id": agent_ref,
650
+ "remote_path": remote_path,
651
+ "local_path": local_path,
652
+ }
653
+ if endpoint:
654
+ kwargs["endpoint"] = endpoint
655
+ if api_key:
656
+ kwargs["api_key"] = api_key
657
+ return await client.upload_workspace_file(**kwargs)
658
+
659
+
660
+ async def _download_workspace_file(
661
+ *,
662
+ agent_ref: str | None,
663
+ remote_path: str,
664
+ region: str,
665
+ endpoint: str | None,
666
+ api_key: str | None,
667
+ ) -> bytes:
668
+ async with AgentEngineClient(region=region) as client:
669
+ kwargs = {
670
+ "agent_id": agent_ref,
671
+ "remote_path": remote_path,
672
+ }
673
+ if endpoint:
674
+ kwargs["endpoint"] = endpoint
675
+ if api_key:
676
+ kwargs["api_key"] = api_key
677
+ return await client.download_workspace_file(**kwargs)
678
+
679
+
680
+ async def _delete_workspace_file(
681
+ *,
682
+ agent_ref: str | None,
683
+ remote_path: str,
684
+ region: str,
685
+ endpoint: str | None,
686
+ api_key: str | None,
687
+ ):
688
+ async with AgentEngineClient(region=region) as client:
689
+ kwargs = {
690
+ "agent_id": agent_ref,
691
+ "remote_path": remote_path,
692
+ }
693
+ if endpoint:
694
+ kwargs["endpoint"] = endpoint
695
+ if api_key:
696
+ kwargs["api_key"] = api_key
697
+ return await client.delete_workspace_file(**kwargs)
698
+
699
+
700
+ async def _push_workspace_files(
701
+ *,
702
+ agent_ref: str | None,
703
+ local_dir: Path,
704
+ remote_path: str,
705
+ force: bool,
706
+ region: str,
707
+ endpoint: str | None,
708
+ api_key: str | None,
709
+ progress_callback: Callable[[dict], None] | None = None,
710
+ ignore_dev_artifacts: bool = False,
711
+ ignore_git_artifacts: bool = True,
712
+ ) -> dict:
713
+ remote_dir = _normalize_workspace_dir(remote_path)
714
+ local_report = _collect_local_files_report(
715
+ local_dir,
716
+ ignore_dev_artifacts=ignore_dev_artifacts,
717
+ ignore_git_artifacts=ignore_git_artifacts,
718
+ )
719
+ local_files = local_report["files"]
720
+ total_bytes = int(local_report["total_bytes"])
721
+ remote_existing: set[str] = set()
722
+ transport_mode = ""
723
+ client_kwargs = _workspace_client_kwargs(
724
+ agent_ref=agent_ref,
725
+ endpoint=endpoint,
726
+ api_key=api_key,
727
+ )
728
+
729
+ async with AgentEngineClient(region=region) as client:
730
+ if progress_callback:
731
+ progress_callback(
732
+ {
733
+ "phase": "list_start",
734
+ "remote_path": remote_dir,
735
+ "total": len(local_files),
736
+ }
737
+ )
738
+ try:
739
+ payload = await client.list_workspace_files(
740
+ path=remote_dir,
741
+ recursive=True,
742
+ **client_kwargs,
743
+ )
744
+ except AgentEngineAPIError as exc:
745
+ if exc.code != 404:
746
+ raise
747
+ payload = {"entries": []}
748
+ transport_mode = str(payload.get("transport_mode") or "").strip()
749
+ if progress_callback:
750
+ progress_callback(
751
+ {
752
+ "phase": "list_done",
753
+ "remote_path": remote_dir,
754
+ "total": len(local_files),
755
+ "remote_entry_count": len(payload.get("entries", [])),
756
+ }
757
+ )
758
+
759
+ for entry in payload.get("entries", []):
760
+ if entry.get("type") == "file" and entry.get("path"):
761
+ remote_existing.add(str(entry["path"]))
762
+
763
+ created: list[str] = []
764
+ overwritten: list[str] = []
765
+ skipped: list[str] = []
766
+ total_files = len(local_files)
767
+ for index, (relative_path, absolute_path) in enumerate(local_files, start=1):
768
+ destination_path = _join_remote_path(remote_dir, relative_path)
769
+ if destination_path in remote_existing and not force:
770
+ skipped.append(destination_path)
771
+ if progress_callback:
772
+ progress_callback(
773
+ {
774
+ "phase": "upload_skipped",
775
+ "current": index,
776
+ "total": total_files,
777
+ "remote_path": destination_path,
778
+ "local_path": str(absolute_path),
779
+ "size_bytes": int(absolute_path.stat().st_size),
780
+ "total_bytes": total_bytes,
781
+ }
782
+ )
783
+ continue
784
+ if progress_callback:
785
+ progress_callback(
786
+ {
787
+ "phase": "upload_start",
788
+ "current": index,
789
+ "total": total_files,
790
+ "remote_path": destination_path,
791
+ "local_path": str(absolute_path),
792
+ "size_bytes": int(absolute_path.stat().st_size),
793
+ "total_bytes": total_bytes,
794
+ }
795
+ )
796
+ response = await client.upload_workspace_file(
797
+ remote_path=destination_path,
798
+ local_path=absolute_path,
799
+ **client_kwargs,
800
+ )
801
+ if not transport_mode:
802
+ transport_mode = str(response.get("transport_mode") or "").strip()
803
+ resolved_path = response.get("entry", {}).get("path", destination_path)
804
+ if destination_path in remote_existing:
805
+ overwritten.append(resolved_path)
806
+ else:
807
+ created.append(resolved_path)
808
+ if progress_callback:
809
+ progress_callback(
810
+ {
811
+ "phase": "upload_done",
812
+ "current": index,
813
+ "total": total_files,
814
+ "remote_path": resolved_path,
815
+ "local_path": str(absolute_path),
816
+ "size_bytes": int(absolute_path.stat().st_size),
817
+ "total_bytes": total_bytes,
818
+ }
819
+ )
820
+
821
+ return {
822
+ "direction": "push",
823
+ "local_dir": str(local_dir),
824
+ "remote_path": remote_dir,
825
+ "workspace_root": DEFAULT_WORKSPACE_ROOT_LABEL,
826
+ "transport_mode": transport_mode or None,
827
+ "force": bool(force),
828
+ "total_files": len(local_files),
829
+ "created": created,
830
+ "overwritten": overwritten,
831
+ "skipped": skipped,
832
+ }
833
+
834
+
835
+ async def _pull_workspace_files(
836
+ *,
837
+ agent_ref: str | None,
838
+ local_dir: Path,
839
+ remote_path: str,
840
+ force: bool,
841
+ region: str,
842
+ endpoint: str | None,
843
+ api_key: str | None,
844
+ ) -> dict:
845
+ remote_dir = _normalize_workspace_dir(remote_path)
846
+ transport_mode = ""
847
+ client_kwargs = _workspace_client_kwargs(
848
+ agent_ref=agent_ref,
849
+ endpoint=endpoint,
850
+ api_key=api_key,
851
+ )
852
+
853
+ async with AgentEngineClient(region=region) as client:
854
+ payload = await client.list_workspace_files(
855
+ path=remote_dir,
856
+ recursive=True,
857
+ **client_kwargs,
858
+ )
859
+ transport_mode = str(payload.get("transport_mode") or "").strip()
860
+ remote_files = sorted(
861
+ [
862
+ entry
863
+ for entry in payload.get("entries", [])
864
+ if entry.get("type") == "file" and entry.get("path")
865
+ ],
866
+ key=lambda entry: str(entry.get("path", "")),
867
+ )
868
+
869
+ created: list[str] = []
870
+ overwritten: list[str] = []
871
+ skipped: list[str] = []
872
+ for entry in remote_files:
873
+ remote_file_path = str(entry["path"])
874
+ relative_path = _relative_remote_path(remote_file_path, remote_dir)
875
+ target_path = local_dir / Path(relative_path)
876
+ existed_before = target_path.exists()
877
+ if existed_before and target_path.is_dir():
878
+ raise click.ClickException(f"本地目标 {target_path} 是目录,无法写入文件")
879
+ if existed_before and not force:
880
+ skipped.append(relative_path)
881
+ continue
882
+
883
+ content = await client.download_workspace_file(
884
+ remote_path=remote_file_path,
885
+ **client_kwargs,
886
+ )
887
+ target_path.parent.mkdir(parents=True, exist_ok=True)
888
+ target_path.write_bytes(content)
889
+ if existed_before:
890
+ overwritten.append(relative_path)
891
+ else:
892
+ created.append(relative_path)
893
+
894
+ return {
895
+ "direction": "pull",
896
+ "local_dir": str(local_dir),
897
+ "remote_path": remote_dir,
898
+ "workspace_root": DEFAULT_WORKSPACE_ROOT_LABEL,
899
+ "transport_mode": transport_mode or None,
900
+ "force": bool(force),
901
+ "total_files": len(remote_files),
902
+ "created": created,
903
+ "overwritten": overwritten,
904
+ "skipped": skipped,
905
+ }
906
+
907
+
908
+ @click.group("files", context_settings=CONTEXT_SETTINGS)
909
+ def files():
910
+ """管理 Agent workspace 文件。"""
911
+
912
+
913
+ @files.command("list", context_settings=CONTEXT_SETTINGS)
914
+ @click.argument("agent_ref", required=False)
915
+ @click.option("--agent", "agent_option", "-a", help="Agent ID")
916
+ @click.option("--endpoint", "-e", help="Agent Endpoint URL (覆盖自动获取)")
917
+ @click.option("--api-key", help="Runtime API Key (与 --endpoint 搭配使用)")
918
+ @click.option("--path", default=".", show_default=True, help="Workspace 目录路径")
919
+ @click.option("--recursive", is_flag=True, help="递归列出目录")
920
+ @click.option("--region", "-r", default=None, envvar=None, help="区域 (默认优先读取 .agentengine.state)")
921
+ @cli_output_option()
922
+ def list_files(
923
+ agent_ref: str | None,
924
+ agent_option: str | None,
925
+ endpoint: str | None,
926
+ api_key: str | None,
927
+ path: str,
928
+ recursive: bool,
929
+ region: str | None,
930
+ output_mode: str | None,
931
+ ):
932
+ """列出 workspace 文件。"""
933
+ ensure_dry_run_supported("agentengine files list")
934
+ normalized_path = _normalize_workspace_dir(path)
935
+ agent_ref, region, endpoint, api_key = _resolve_workspace_command_context(
936
+ agent_option=agent_option,
937
+ positional_agent=agent_ref,
938
+ endpoint=endpoint,
939
+ api_key=api_key,
940
+ region=region,
941
+ )
942
+ payload = asyncio.run(
943
+ _list_workspace_files(
944
+ agent_ref=agent_ref,
945
+ path=normalized_path,
946
+ recursive=recursive,
947
+ region=region,
948
+ endpoint=endpoint,
949
+ api_key=api_key,
950
+ )
951
+ )
952
+ normalized_payload = _build_list_payload(payload)
953
+ _emit_payload(normalized_payload, output_mode)
954
+
955
+
956
+ @files.command("upload", context_settings=CONTEXT_SETTINGS)
957
+ @click.argument("agent_ref", required=False)
958
+ @click.option("--agent", "agent_option", "-a", help="Agent ID")
959
+ @click.option("--endpoint", "-e", help="Agent Endpoint URL (覆盖自动获取)")
960
+ @click.option("--api-key", help="Runtime API Key (与 --endpoint 搭配使用)")
961
+ @click.option(
962
+ "--local-path",
963
+ type=click.Path(exists=True, dir_okay=False, path_type=Path),
964
+ required=True,
965
+ help="本地文件路径",
966
+ )
967
+ @click.option("--remote-path", required=True, help="Workspace 目标路径")
968
+ @click.option("--region", "-r", default=None, envvar=None, help="区域 (默认优先读取 .agentengine.state)")
969
+ @cli_output_option()
970
+ def upload_file(
971
+ agent_ref: str | None,
972
+ agent_option: str | None,
973
+ endpoint: str | None,
974
+ api_key: str | None,
975
+ local_path: Path,
976
+ remote_path: str,
977
+ region: str | None,
978
+ output_mode: str | None,
979
+ ):
980
+ """上传文件到 workspace。"""
981
+ ensure_dry_run_supported("agentengine files upload")
982
+ normalized_remote_path = _normalize_workspace_file_path(remote_path)
983
+ agent_ref, region, endpoint, api_key = _resolve_workspace_command_context(
984
+ agent_option=agent_option,
985
+ positional_agent=agent_ref,
986
+ endpoint=endpoint,
987
+ api_key=api_key,
988
+ region=region,
989
+ )
990
+ payload = asyncio.run(
991
+ _upload_workspace_file(
992
+ agent_ref=agent_ref,
993
+ remote_path=normalized_remote_path,
994
+ local_path=local_path,
995
+ region=region,
996
+ endpoint=endpoint,
997
+ api_key=api_key,
998
+ )
999
+ )
1000
+ normalized_payload = _build_upload_payload(
1001
+ payload,
1002
+ local_path=local_path,
1003
+ remote_path=normalized_remote_path,
1004
+ )
1005
+ if output_mode == "json":
1006
+ click.echo(json.dumps(normalized_payload, ensure_ascii=False))
1007
+ return
1008
+ entry = normalized_payload.get("entry", {})
1009
+ _echo_section_title("上传完成", fg="green")
1010
+ _echo_key_value("本地文件", normalized_payload["local_path"], fg="bright_blue")
1011
+ _echo_key_value(
1012
+ "远端文件",
1013
+ normalized_payload["remote_display_path"],
1014
+ fg="cyan",
1015
+ )
1016
+ if entry.get("size_bytes") is not None:
1017
+ _echo_key_value("文件大小", normalized_payload["summary"]["size_human"], fg="yellow")
1018
+
1019
+
1020
+ @files.command("download", context_settings=CONTEXT_SETTINGS)
1021
+ @click.argument("agent_ref", required=False)
1022
+ @click.option("--agent", "agent_option", "-a", help="Agent ID")
1023
+ @click.option("--endpoint", "-e", help="Agent Endpoint URL (覆盖自动获取)")
1024
+ @click.option("--api-key", help="Runtime API Key (与 --endpoint 搭配使用)")
1025
+ @click.option("--remote-path", required=True, help="Workspace 文件路径")
1026
+ @click.option(
1027
+ "--output-path",
1028
+ type=click.Path(dir_okay=False, path_type=Path),
1029
+ required=True,
1030
+ help="本地输出文件路径",
1031
+ )
1032
+ @click.option("--region", "-r", default=None, envvar=None, help="区域 (默认优先读取 .agentengine.state)")
1033
+ @cli_output_option()
1034
+ def download_file(
1035
+ agent_ref: str | None,
1036
+ agent_option: str | None,
1037
+ endpoint: str | None,
1038
+ api_key: str | None,
1039
+ remote_path: str,
1040
+ output_path: Path,
1041
+ region: str | None,
1042
+ output_mode: str | None,
1043
+ ):
1044
+ """下载 workspace 文件。"""
1045
+ ensure_dry_run_supported("agentengine files download")
1046
+ normalized_remote_path = _normalize_workspace_file_path(remote_path)
1047
+ agent_ref, region, endpoint, api_key = _resolve_workspace_command_context(
1048
+ agent_option=agent_option,
1049
+ positional_agent=agent_ref,
1050
+ endpoint=endpoint,
1051
+ api_key=api_key,
1052
+ region=region,
1053
+ )
1054
+ content = asyncio.run(
1055
+ _download_workspace_file(
1056
+ agent_ref=agent_ref,
1057
+ remote_path=normalized_remote_path,
1058
+ region=region,
1059
+ endpoint=endpoint,
1060
+ api_key=api_key,
1061
+ )
1062
+ )
1063
+ output_path.parent.mkdir(parents=True, exist_ok=True)
1064
+ output_path.write_bytes(content)
1065
+ payload = _build_download_payload(
1066
+ remote_path=normalized_remote_path,
1067
+ output_path=output_path,
1068
+ size_bytes=len(content),
1069
+ )
1070
+ if output_mode == "json":
1071
+ click.echo(json.dumps(payload, ensure_ascii=False))
1072
+ return
1073
+ _echo_section_title("下载完成", fg="green")
1074
+ _echo_key_value("远端文件", payload["remote_display_path"], fg="cyan")
1075
+ _echo_key_value("本地文件", payload["local_path"], fg="bright_blue")
1076
+ _echo_key_value("文件大小", payload["size_human"], fg="yellow")
1077
+
1078
+
1079
+ @files.command("delete", context_settings=CONTEXT_SETTINGS)
1080
+ @click.argument("agent_ref", required=False)
1081
+ @click.option("--agent", "agent_option", "-a", help="Agent ID")
1082
+ @click.option("--endpoint", "-e", help="Agent Endpoint URL (覆盖自动获取)")
1083
+ @click.option("--api-key", help="Runtime API Key (与 --endpoint 搭配使用)")
1084
+ @click.option("--remote-path", required=True, help="Workspace 文件路径")
1085
+ @click.option("--yes", is_flag=True, help="跳过确认")
1086
+ @click.option("--region", "-r", default=None, envvar=None, help="区域 (默认优先读取 .agentengine.state)")
1087
+ @cli_output_option()
1088
+ def delete_file(
1089
+ agent_ref: str | None,
1090
+ agent_option: str | None,
1091
+ endpoint: str | None,
1092
+ api_key: str | None,
1093
+ remote_path: str,
1094
+ yes: bool,
1095
+ region: str | None,
1096
+ output_mode: str | None,
1097
+ ):
1098
+ """删除 workspace 文件。"""
1099
+ ensure_dry_run_supported("agentengine files delete")
1100
+ normalized_remote_path = _normalize_workspace_file_path(remote_path)
1101
+ agent_ref, region, endpoint, api_key = _resolve_workspace_command_context(
1102
+ agent_option=agent_option,
1103
+ positional_agent=agent_ref,
1104
+ endpoint=endpoint,
1105
+ api_key=api_key,
1106
+ region=region,
1107
+ )
1108
+ if not yes and not click.confirm(f"删除 workspace 文件 {normalized_remote_path}?", default=False):
1109
+ raise click.Abort()
1110
+ payload = asyncio.run(
1111
+ _delete_workspace_file(
1112
+ agent_ref=agent_ref,
1113
+ remote_path=normalized_remote_path,
1114
+ region=region,
1115
+ endpoint=endpoint,
1116
+ api_key=api_key,
1117
+ )
1118
+ )
1119
+ normalized_payload = _build_delete_payload(payload, remote_path=normalized_remote_path)
1120
+ if output_mode == "json":
1121
+ click.echo(json.dumps(normalized_payload, ensure_ascii=False))
1122
+ return
1123
+ _echo_section_title("删除完成", fg="red")
1124
+ _echo_key_value("远端文件", normalized_payload["remote_display_path"], fg="cyan")
1125
+
1126
+
1127
+ @files.command("push", context_settings=CONTEXT_SETTINGS)
1128
+ @click.argument("agent_ref", required=False)
1129
+ @click.option("--agent", "agent_option", "-a", help="Agent ID")
1130
+ @click.option("--endpoint", "-e", help="Agent Endpoint URL (覆盖自动获取)")
1131
+ @click.option("--api-key", help="Runtime API Key (与 --endpoint 搭配使用)")
1132
+ @click.option(
1133
+ "--local-dir",
1134
+ type=click.Path(exists=True, file_okay=False, dir_okay=True, path_type=Path),
1135
+ required=True,
1136
+ help="本地目录路径",
1137
+ )
1138
+ @click.option("--remote-path", default=".", show_default=True, help="Workspace 目标目录")
1139
+ @click.option("--force", is_flag=True, help="覆盖远端已存在的同名文件")
1140
+ @click.option("--region", "-r", default=None, envvar=None, help="区域 (默认优先读取 .agentengine.state)")
1141
+ @cli_output_option()
1142
+ def push_files(
1143
+ agent_ref: str | None,
1144
+ agent_option: str | None,
1145
+ endpoint: str | None,
1146
+ api_key: str | None,
1147
+ local_dir: Path,
1148
+ remote_path: str,
1149
+ force: bool,
1150
+ region: str | None,
1151
+ output_mode: str | None,
1152
+ ):
1153
+ """递归推送本地目录到 workspace 子目录。"""
1154
+ ensure_dry_run_supported("agentengine files push")
1155
+ normalized_remote_path = _normalize_workspace_dir(remote_path)
1156
+ agent_ref, region, endpoint, api_key = _resolve_workspace_command_context(
1157
+ agent_option=agent_option,
1158
+ positional_agent=agent_ref,
1159
+ endpoint=endpoint,
1160
+ api_key=api_key,
1161
+ region=region,
1162
+ )
1163
+ payload = asyncio.run(
1164
+ _push_workspace_files(
1165
+ agent_ref=agent_ref,
1166
+ local_dir=local_dir,
1167
+ remote_path=normalized_remote_path,
1168
+ force=force,
1169
+ region=region,
1170
+ endpoint=endpoint,
1171
+ api_key=api_key,
1172
+ )
1173
+ )
1174
+ normalized_payload = _build_sync_payload(payload)
1175
+ _emit_sync_payload(normalized_payload, output_mode)
1176
+
1177
+
1178
+ @files.command("pull", context_settings=CONTEXT_SETTINGS)
1179
+ @click.argument("agent_ref", required=False)
1180
+ @click.option("--agent", "agent_option", "-a", help="Agent ID")
1181
+ @click.option("--endpoint", "-e", help="Agent Endpoint URL (覆盖自动获取)")
1182
+ @click.option("--api-key", help="Runtime API Key (与 --endpoint 搭配使用)")
1183
+ @click.option("--remote-path", default=".", show_default=True, help="Workspace 源目录")
1184
+ @click.option(
1185
+ "--local-dir",
1186
+ type=click.Path(file_okay=False, dir_okay=True, path_type=Path),
1187
+ required=True,
1188
+ help="本地输出目录",
1189
+ )
1190
+ @click.option("--force", is_flag=True, help="覆盖本地已存在的同名文件")
1191
+ @click.option("--region", "-r", default=None, envvar=None, help="区域 (默认优先读取 .agentengine.state)")
1192
+ @cli_output_option()
1193
+ def pull_files(
1194
+ agent_ref: str | None,
1195
+ agent_option: str | None,
1196
+ endpoint: str | None,
1197
+ api_key: str | None,
1198
+ remote_path: str,
1199
+ local_dir: Path,
1200
+ force: bool,
1201
+ region: str | None,
1202
+ output_mode: str | None,
1203
+ ):
1204
+ """递归拉取 workspace 子目录到本地目录。"""
1205
+ ensure_dry_run_supported("agentengine files pull")
1206
+ normalized_remote_path = _normalize_workspace_dir(remote_path)
1207
+ agent_ref, region, endpoint, api_key = _resolve_workspace_command_context(
1208
+ agent_option=agent_option,
1209
+ positional_agent=agent_ref,
1210
+ endpoint=endpoint,
1211
+ api_key=api_key,
1212
+ region=region,
1213
+ )
1214
+ local_dir.mkdir(parents=True, exist_ok=True)
1215
+ payload = asyncio.run(
1216
+ _pull_workspace_files(
1217
+ agent_ref=agent_ref,
1218
+ local_dir=local_dir,
1219
+ remote_path=normalized_remote_path,
1220
+ force=force,
1221
+ region=region,
1222
+ endpoint=endpoint,
1223
+ api_key=api_key,
1224
+ )
1225
+ )
1226
+ normalized_payload = _build_sync_payload(payload)
1227
+ _emit_sync_payload(normalized_payload, output_mode)