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_mcp.py ADDED
@@ -0,0 +1,1174 @@
1
+ """agentengine mcp - MCP 资源管理。"""
2
+
3
+ import os
4
+ from dataclasses import asdict, is_dataclass, replace
5
+ from datetime import datetime
6
+ from pathlib import Path
7
+
8
+ import click
9
+
10
+ from ksadk.api.client import DryRunExit
11
+ from ksadk.cli.agent_ref import resolve_mcp_ref
12
+ from ksadk.cli.dry_run import dry_run_option, run_async_with_dry_run, effective_dry_run
13
+ from ksadk.cli.error_utils import abort_with_cli_error, remote_error, resolution_error, usage_error, validation_error
14
+ from ksadk.cli.network_options import build_network_payload, network_cli_kwargs, network_options
15
+ from ksadk.cli.resource_common import (
16
+ CONTEXT_SETTINGS,
17
+ ResourceActionSet,
18
+ ResourceDescriptor,
19
+ ResourceListSchema,
20
+ ResourceStatusSchema,
21
+ build_resource_group_help,
22
+ confirm_destructive,
23
+ confirm_options,
24
+ pagination_options,
25
+ print_next_action_hint,
26
+ render_descriptor_list,
27
+ render_descriptor_status,
28
+ region_option,
29
+ )
30
+ from ksadk.cli.ui import (
31
+ capture_standard_output,
32
+ get_console,
33
+ is_json_output,
34
+ output_option as cli_output_option,
35
+ print_info,
36
+ print_kv,
37
+ print_rule,
38
+ print_success,
39
+ print_title,
40
+ print_warn,
41
+ status_rich_style,
42
+ )
43
+ from ksadk.cli.workflow_common import (
44
+ build_workflow_local_plan,
45
+ clear_build_metadata,
46
+ emit_no_cache_hint,
47
+ load_cached_artifact_reference,
48
+ plan_artifact_build,
49
+ print_workflow_header,
50
+ render_workflow_dry_run,
51
+ render_workflow_result,
52
+ resolve_artifact_build_plan,
53
+ )
54
+ from ksadk.builders.container_builder import (
55
+ registry_kind_label,
56
+ resolve_registry_credentials,
57
+ )
58
+
59
+ console = get_console()
60
+
61
+ MCP_RESOURCE = ResourceDescriptor(
62
+ name="MCP",
63
+ summary="MCP 资源管理。",
64
+ resource_key="mcp",
65
+ actions=ResourceActionSet(
66
+ list="agentengine mcp list",
67
+ status="agentengine mcp status [mcp_ref]",
68
+ delete="agentengine mcp delete [mcp_ref...]",
69
+ deploy="agentengine mcp deploy",
70
+ extra=("agentengine mcp build",),
71
+ ),
72
+ list_schema=ResourceListSchema(
73
+ title="MCP 列表",
74
+ noun="MCP",
75
+ columns=(
76
+ {"header": "ID", "key": "id", "style": "#58a6ff", "no_wrap": True},
77
+ {"header": "名称", "key": "name", "style": "white"},
78
+ {"header": "状态", "key": "status", "no_wrap": True, "justify": "center"},
79
+ {"header": "MCP URL", "key": "mcp_url", "style": "#8b949e", "overflow": "ellipsis"},
80
+ ),
81
+ empty_message="没有找到已部署的 MCP",
82
+ summary_lines=("使用 `agentengine mcp status <mcp_ref>` 查看详情。",),
83
+ ),
84
+ status_schema=ResourceStatusSchema(
85
+ title="MCP 状态",
86
+ next_steps=("agentengine mcp list",),
87
+ ),
88
+ examples=(
89
+ "agentengine mcp deploy .",
90
+ "agentengine mcp list",
91
+ "KSYUN_REGION=cn-beijing-6 agentengine mcp status <id>",
92
+ ),
93
+ missing_ref_message="请指定 MCP ID/名称,或在 MCP 项目目录下运行",
94
+ resolution_commands=("agentengine mcp list",),
95
+ list_action_help="列出已部署的 MCP",
96
+ status_action_help="查看单个 MCP 状态",
97
+ delete_action_help="删除一个或多个 MCP",
98
+ deploy_action_help="部署 MCP 到云端",
99
+ extra_action_help=(("build", "构建 MCP 制品"),),
100
+ )
101
+
102
+
103
+ def _abort_mcp_error(
104
+ err: Exception,
105
+ *,
106
+ context: str | None = None,
107
+ argv: list[str] | None = None,
108
+ show_help: bool = False,
109
+ ) -> None:
110
+ abort_with_cli_error(err, context=context, argv=argv, show_help=show_help)
111
+
112
+
113
+ @click.group("mcp", context_settings=CONTEXT_SETTINGS, help=build_resource_group_help(MCP_RESOURCE))
114
+ def mcp():
115
+ pass
116
+
117
+
118
+ @mcp.command("build", context_settings=CONTEXT_SETTINGS)
119
+ @click.argument("mcp_dir", default=".", type=click.Path(exists=True))
120
+ @click.option(
121
+ "--artifact-type",
122
+ type=click.Choice(["Code", "Container"], case_sensitive=True),
123
+ default="Code",
124
+ help="构建模式: Code-代码包 (默认) 或 Container-镜像模式",
125
+ )
126
+ @click.option("--push", is_flag=True, help="构建后上传/推送制品")
127
+ @click.option("--tag", help="镜像标签 (Container 模式)")
128
+ @click.option("--registry", help="镜像仓库地址 (Container 模式)")
129
+ @click.option(
130
+ "--region", "-r",
131
+ default="cn-beijing-6",
132
+ envvar="KSYUN_REGION",
133
+ help="构建使用的区域 (Code 模式用于 KS3,Container 模式用于默认镜像仓库推断)",
134
+ )
135
+ @click.option(
136
+ "--ks3-bucket",
137
+ help="KS3 存储桶名称 (Code 模式,默认: agentengine-{account_id}-{region})"
138
+ )
139
+ @click.option(
140
+ "--no-cache",
141
+ is_flag=True,
142
+ default=False,
143
+ help="强制重新构建,不使用缓存 (Code/Container 模式均适用)",
144
+ )
145
+ @cli_output_option()
146
+ def build(
147
+ mcp_dir: str,
148
+ artifact_type: str,
149
+ push: bool,
150
+ tag: str | None,
151
+ registry: str | None,
152
+ region: str,
153
+ ks3_bucket: str | None,
154
+ no_cache: bool,
155
+ output_mode: str | None,
156
+ ):
157
+ """构建 MCP Server 制品。"""
158
+ _ = output_mode
159
+ try:
160
+ result = run_async_with_dry_run(
161
+ _build_mcp_async(
162
+ mcp_dir=mcp_dir,
163
+ artifact_type=artifact_type,
164
+ push=push,
165
+ region=region,
166
+ ks3_bucket=ks3_bucket,
167
+ tag=tag,
168
+ registry=registry,
169
+ no_cache=no_cache,
170
+ ),
171
+ dry_run=False,
172
+ )
173
+ except Exception as e:
174
+ _abort_mcp_error(e, context="构建失败", argv=["mcp", "build"])
175
+ return
176
+ if result is not None and is_json_output():
177
+ render_workflow_result(action="build", result=result)
178
+
179
+
180
+ @mcp.command("deploy", context_settings=CONTEXT_SETTINGS)
181
+ @click.argument("mcp_dir", default=".", type=click.Path(exists=True))
182
+ @click.option(
183
+ "--name", "-n",
184
+ help="MCP Server 名称 (默认: 目录名)"
185
+ )
186
+ @click.option(
187
+ "--region", "-r",
188
+ default="cn-beijing-6",
189
+ envvar="KSYUN_REGION",
190
+ help="部署区域 (default: cn-beijing-6)"
191
+ )
192
+ @click.option(
193
+ "--ks3-bucket",
194
+ help="KS3 存储桶名称 (默认: agentengine-{region})"
195
+ )
196
+ @click.option(
197
+ "--enable-auth",
198
+ is_flag=True,
199
+ default=False,
200
+ help="启用 API Key 保护 (可选)"
201
+ )
202
+ @dry_run_option("仅显示请求内容,不实际部署")
203
+ @click.option(
204
+ "--artifact-type",
205
+ type=click.Choice(["Code", "Container"], case_sensitive=True),
206
+ default="Code",
207
+ help="部署模式: Code-代码包 (默认) 或 Container-镜像模式",
208
+ )
209
+ @click.option(
210
+ "--no-cache",
211
+ is_flag=True,
212
+ default=False,
213
+ help="强制重新构建,不使用缓存 (Code/Container 模式均适用)",
214
+ )
215
+ @network_options
216
+ @cli_output_option()
217
+ def deploy(
218
+ mcp_dir: str,
219
+ name: str,
220
+ region: str,
221
+ ks3_bucket: str,
222
+ enable_auth: bool,
223
+ dry_run: bool,
224
+ artifact_type: str,
225
+ no_cache: bool,
226
+ enable_public_access: bool | None,
227
+ enable_vpc_access: bool,
228
+ vpc_id: str | None,
229
+ subnet_id: str | None,
230
+ security_group_id: str | None,
231
+ availability_zone: str | None,
232
+ output_mode: str | None,
233
+ ):
234
+ """部署 MCP Server 到云端
235
+
236
+ \b
237
+ MCP_DIR: MCP 项目目录 (默认: 当前目录)
238
+
239
+ \b
240
+ 示例:
241
+ # 1) 默认部署 (Code 模式)
242
+ agentengine mcp deploy .
243
+ # 2) 显式指定部署参数
244
+ agentengine mcp deploy ./my-mcp --name my-tools --artifact-type Container
245
+ # 3) 显式指定区域
246
+ KSYUN_REGION=cn-beijing-6 agentengine mcp deploy . --dry-run
247
+
248
+ \b
249
+ 部署后的 endpoint 兼容标准 MCP 协议,可以被:
250
+ - LangGraph/LangChain (via langchain-mcp-adapters)
251
+ - Google ADK (via MCPToolset)
252
+ - Cursor / Claude Code
253
+ - Dify 等外部平台
254
+ """
255
+ _ = output_mode
256
+ dry_run = effective_dry_run(dry_run)
257
+ dry_run_context: dict[str, object] = {}
258
+ try:
259
+ result = run_async_with_dry_run(
260
+ _deploy_mcp_async(
261
+ mcp_dir=mcp_dir,
262
+ name=name,
263
+ region=region,
264
+ ks3_bucket=ks3_bucket,
265
+ enable_auth=enable_auth,
266
+ dry_run=dry_run,
267
+ artifact_type=artifact_type,
268
+ no_cache=no_cache,
269
+ **network_cli_kwargs(
270
+ enable_public_access=enable_public_access,
271
+ enable_vpc_access=enable_vpc_access,
272
+ vpc_id=vpc_id,
273
+ subnet_id=subnet_id,
274
+ security_group_id=security_group_id,
275
+ availability_zone=availability_zone,
276
+ ),
277
+ dry_run_context=dry_run_context,
278
+ ),
279
+ dry_run=dry_run,
280
+ on_dry_run=(
281
+ lambda exc: render_workflow_dry_run(
282
+ action="deploy",
283
+ request=dict(exc.payload or {}),
284
+ plan=dict(dry_run_context.get("plan") or {}) or None,
285
+ )
286
+ ),
287
+ )
288
+ except Exception as e:
289
+ _abort_mcp_error(e, context="部署失败", argv=["mcp", "deploy"])
290
+ return
291
+ if result is not None and is_json_output():
292
+ render_workflow_result(action="deploy", result=result)
293
+
294
+
295
+ def _load_mcp_config(mcp_path: Path) -> dict:
296
+ """加载 MCP 项目配置文件。"""
297
+ import yaml
298
+
299
+ config_path = mcp_path / "agentengine.yaml"
300
+ if not config_path.exists():
301
+ config_path = mcp_path / "ksadk.yaml"
302
+
303
+ if not config_path.exists():
304
+ return {}
305
+
306
+ with open(config_path, encoding="utf-8-sig") as f:
307
+ return yaml.safe_load(f) or {}
308
+
309
+
310
+ def _normalize_mcp_name(name: str | None, mcp_path: Path, config: dict | None = None) -> str:
311
+ raw_name = (name or (config or {}).get("name") or mcp_path.name).strip()
312
+ return raw_name.replace("-", "_").replace(".", "_")
313
+
314
+
315
+ def _normalize_artifact_type(artifact_type: str | None) -> str:
316
+ return "Container" if str(artifact_type or "").strip().lower() == "container" else "Code"
317
+
318
+
319
+ def _normalize_upload_region(region: str) -> str:
320
+ return "cn-beijing-6" if str(region or "").strip().lower() == "pre-online" else region
321
+
322
+
323
+ def _default_container_tag(config: dict, tag: str | None) -> str:
324
+ return (
325
+ str(tag or "").strip()
326
+ or str(config.get("version") or "").strip()
327
+ or str((config.get("image") or {}).get("tag") or "").strip()
328
+ or "latest"
329
+ )
330
+
331
+
332
+ def _default_container_registry(config: dict, registry: str | None) -> str:
333
+ return (
334
+ str(registry or "").strip().rstrip("/")
335
+ or str(os.getenv("KCR_REGISTRY") or "").strip().rstrip("/")
336
+ or str((config.get("image") or {}).get("registry") or "").strip().rstrip("/")
337
+ or "hub.kce.ksyun.com/agentengine"
338
+ )
339
+
340
+
341
+ def _parse_ks3_bucket(artifact_path: str | None) -> str | None:
342
+ normalized = str(artifact_path or "").strip()
343
+ if not normalized.startswith("ks3://"):
344
+ return None
345
+ bucket_and_key = normalized[6:]
346
+ if "/" not in bucket_and_key:
347
+ return bucket_and_key or None
348
+ bucket, _ = bucket_and_key.split("/", 1)
349
+ return bucket or None
350
+
351
+
352
+ def _predict_mcp_artifact_reference(
353
+ *,
354
+ artifact_type: str,
355
+ mcp_name: str,
356
+ region: str,
357
+ ks3_bucket: str | None,
358
+ registry: str | None,
359
+ account_id: str | None,
360
+ ) -> str:
361
+ if artifact_type == "Code":
362
+ bucket = str(ks3_bucket or "").strip()
363
+ if not bucket:
364
+ normalized_region = _normalize_upload_region(region)
365
+ if account_id and normalized_region:
366
+ bucket = f"agentengine-{account_id}-{normalized_region}"
367
+ if not bucket:
368
+ bucket = "<ks3-bucket>"
369
+ return f"ks3://{bucket}/mcps/{mcp_name}/code_<dry-run>.zip"
370
+
371
+ normalized_registry = str(registry or "").strip().rstrip("/") or "<registry>"
372
+ return f"{normalized_registry}/{mcp_name}:dry-run"
373
+
374
+
375
+ def _print_mcp_detection(detection_result) -> None:
376
+ print_success("检测到 FastMCP 项目")
377
+ print_kv("入口", detection_result.entry_point)
378
+ print_kv("MCP 变量", detection_result.mcp_variable)
379
+ if detection_result.tools:
380
+ print_kv("工具", ", ".join(detection_result.tools))
381
+
382
+
383
+ def _print_mcp_build_summary(
384
+ *,
385
+ artifact_type: str,
386
+ build_result,
387
+ artifact_reference: str,
388
+ push: bool,
389
+ ) -> None:
390
+ print_rule(f"构建摘要 ({artifact_type} 模式)")
391
+ if build_result.artifact_path:
392
+ print_kv("zip 文件", str(build_result.artifact_path))
393
+ print_kv("大小", f"{build_result.artifact_size_mb:.2f} MB")
394
+ if build_result.metadata.get("image"):
395
+ print_kv("镜像", str(build_result.metadata["image"]))
396
+ if artifact_type == "Code" and push and artifact_reference:
397
+ print_kv("KS3 路径", artifact_reference, value_style="#58a6ff")
398
+ if artifact_type == "Container" and push and artifact_reference:
399
+ print_kv("镜像仓库", artifact_reference, value_style="#58a6ff")
400
+ if build_result.metadata.get("mcp_variable"):
401
+ print_kv("MCP 变量", str(build_result.metadata["mcp_variable"]))
402
+ if build_result.metadata.get("tools"):
403
+ print_kv("工具", ", ".join(build_result.metadata["tools"]))
404
+
405
+
406
+ def _persist_mcp_build_metadata(mcp_path: Path, build_result, *, artifact_type: str, artifact_reference: str) -> None:
407
+ metadata_file = mcp_path / ".agentengine" / "build-metadata.json"
408
+ if is_dataclass(build_result):
409
+ payload = asdict(build_result)
410
+ else:
411
+ payload = {
412
+ "success": bool(getattr(build_result, "success", False)),
413
+ "artifact_path": getattr(build_result, "artifact_path", None),
414
+ "artifact_size": int(getattr(build_result, "artifact_size", 0) or 0),
415
+ "metadata": dict(getattr(build_result, "metadata", {}) or {}),
416
+ "error_message": getattr(build_result, "error_message", None),
417
+ }
418
+ payload["metadata"] = dict(payload.get("metadata") or {})
419
+
420
+ if artifact_type == "Code":
421
+ payload["metadata"]["ks3_path"] = artifact_reference
422
+ else:
423
+ payload["metadata"]["image"] = artifact_reference
424
+ payload["image"] = artifact_reference
425
+
426
+ def _serialize(obj):
427
+ if isinstance(obj, Path):
428
+ return str(obj)
429
+ raise TypeError(f"Object of type {type(obj)} is not JSON serializable")
430
+
431
+ metadata_file.parent.mkdir(parents=True, exist_ok=True)
432
+ import json
433
+
434
+ with open(metadata_file, "w", encoding="utf-8") as f:
435
+ json.dump(payload, f, indent=2, default=_serialize)
436
+
437
+
438
+ async def _build_code_artifact(
439
+ *,
440
+ mcp_path: Path,
441
+ mcp_name: str,
442
+ region: str,
443
+ ks3_bucket: str | None,
444
+ no_cache: bool,
445
+ push: bool,
446
+ ):
447
+ from ksadk.builders.ks3_uploader import KS3Uploader
448
+ from ksadk.builders.mcp_builder import MCPCodeBuilder
449
+
450
+ print_rule(f"构建代码包: {mcp_name}")
451
+ builder = MCPCodeBuilder(mcp_path, config={"no_cache": no_cache})
452
+ with capture_standard_output():
453
+ build_result = builder.build()
454
+
455
+ if not build_result.success:
456
+ raise validation_error(build_result.error_message or "构建失败")
457
+
458
+ artifact_reference = str(build_result.artifact_path or "")
459
+ if push:
460
+ print_rule("上传到 KS3")
461
+ upload_region = _normalize_upload_region(region)
462
+ uploader = KS3Uploader(region=upload_region, bucket=ks3_bucket)
463
+ timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
464
+ object_key = f"mcps/{mcp_name}/code_{timestamp}.zip"
465
+ with capture_standard_output():
466
+ ks3_path = await uploader.upload(build_result.artifact_path, object_key)
467
+ if not ks3_path:
468
+ raise remote_error("KS3 上传失败")
469
+ artifact_reference = ks3_path
470
+ build_result.metadata["ks3_path"] = ks3_path
471
+ build_result.metadata["ks3_bucket"] = uploader.bucket_name
472
+ print_success(f"上传成功: {ks3_path}")
473
+ else:
474
+ print_info("跳过上传 (使用 --push 上传到 KS3)")
475
+
476
+ return build_result, artifact_reference
477
+
478
+
479
+ def _build_container_artifact(
480
+ *,
481
+ mcp_path: Path,
482
+ tag: str | None,
483
+ registry: str | None,
484
+ no_cache: bool,
485
+ push: bool,
486
+ ):
487
+ from ksadk.builders.mcp_builder import MCPContainerBuilder
488
+
489
+ print_rule("构建 Docker 镜像")
490
+ builder = MCPContainerBuilder(
491
+ project_dir=mcp_path,
492
+ tag=tag,
493
+ registry=registry,
494
+ no_cache=no_cache,
495
+ )
496
+ with capture_standard_output():
497
+ build_result = builder.build()
498
+
499
+ if not build_result.success:
500
+ raise validation_error(f"Docker 镜像构建失败: {build_result.error_message}")
501
+
502
+ image_name = str(build_result.metadata.get("image") or "")
503
+ if not image_name:
504
+ raise validation_error("Docker 镜像构建成功,但未返回镜像地址")
505
+
506
+ if push:
507
+ print_rule("推送镜像到仓库")
508
+ with capture_standard_output():
509
+ pushed = builder.push(image_name)
510
+ if not pushed:
511
+ raise remote_error("镜像推送失败")
512
+ print_success(f"推送成功: {image_name}")
513
+ else:
514
+ print_info("跳过推送 (使用 --push 推送镜像)")
515
+
516
+ return build_result, image_name
517
+
518
+
519
+ def _build_mcp_request_data(
520
+ *,
521
+ mcp_name: str,
522
+ config: dict,
523
+ artifact_type: str,
524
+ artifact_reference: str,
525
+ region: str,
526
+ enable_auth: bool,
527
+ detection_result,
528
+ ) -> dict:
529
+ resources = config.get("resources") or {}
530
+ scaling = config.get("scaling") or {}
531
+ request_data = {
532
+ "name": mcp_name,
533
+ "type": "mcp",
534
+ "artifact_type": artifact_type,
535
+ "artifact_path": artifact_reference,
536
+ "region": region,
537
+ "enable_auth": enable_auth,
538
+ "resources": {
539
+ "cpu": str(resources.get("cpu", "1")),
540
+ "memory": str(resources.get("memory", "2Gi")),
541
+ },
542
+ "scaling": {
543
+ "min_replicas": int(scaling.get("min_replicas", 1)),
544
+ "max_replicas": int(scaling.get("max_replicas", 5)),
545
+ "concurrency": int(scaling.get("concurrency", 20)),
546
+ },
547
+ "metadata": {
548
+ "mcp_variable": detection_result.mcp_variable,
549
+ "tools": list(detection_result.tools or []),
550
+ },
551
+ }
552
+
553
+ if artifact_type == "Code":
554
+ from ksadk.common.auth import AWSV4Auth
555
+
556
+ auth = AWSV4Auth()
557
+ bucket = _parse_ks3_bucket(artifact_reference)
558
+ request_data["ks3"] = {
559
+ "access_key": auth.access_key_id or None,
560
+ "secret_key": auth.secret_access_key or None,
561
+ "region": _normalize_upload_region(region),
562
+ "bucket": bucket,
563
+ }
564
+ else:
565
+ kcr_username, kcr_password, registry_kind = resolve_registry_credentials(artifact_reference)
566
+ if kcr_username and kcr_password:
567
+ request_data["image_credential"] = {
568
+ "endpoint": artifact_reference.split("/", 1)[0],
569
+ "username": kcr_username,
570
+ "password": kcr_password,
571
+ }
572
+ print_kv("镜像凭证", f"{kcr_username}@{request_data['image_credential']['endpoint']}")
573
+ else:
574
+ if registry_kind == "personal_kcr":
575
+ print_warn("未配置个人版 KCR 镜像凭证 (KSYUN_ACCOUNT_ID/KCR_PASSWORD),私有镜像可能无法拉取")
576
+ else:
577
+ print_warn(
578
+ f"未配置{registry_kind_label(registry_kind)} 镜像凭证 "
579
+ "(KCR_USERNAME/KCR_PASSWORD),私有镜像可能无法拉取"
580
+ )
581
+
582
+ return request_data
583
+
584
+
585
+ async def _build_mcp_async(
586
+ *,
587
+ mcp_dir: str,
588
+ artifact_type: str,
589
+ push: bool,
590
+ region: str,
591
+ ks3_bucket: str | None,
592
+ tag: str | None,
593
+ registry: str | None,
594
+ no_cache: bool,
595
+ ):
596
+ """异步 MCP 构建流程。"""
597
+ from ksadk.detection.mcp_detector import MCPDetector
598
+
599
+ mcp_path = Path(mcp_dir).resolve()
600
+ config = _load_mcp_config(mcp_path)
601
+ normalized_artifact_type = _normalize_artifact_type(artifact_type)
602
+ mcp_name = _normalize_mcp_name(None, mcp_path, config)
603
+
604
+ print_workflow_header(
605
+ title="MCP 构建",
606
+ subtitle=f"mode: {normalized_artifact_type}",
607
+ project_dir=mcp_path,
608
+ target="build",
609
+ region=region,
610
+ mode_label="构建模式",
611
+ mode_value=normalized_artifact_type,
612
+ )
613
+
614
+ detector = MCPDetector(str(mcp_path))
615
+ detection_result = detector.detect()
616
+ if not detection_result.is_valid:
617
+ raise validation_error(
618
+ "未检测到 FastMCP 项目。",
619
+ hints=["请确保项目包含 `from fastmcp import FastMCP`。"],
620
+ )
621
+ _print_mcp_detection(detection_result)
622
+ print_kv("构建名称", mcp_name)
623
+
624
+ if not push:
625
+ try:
626
+ if clear_build_metadata(mcp_path):
627
+ print_info("当前构建未发布远端制品,已清理旧的可复用部署引用")
628
+ except Exception as e:
629
+ print_warn(f"清理旧构建元数据失败: {e}")
630
+
631
+ tag = _default_container_tag(config, tag)
632
+ registry = _default_container_registry(config, registry)
633
+
634
+ if normalized_artifact_type == "Code":
635
+ build_result, artifact_reference = await _build_code_artifact(
636
+ mcp_path=mcp_path,
637
+ mcp_name=mcp_name,
638
+ region=region,
639
+ ks3_bucket=ks3_bucket,
640
+ no_cache=no_cache,
641
+ push=push,
642
+ )
643
+ else:
644
+ build_result, artifact_reference = _build_container_artifact(
645
+ mcp_path=mcp_path,
646
+ tag=tag,
647
+ registry=registry,
648
+ no_cache=no_cache,
649
+ push=push,
650
+ )
651
+
652
+ if push:
653
+ _persist_mcp_build_metadata(
654
+ mcp_path,
655
+ build_result,
656
+ artifact_type=normalized_artifact_type,
657
+ artifact_reference=artifact_reference,
658
+ )
659
+
660
+ _print_mcp_build_summary(
661
+ artifact_type=normalized_artifact_type,
662
+ build_result=build_result,
663
+ artifact_reference=artifact_reference,
664
+ push=push,
665
+ )
666
+
667
+ return {
668
+ "framework": "mcp",
669
+ "artifact_type": normalized_artifact_type.lower(),
670
+ "artifact_source": (
671
+ "built_and_uploaded"
672
+ if normalized_artifact_type == "Code" and push
673
+ else "built_and_pushed" if normalized_artifact_type == "Container" and push
674
+ else "built"
675
+ ),
676
+ "artifact_reused": bool(build_result.metadata.get("reused", False)),
677
+ "artifact_built": True,
678
+ "artifact_reference": str(artifact_reference or ""),
679
+ "artifact_path": str(build_result.artifact_path or ""),
680
+ "image": str(build_result.metadata.get("image") or ""),
681
+ "push": bool(push),
682
+ "region": region,
683
+ "mcp_name": mcp_name,
684
+ "tools": list(detection_result.tools or []),
685
+ }
686
+
687
+
688
+ async def _deploy_mcp_async(
689
+ mcp_dir: str,
690
+ name: str | None,
691
+ region: str,
692
+ ks3_bucket: str | None,
693
+ enable_auth: bool,
694
+ dry_run: bool,
695
+ artifact_type: str,
696
+ no_cache: bool = False,
697
+ enable_public_access: bool | None = None,
698
+ enable_vpc_access: bool = False,
699
+ vpc_id: str | None = None,
700
+ subnet_id: str | None = None,
701
+ security_group_id: str | None = None,
702
+ availability_zone: str | None = None,
703
+ dry_run_context: dict[str, object] | None = None,
704
+ ):
705
+ """异步 MCP 部署流程。"""
706
+ from ksadk.api import AgentEngineClient
707
+ from ksadk.deployment.state import load_state, save_state
708
+ from ksadk.detection.mcp_detector import MCPDetector
709
+
710
+ mcp_path = Path(mcp_dir).resolve()
711
+ config = _load_mcp_config(mcp_path)
712
+ normalized_artifact_type = _normalize_artifact_type(artifact_type)
713
+ mcp_name = _normalize_mcp_name(name, mcp_path, config)
714
+ account_id = os.getenv("KSYUN_ACCOUNT_ID", "")
715
+ predicted_registry = _default_container_registry(config, None)
716
+
717
+ print_workflow_header(
718
+ title="MCP 部署",
719
+ subtitle="target: serverless",
720
+ project_dir=mcp_path,
721
+ target="serverless",
722
+ region=region,
723
+ mode_label="部署模式",
724
+ mode_value=normalized_artifact_type,
725
+ account_id=account_id or None,
726
+ )
727
+
728
+ detector = MCPDetector(str(mcp_path))
729
+ detection_result = detector.detect()
730
+ if not detection_result.is_valid:
731
+ raise validation_error(
732
+ "未检测到 FastMCP 项目。",
733
+ hints=["请确保项目包含 `from fastmcp import FastMCP`。"],
734
+ )
735
+
736
+ _print_mcp_detection(detection_result)
737
+ print_kv("部署名称", mcp_name)
738
+
739
+ artifact_plan = plan_artifact_build(
740
+ target="serverless",
741
+ artifact_type=normalized_artifact_type,
742
+ ks3_path=None,
743
+ image=None,
744
+ no_cache=no_cache,
745
+ )
746
+ if artifact_plan.should_clear_metadata:
747
+ try:
748
+ if clear_build_metadata(mcp_path):
749
+ print_warn("已清除旧构建元数据 (--no-cache)")
750
+ except Exception as e:
751
+ print_warn(f"清理旧构建元数据失败: {e}")
752
+ emit_no_cache_hint(plan=artifact_plan, no_cache=no_cache)
753
+
754
+ cached_artifact_reference = None
755
+ if not artifact_plan.should_clear_metadata:
756
+ cached_artifact_reference = load_cached_artifact_reference(mcp_path, normalized_artifact_type)
757
+
758
+ resolved_artifact_plan = resolve_artifact_build_plan(
759
+ plan=artifact_plan,
760
+ target="serverless",
761
+ artifact_type=normalized_artifact_type,
762
+ dry_run=dry_run,
763
+ deploy_name=mcp_name,
764
+ region=region,
765
+ account_id=account_id,
766
+ ks3_bucket=ks3_bucket,
767
+ registry=predicted_registry,
768
+ explicit_reference=None,
769
+ cached_reference=cached_artifact_reference,
770
+ )
771
+ if resolved_artifact_plan.reference_is_predicted:
772
+ resolved_artifact_plan = replace(
773
+ resolved_artifact_plan,
774
+ reference=_predict_mcp_artifact_reference(
775
+ artifact_type=normalized_artifact_type,
776
+ mcp_name=mcp_name,
777
+ region=region,
778
+ ks3_bucket=ks3_bucket,
779
+ registry=predicted_registry,
780
+ account_id=account_id,
781
+ ),
782
+ )
783
+
784
+ state = load_state(mcp_path)
785
+ existing_mcp_id = state.get("mcp_id") if state.get("type") == "mcp" else None
786
+
787
+ print_rule("Step 1/2 准备制品")
788
+ artifact_reference = str(resolved_artifact_plan.reference or "")
789
+
790
+ if not resolved_artifact_plan.will_build and artifact_reference:
791
+ source_label = {
792
+ "cached": "缓存制品",
793
+ "planned_build": "预测制品",
794
+ }.get(resolved_artifact_plan.source or "", "制品引用")
795
+ print_kv(source_label, artifact_reference)
796
+ if resolved_artifact_plan.source == "cached":
797
+ print_info("检测到缓存制品,跳过重新构建")
798
+ elif resolved_artifact_plan.source == "planned_build":
799
+ print_info("Dry Run: 仅生成本地构建计划,不执行真实构建/上传")
800
+
801
+ if resolved_artifact_plan.will_build:
802
+ print_rule("Step 1/2 构建与发布")
803
+ if normalized_artifact_type == "Code":
804
+ build_result, artifact_reference = await _build_code_artifact(
805
+ mcp_path=mcp_path,
806
+ mcp_name=mcp_name,
807
+ region=region,
808
+ ks3_bucket=ks3_bucket,
809
+ no_cache=no_cache,
810
+ push=True,
811
+ )
812
+ else:
813
+ build_result, artifact_reference = _build_container_artifact(
814
+ mcp_path=mcp_path,
815
+ tag=_default_container_tag(config, None),
816
+ registry=predicted_registry,
817
+ no_cache=no_cache,
818
+ push=True,
819
+ )
820
+ _persist_mcp_build_metadata(
821
+ mcp_path,
822
+ build_result,
823
+ artifact_type=normalized_artifact_type,
824
+ artifact_reference=artifact_reference,
825
+ )
826
+
827
+ local_plan = build_workflow_local_plan(
828
+ project_dir=mcp_path,
829
+ framework="mcp",
830
+ target="serverless",
831
+ region=region,
832
+ deploy_name=mcp_name,
833
+ artifact_type=normalized_artifact_type,
834
+ artifact_plan=resolved_artifact_plan,
835
+ build_dir=str(mcp_path / ".agentengine"),
836
+ artifact_reference=str(artifact_reference),
837
+ no_cache=no_cache,
838
+ )
839
+ if dry_run_context is not None:
840
+ dry_run_context["plan"] = local_plan
841
+
842
+ print_rule("Step 2/2 部署 MCP Server")
843
+ request_data = _build_mcp_request_data(
844
+ mcp_name=mcp_name,
845
+ config=config,
846
+ artifact_type=normalized_artifact_type,
847
+ artifact_reference=artifact_reference,
848
+ region=region,
849
+ enable_auth=enable_auth,
850
+ detection_result=detection_result,
851
+ )
852
+ network_payload = build_network_payload(
853
+ enable_public_access=enable_public_access,
854
+ enable_vpc_access=enable_vpc_access,
855
+ vpc_id=vpc_id,
856
+ subnet_id=subnet_id,
857
+ security_group_id=security_group_id,
858
+ availability_zone=availability_zone,
859
+ region=region,
860
+ dry_run=dry_run,
861
+ )
862
+ if network_payload:
863
+ request_data["network"] = network_payload
864
+
865
+ async with AgentEngineClient(region=region, dry_run=dry_run) as client:
866
+ if existing_mcp_id:
867
+ print_info(f"检测到本地状态: {existing_mcp_id}")
868
+ print_info("执行热更新...")
869
+ res = await client.update_mcp(existing_mcp_id, request_data)
870
+ mcp_id = existing_mcp_id
871
+ else:
872
+ res = await client.create_mcp(request_data)
873
+ if not res:
874
+ raise remote_error("Server 返回空响应,请检查 MCP 名称是否冲突或服务端日志。")
875
+ mcp_id = res.get("mcp_id")
876
+
877
+ endpoint = res.get("endpoint")
878
+
879
+ state_data = {
880
+ "type": "mcp",
881
+ "mcp_id": mcp_id,
882
+ "name": mcp_name,
883
+ "region": region,
884
+ "artifact_type": normalized_artifact_type,
885
+ "endpoint": endpoint,
886
+ "mcp_endpoint": f"{endpoint}/mcp" if endpoint else None,
887
+ "tools": list(detection_result.tools or []),
888
+ }
889
+ if res.get("api_key"):
890
+ state_data["api_key"] = res.get("api_key")
891
+
892
+ save_state(mcp_path, state_data)
893
+ print_info("已保存状态到 .agentengine.state")
894
+
895
+ print_success("MCP 部署成功")
896
+ print_kv("MCP ID", mcp_id)
897
+ if endpoint:
898
+ print_kv("Endpoint", endpoint, value_style="#58a6ff")
899
+ print_kv("MCP URL", f"{endpoint}/mcp", value_style="#58a6ff")
900
+ print_rule("调用方式")
901
+ print_info('# Cursor/Claude: {"url": "<endpoint>/mcp"}')
902
+ print_info('LangChain/LangGraph: MCPClientToolkit(url="<endpoint>/mcp")')
903
+ print_info('ADK: MCPToolset.from_server(connection_params={"url": "<endpoint>/mcp"})')
904
+
905
+ return {
906
+ "framework": "mcp",
907
+ "artifact_type": normalized_artifact_type.lower(),
908
+ "artifact_source": str(resolved_artifact_plan.source or ""),
909
+ "artifact_reused": bool((resolved_artifact_plan.source or "") == "cached"),
910
+ "artifact_built": bool(resolved_artifact_plan.will_build),
911
+ "artifact_reference": str(artifact_reference or ""),
912
+ "mcp_id": str(mcp_id or ""),
913
+ "mcp_name": str(mcp_name),
914
+ "endpoint": str(endpoint or ""),
915
+ "mcp_url": str(f"{endpoint}/mcp" if endpoint else ""),
916
+ "api_key_present": bool(res.get("api_key")),
917
+ "status": "DEPLOYED",
918
+ "region": region,
919
+ "tools": list(detection_result.tools or []),
920
+ }
921
+
922
+
923
+ @mcp.command("list", context_settings=CONTEXT_SETTINGS)
924
+ @region_option()
925
+ @pagination_options(default_page=1, default_size=20)
926
+ @dry_run_option()
927
+ @cli_output_option()
928
+ def list_mcps(region: str, page: int, size: int, dry_run: bool, output_mode: str | None):
929
+ """列出已部署的 MCP"""
930
+ _ = output_mode
931
+ dry_run = effective_dry_run(dry_run)
932
+ from ksadk.api import AgentEngineClient
933
+
934
+ async def _list():
935
+ async with AgentEngineClient(region=region, dry_run=dry_run) as client:
936
+ resp = await client.list_mcps(region=region, page=page, page_size=size)
937
+ mcps = resp.get("mcps", [])
938
+ total = int(resp.get("total", len(mcps)) or 0)
939
+
940
+ rows = []
941
+ items = []
942
+ for m in mcps:
943
+ status = (m.get("status") or "UNKNOWN").upper()
944
+ rows.append(
945
+ (
946
+ str(m.get("mcp_id", "-")),
947
+ str(m.get("name", "-")),
948
+ f"[{status_rich_style(status)}]{status}[/]",
949
+ str(m.get("mcp_endpoint", "N/A")),
950
+ )
951
+ )
952
+ items.append(
953
+ {
954
+ "id": str(m.get("mcp_id", "-")),
955
+ "name": str(m.get("name", "-")),
956
+ "status": status,
957
+ "mcp_url": str(m.get("mcp_endpoint", "N/A")),
958
+ }
959
+ )
960
+
961
+ if not render_descriptor_list(
962
+ MCP_RESOURCE,
963
+ rows=rows,
964
+ total=total,
965
+ page=page,
966
+ size=size,
967
+ items=items,
968
+ ):
969
+ return
970
+
971
+ try:
972
+ run_async_with_dry_run(
973
+ _list(),
974
+ dry_run=dry_run,
975
+ dry_run_resource="mcp",
976
+ dry_run_action="list",
977
+ )
978
+ except Exception as e:
979
+ _abort_mcp_error(e, context="获取列表失败", argv=["mcp", "list"])
980
+
981
+
982
+ @mcp.command("status", context_settings=CONTEXT_SETTINGS)
983
+ @click.argument("mcp_ref", required=False)
984
+ @region_option(default=None, envvar=None, help_text="区域 (默认优先读取 .agentengine.state)")
985
+ @dry_run_option()
986
+ @cli_output_option()
987
+ def status(mcp_ref: str | None, region: str | None, dry_run: bool, output_mode: str | None):
988
+ """查看 MCP 状态
989
+
990
+ MCP_ID: MCP 的 ID
991
+ """
992
+ _ = output_mode
993
+ dry_run = effective_dry_run(dry_run)
994
+ from ksadk.api import AgentEngineClient
995
+ from ksadk.deployment.state import load_state
996
+
997
+ cwd = Path(".").resolve()
998
+ state = load_state(cwd)
999
+ region = region or state.get("region") or os.getenv("KSYUN_REGION") or "cn-beijing-6"
1000
+ resolved = resolve_mcp_ref(mcp_ref, cwd=cwd, include_state=True)
1001
+ if not resolved:
1002
+ _abort_mcp_error(
1003
+ resolution_error(
1004
+ MCP_RESOURCE.missing_ref_message or "请指定 MCP。",
1005
+ hints=list(MCP_RESOURCE.resolution_commands),
1006
+ ),
1007
+ argv=["mcp", "status"],
1008
+ )
1009
+ return
1010
+ target_ref = resolved.value
1011
+ if resolved.source != "cli":
1012
+ print_info(f"未显式指定 MCP,使用 {resolved.source_text}: {target_ref}")
1013
+
1014
+ async def _get():
1015
+ async with AgentEngineClient(region=region, dry_run=dry_run) as client:
1016
+ mcp = None
1017
+ try:
1018
+ mcp = await client.get_mcp(target_ref)
1019
+ except DryRunExit:
1020
+ raise
1021
+ except Exception:
1022
+ mcp = await client.get_mcp_by_name(target_ref, region=region)
1023
+ if not mcp:
1024
+ raise resolution_error(f"未找到 MCP: {target_ref}", hints=["agentengine mcp list"])
1025
+
1026
+ status_text = (mcp.get("status") or "UNKNOWN").upper()
1027
+ fields = [
1028
+ ("ID", str(mcp.get("mcp_id", "-")), None),
1029
+ ("状态", status_text, status_rich_style(status_text)),
1030
+ ("区域", str(mcp.get("region", region)), None),
1031
+ ("Endpoint", str(mcp.get("endpoint", "N/A")), "#58a6ff"),
1032
+ ("MCP URL", str(mcp.get("mcp_endpoint", "N/A")), "#58a6ff"),
1033
+ ("认证", "已开启" if mcp.get("enable_auth") else "未开启", None),
1034
+ ]
1035
+ if mcp.get('tools'):
1036
+ fields.append(("工具", ", ".join(mcp["tools"]), None))
1037
+ fields.extend(
1038
+ [
1039
+ ("创建时间", str(mcp.get("created_at")), None),
1040
+ ("更新时间", str(mcp.get("updated_at")), None),
1041
+ ]
1042
+ )
1043
+ render_descriptor_status(
1044
+ MCP_RESOURCE,
1045
+ subtitle=str(mcp.get("name", target_ref)),
1046
+ fields=fields,
1047
+ item={
1048
+ "id": str(mcp.get("mcp_id", "-")),
1049
+ "name": str(mcp.get("name", target_ref)),
1050
+ "status": status_text,
1051
+ "region": str(mcp.get("region", region)),
1052
+ "endpoint": str(mcp.get("endpoint", "N/A")),
1053
+ "mcp_url": str(mcp.get("mcp_endpoint", "N/A")),
1054
+ "auth_enabled": bool(mcp.get("enable_auth")),
1055
+ "tools": list(mcp.get("tools") or []),
1056
+ "created_at": str(mcp.get("created_at")),
1057
+ "updated_at": str(mcp.get("updated_at")),
1058
+ },
1059
+ )
1060
+
1061
+ try:
1062
+ run_async_with_dry_run(
1063
+ _get(),
1064
+ dry_run=dry_run,
1065
+ dry_run_resource="mcp",
1066
+ dry_run_action="status",
1067
+ )
1068
+ except Exception as e:
1069
+ _abort_mcp_error(e, context="获取状态失败", argv=["mcp", "status"])
1070
+
1071
+
1072
+ def _delete_impl(mcp_ids: tuple[str, ...], region: str, assume_yes: bool, dry_run: bool):
1073
+ """删除 MCP。
1074
+
1075
+ MCP_ID: 要删除的 MCP ID
1076
+ """
1077
+ dry_run = effective_dry_run(dry_run)
1078
+ from ksadk.api import AgentEngineClient
1079
+
1080
+ if not confirm_destructive(
1081
+ assume_yes=assume_yes,
1082
+ dry_run=dry_run,
1083
+ prompt=f"确定要删除这 {len(mcp_ids)} 个 MCP 吗?",
1084
+ ):
1085
+ return
1086
+
1087
+ async def _delete():
1088
+ async with AgentEngineClient(region=region, dry_run=dry_run) as client:
1089
+ failed_ids: list[str] = []
1090
+ deleted_ids: list[str] = []
1091
+ for mcp_id in mcp_ids:
1092
+ success = await client.delete_mcp(mcp_id)
1093
+ if success:
1094
+ deleted_ids.append(mcp_id)
1095
+ print_success(f"MCP 已删除: {mcp_id}")
1096
+
1097
+ # 尝试清理本地状态文件 (如果在项目目录中)
1098
+ from ksadk.deployment.state import clear_state
1099
+ try:
1100
+ removed = clear_state(Path("."), key=mcp_id)
1101
+ if removed:
1102
+ print_info("本地状态文件已清理")
1103
+ else:
1104
+ print_warn("未清理本地状态文件: 当前目录状态与目标 ID 不匹配")
1105
+ except Exception:
1106
+ pass
1107
+ else:
1108
+ failed_ids.append(mcp_id)
1109
+
1110
+ if failed_ids:
1111
+ raise remote_error(
1112
+ f"以下 MCP 删除失败: {', '.join(failed_ids)}",
1113
+ details={"deleted": deleted_ids, "failed": failed_ids},
1114
+ )
1115
+ return {
1116
+ "targets": list(mcp_ids),
1117
+ "deleted": deleted_ids,
1118
+ "failed": failed_ids,
1119
+ }
1120
+
1121
+ dry_run_kwargs = {"dry_run": dry_run}
1122
+ if is_json_output():
1123
+ dry_run_kwargs.update(
1124
+ dry_run_resource="mcp",
1125
+ dry_run_action="delete",
1126
+ )
1127
+ try:
1128
+ result = run_async_with_dry_run(_delete(), **dry_run_kwargs)
1129
+ except Exception as e:
1130
+ _abort_mcp_error(e, context="删除失败", argv=["mcp", "delete"])
1131
+ return
1132
+ if result is not None:
1133
+ deleted_text = ", ".join(result["deleted"]) or "-"
1134
+ failed_text = ", ".join(result["failed"]) or "-"
1135
+ render_descriptor_status(
1136
+ MCP_RESOURCE,
1137
+ title="MCP 删除结果",
1138
+ subtitle=", ".join(result["targets"]) if result["targets"] else "-",
1139
+ fields=[
1140
+ ("目标数量", str(len(result["targets"])), None),
1141
+ ("已删除", deleted_text, "ok" if result["deleted"] else "muted"),
1142
+ ("失败", failed_text, "err" if result["failed"] else "muted"),
1143
+ ],
1144
+ next_steps=(
1145
+ "agentengine mcp list",
1146
+ "agentengine mcp deploy",
1147
+ ),
1148
+ action="delete",
1149
+ item=result,
1150
+ )
1151
+
1152
+
1153
+ @mcp.command("delete", context_settings=CONTEXT_SETTINGS)
1154
+ @click.argument("mcp_ids", nargs=-1, required=True)
1155
+ @region_option()
1156
+ @confirm_options()
1157
+ @dry_run_option()
1158
+ @cli_output_option()
1159
+ def delete(mcp_ids: tuple[str, ...], region: str, assume_yes: bool, dry_run: bool, output_mode: str | None):
1160
+ """删除 MCP。"""
1161
+ _ = output_mode
1162
+ _delete_impl(mcp_ids=mcp_ids, region=region, assume_yes=assume_yes, dry_run=dry_run)
1163
+
1164
+
1165
+ @mcp.command("destroy", context_settings=CONTEXT_SETTINGS, hidden=True)
1166
+ @click.argument("mcp_ids", nargs=-1, required=True)
1167
+ @region_option()
1168
+ @confirm_options()
1169
+ @dry_run_option()
1170
+ @cli_output_option()
1171
+ def destroy(mcp_ids: tuple[str, ...], region: str, assume_yes: bool, dry_run: bool, output_mode: str | None):
1172
+ """删除 MCP。"""
1173
+ _ = output_mode
1174
+ _delete_impl(mcp_ids=mcp_ids, region=region, assume_yes=assume_yes, dry_run=dry_run)