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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (371) hide show
  1. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/METADATA +36 -20
  2. agentengine_sdk_python-0.8.0.dist-info/RECORD +578 -0
  3. ksadk/a2a/__init__.py +178 -11
  4. ksadk/a2a/bootstrap.py +334 -0
  5. ksadk/a2a/card.py +120 -0
  6. ksadk/a2a/context_store.py +203 -0
  7. ksadk/a2a/control_plane.py +818 -0
  8. ksadk/a2a/credential.py +99 -0
  9. ksadk/a2a/event_adapter.py +149 -0
  10. ksadk/a2a/executor.py +406 -89
  11. ksadk/a2a/external_transport.py +516 -0
  12. ksadk/a2a/identity.py +304 -0
  13. ksadk/a2a/ids.py +22 -0
  14. ksadk/a2a/langgraph.py +285 -0
  15. ksadk/a2a/resume_store.py +201 -0
  16. ksadk/a2a/routes.py +105 -0
  17. ksadk/a2a/server.py +107 -60
  18. ksadk/a2a/space_client.py +1101 -0
  19. ksadk/a2a/task_adapter.py +423 -0
  20. ksadk/a2a/task_event_dispatcher.py +167 -0
  21. ksadk/a2a/task_event_outbox.py +326 -0
  22. ksadk/a2a/task_store.py +206 -0
  23. ksadk/a2ui/__init__.py +27 -0
  24. ksadk/a2ui/core.py +186 -0
  25. ksadk/a2ui/models.py +166 -0
  26. ksadk/a2ui/renderer.py +198 -0
  27. ksadk/agui/__init__.py +9 -0
  28. ksadk/agui/a2ui_projection.py +92 -0
  29. ksadk/agui/agent.py +857 -0
  30. ksadk/agui/config.py +86 -0
  31. ksadk/agui/routes.py +55 -0
  32. ksadk/api/client.py +233 -191
  33. ksadk/builders/__init__.py +2 -0
  34. ksadk/builders/base.py +16 -14
  35. ksadk/builders/code_builder.py +318 -236
  36. ksadk/builders/container_builder.py +187 -167
  37. ksadk/builders/framework_requirements.py +29 -11
  38. ksadk/builders/ks3_uploader.py +58 -27
  39. ksadk/builders/managed_runtime_builder.py +145 -0
  40. ksadk/builders/mcp_builder.py +91 -92
  41. ksadk/builders/requirements_utils.py +1 -5
  42. ksadk/cli/__init__.py +89 -171
  43. ksadk/cli/cmd_a2a.py +254 -70
  44. ksadk/cli/cmd_agent.py +19 -5
  45. ksadk/cli/cmd_build.py +158 -29
  46. ksadk/cli/cmd_completion.py +47 -35
  47. ksadk/cli/cmd_config.py +267 -198
  48. ksadk/cli/cmd_create.py +500 -720
  49. ksadk/cli/cmd_dashboard.py +120 -45
  50. ksadk/cli/cmd_deploy.py +117 -58
  51. ksadk/cli/cmd_destroy.py +44 -14
  52. ksadk/cli/cmd_files.py +63 -24
  53. ksadk/cli/cmd_hermes.py +168 -89
  54. ksadk/cli/cmd_invoke.py +184 -122
  55. ksadk/cli/cmd_launch.py +64 -28
  56. ksadk/cli/cmd_mcp.py +98 -64
  57. ksadk/cli/cmd_model.py +14 -5
  58. ksadk/cli/cmd_openclaw.py +483 -227
  59. ksadk/cli/cmd_replay.py +71 -0
  60. ksadk/cli/cmd_run.py +33 -10
  61. ksadk/cli/cmd_status.py +80 -31
  62. ksadk/cli/cmd_version.py +20 -13
  63. ksadk/cli/cmd_web.py +89 -13
  64. ksadk/cli/deploy_utils.py +20 -20
  65. ksadk/cli/dry_run.py +5 -3
  66. ksadk/cli/error_utils.py +37 -12
  67. ksadk/cli/global_options.py +1 -2
  68. ksadk/cli/local_runtime.py +1 -2
  69. ksadk/cli/model_catalog.py +6 -2
  70. ksadk/cli/network_options.py +34 -14
  71. ksadk/cli/resource_common.py +6 -2
  72. ksadk/cli/storage.py +0 -1
  73. ksadk/cli/ui.py +5 -3
  74. ksadk/cli/workflow_common.py +51 -17
  75. ksadk/codex/__init__.py +12 -0
  76. ksadk/codex/client.py +408 -0
  77. ksadk/codex/phase.py +143 -0
  78. ksadk/codex/runtime.py +449 -0
  79. ksadk/common/aicp_env.py +0 -1
  80. ksadk/common/auth.py +2 -2
  81. ksadk/common/constants.py +1 -3
  82. ksadk/common/llm_utils.py +17 -13
  83. ksadk/compat/__init__.py +5 -0
  84. ksadk/compat/adk_compat.py +200 -0
  85. ksadk/compat/copilotkit_a2ui.py +330 -0
  86. ksadk/configs/__init__.py +12 -12
  87. ksadk/configs/env_registry.py +500 -100
  88. ksadk/configs/global_config.py +2 -1
  89. ksadk/configs/settings.py +151 -124
  90. ksadk/conversations/__init__.py +7 -5
  91. ksadk/conversations/attachment_storage.py +16 -11
  92. ksadk/conversations/attachments.py +44 -36
  93. ksadk/conversations/compaction_pipeline.py +12 -12
  94. ksadk/conversations/compaction_prompt.py +9 -5
  95. ksadk/conversations/context.py +221 -6
  96. ksadk/conversations/message_projection.py +438 -51
  97. ksadk/conversations/model_context.py +12 -6
  98. ksadk/conversations/model_options.py +0 -1
  99. ksadk/conversations/normalize.py +20 -16
  100. ksadk/conversations/reasoning_markup.py +1 -1
  101. ksadk/conversations/runtime.py +339 -5255
  102. ksadk/conversations/runtime_compaction.py +333 -0
  103. ksadk/conversations/runtime_constants.py +27 -0
  104. ksadk/conversations/runtime_governance.py +185 -0
  105. ksadk/conversations/runtime_input.py +652 -0
  106. ksadk/conversations/runtime_invocation.py +395 -0
  107. ksadk/conversations/runtime_metadata.py +475 -0
  108. ksadk/conversations/runtime_observability.py +355 -0
  109. ksadk/conversations/runtime_payloads.py +272 -0
  110. ksadk/conversations/runtime_persistence.py +440 -0
  111. ksadk/conversations/runtime_preparation.py +418 -0
  112. ksadk/conversations/runtime_resume.py +816 -0
  113. ksadk/conversations/runtime_stream_events.py +902 -0
  114. ksadk/conversations/runtime_streaming.py +547 -0
  115. ksadk/conversations/semantic_summary.py +17 -5
  116. ksadk/conversations/session_title.py +6 -3
  117. ksadk/deployment/__init__.py +15 -16
  118. ksadk/deployment/agent_access.py +12 -23
  119. ksadk/deployment/base.py +51 -38
  120. ksadk/deployment/manager.py +63 -65
  121. ksadk/deployment/providers/serverless.py +309 -202
  122. ksadk/deployment/registry.py +38 -32
  123. ksadk/deployment/state.py +11 -11
  124. ksadk/deployment/ui_config.py +1 -1
  125. ksadk/detection/__init__.py +1 -1
  126. ksadk/detection/detector.py +146 -83
  127. ksadk/detection/mcp_detector.py +9 -6
  128. ksadk/events/__init__.py +25 -0
  129. ksadk/events/parser.py +191 -0
  130. ksadk/events/replay.py +37 -0
  131. ksadk/events/runtime_event.py +264 -0
  132. ksadk/events/store.py +317 -0
  133. ksadk/harness/__init__.py +34 -0
  134. ksadk/harness/app.py +278 -0
  135. ksadk/harness/config.py +181 -0
  136. ksadk/harness/reasoner.py +105 -0
  137. ksadk/harness/runner.py +211 -0
  138. ksadk/harness/sandbox.py +141 -0
  139. ksadk/harness/tools.py +222 -0
  140. ksadk/hermes_terminal.py +23 -12
  141. ksadk/identity/resolver.py +15 -9
  142. ksadk/ids.py +32 -0
  143. ksadk/knowledge_base/adk_tool.py +1 -1
  144. ksadk/knowledge_base/client.py +23 -29
  145. ksadk/managed_runtime.py +188 -0
  146. ksadk/markdown.py +5 -2
  147. ksadk/mcp_runtime/__init__.py +9 -6
  148. ksadk/memory/__init__.py +1 -1
  149. ksadk/memory/adk/__init__.py +2 -0
  150. ksadk/memory/adk/backends/base_ltm_backend.py +2 -6
  151. ksadk/memory/adk/backends/http_ltm_backend.py +13 -21
  152. ksadk/memory/adk/backends/inmemory_ltm_backend.py +7 -13
  153. ksadk/memory/adk/backends/sdk_ltm_backend.py +26 -33
  154. ksadk/memory/adk/long_term_memory.py +31 -35
  155. ksadk/memory/adk/resilient_session_service.py +4 -5
  156. ksadk/memory/adk/short_term_memory.py +12 -21
  157. ksadk/memory/adk_tool.py +3 -2
  158. ksadk/memory/backends/base.py +19 -19
  159. ksadk/memory/backends/memory.py +24 -25
  160. ksadk/memory/backends/redis.py +31 -30
  161. ksadk/memory/langchain_tool.py +2 -1
  162. ksadk/memory/manager.py +52 -47
  163. ksadk/memory/service.py +10 -8
  164. ksadk/model_policy.py +15 -7
  165. ksadk/model_proxy/__init__.py +51 -0
  166. ksadk/model_proxy/bootstrap.py +80 -0
  167. ksadk/model_proxy/cache.py +165 -0
  168. ksadk/model_proxy/config.py +45 -0
  169. ksadk/model_proxy/demo_webui.py +115 -0
  170. ksadk/model_proxy/detect.py +145 -0
  171. ksadk/model_proxy/gate.py +68 -0
  172. ksadk/model_proxy/namespace.py +173 -0
  173. ksadk/model_proxy/protocol_proxy.py +22 -0
  174. ksadk/model_proxy/server.py +300 -0
  175. ksadk/model_proxy/transform.py +691 -0
  176. ksadk/openclaw_gateway.py +29 -14
  177. ksadk/runners/adk_runner.py +345 -120
  178. ksadk/runners/base_runner.py +46 -29
  179. ksadk/runners/codex_runner.py +132 -0
  180. ksadk/runners/deepagents_runner.py +0 -1
  181. ksadk/runners/factory.py +17 -5
  182. ksadk/runners/langchain_runner.py +29 -742
  183. ksadk/runners/langgraph_runner.py +352 -90
  184. ksadk/runners/patch_langchain.py +16 -16
  185. ksadk/runners/remote_runner.py +134 -33
  186. ksadk/runners/usage_accumulator.py +1 -0
  187. ksadk/runners/utils/langfuse.py +3 -3
  188. ksadk/runners/utils/loader.py +7 -7
  189. ksadk/runtime/__init__.py +41 -0
  190. ksadk/runtime/adapter.py +345 -0
  191. ksadk/runtime/framework_adapters.py +124 -0
  192. ksadk/runtime/preprocessing.py +118 -0
  193. ksadk/runtime/runner_adapter.py +873 -0
  194. ksadk/runtime_context.py +18 -3
  195. ksadk/runtime_state.py +0 -1
  196. ksadk/sandbox/__init__.py +4 -1
  197. ksadk/sandbox/backends/__init__.py +4 -1
  198. ksadk/sandbox/backends/e2b.py +13 -5
  199. ksadk/sandbox/backends/local_process.py +11 -3
  200. ksadk/sandbox/base.py +10 -15
  201. ksadk/sandbox/factory.py +14 -4
  202. ksadk/sandbox/registry.py +57 -6
  203. ksadk/server/api_models.py +15 -5
  204. ksadk/server/app.py +455 -3885
  205. ksadk/server/composition.py +21 -0
  206. ksadk/server/factory.py +624 -0
  207. ksadk/server/routes/__init__.py +1 -0
  208. ksadk/server/routes/checkpoint_resolution.py +116 -0
  209. ksadk/server/routes/common.py +713 -0
  210. ksadk/server/routes/control.py +327 -0
  211. ksadk/server/routes/dependencies.py +98 -0
  212. ksadk/server/routes/misc.py +448 -0
  213. ksadk/server/routes/models.py +443 -0
  214. ksadk/server/routes/openai_compat.py +207 -0
  215. ksadk/server/routes/projection.py +795 -0
  216. ksadk/server/routes/routers.py +52 -0
  217. ksadk/server/routes/run.py +726 -0
  218. ksadk/server/routes/sessions.py +649 -0
  219. ksadk/server/routes/streaming.py +223 -0
  220. ksadk/server/routes/workspace.py +381 -0
  221. ksadk/server/static/assets/{ArtifactsPanel-D-SSn2ee.js → ArtifactsPanel-Cjnqt-8W.js} +1 -1
  222. ksadk/server/static/assets/CodeBlock-BqyqZfuB.js +9 -0
  223. ksadk/server/static/assets/MathMessageMarkdown-BpH7jiFM.js +8 -0
  224. ksadk/server/static/assets/MermaidBlock-DWuxETaJ.js +303 -0
  225. ksadk/server/static/assets/NativeTerminalPanel-MDTopWMO.js +1 -0
  226. ksadk/server/static/assets/{arc-BA13sHc9.js → arc-CFKwSk_B.js} +1 -1
  227. ksadk/server/static/assets/architecture-7EHR7CIX-CynqOWjZ.js +1 -0
  228. ksadk/server/static/assets/{architectureDiagram-3BPJPVTR-DzJzgVoL.js → architectureDiagram-3BPJPVTR-Dej8jX8c.js} +1 -1
  229. ksadk/server/static/assets/{blockDiagram-GPEHLZMM-UTdVcZhn.js → blockDiagram-GPEHLZMM-1F64jqvy.js} +1 -1
  230. ksadk/server/static/assets/{c4Diagram-AAUBKEIU-Dix0GD4m.js → c4Diagram-AAUBKEIU-9q7AUAKb.js} +1 -1
  231. ksadk/server/static/assets/channel-iUGv2N24.js +1 -0
  232. ksadk/server/static/assets/{chunk-2J33WTMH-C2JxuZ42.js → chunk-2J33WTMH-6qgwJm7Q.js} +1 -1
  233. ksadk/server/static/assets/{chunk-4BX2VUAB-Be57QPgD.js → chunk-4BX2VUAB-CsWIQRhc.js} +1 -1
  234. ksadk/server/static/assets/{chunk-55IACEB6-WjSuy4nv.js → chunk-55IACEB6-BK8paA20.js} +1 -1
  235. ksadk/server/static/assets/{chunk-727SXJPM-BOovP-b5.js → chunk-727SXJPM-B-JEhy7h.js} +1 -1
  236. ksadk/server/static/assets/{chunk-AQP2D5EJ-DOmZNmWj.js → chunk-AQP2D5EJ-DYBvMHAa.js} +1 -1
  237. ksadk/server/static/assets/{chunk-FMBD7UC4-DzwlodkU.js → chunk-FMBD7UC4-BGhvzDYt.js} +1 -1
  238. ksadk/server/static/assets/{chunk-ND2GUHAM-DMqAikEU.js → chunk-ND2GUHAM-D98vPd-E.js} +1 -1
  239. ksadk/server/static/assets/chunk-QZHKN3VN-YQIEXeF6.js +1 -0
  240. ksadk/server/static/assets/classDiagram-4FO5ZUOK-CDAUuoXK.js +1 -0
  241. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-CDAUuoXK.js +1 -0
  242. ksadk/server/static/assets/{cose-bilkent-S5V4N54A-Zhy2GBnP.js → cose-bilkent-S5V4N54A-CX3yotHq.js} +1 -1
  243. ksadk/server/static/assets/{dagre-BM42HDAG-CbKrtIUz.js → dagre-BM42HDAG-C7TguAWo.js} +1 -1
  244. ksadk/server/static/assets/{diagram-2AECGRRQ-BRApgQRK.js → diagram-2AECGRRQ-Dd17_kws.js} +1 -1
  245. ksadk/server/static/assets/{diagram-5GNKFQAL-D0xbnDiK.js → diagram-5GNKFQAL-DVIClIil.js} +1 -1
  246. ksadk/server/static/assets/{diagram-KO2AKTUF-CVugVI9L.js → diagram-KO2AKTUF-Df_3gYQa.js} +1 -1
  247. ksadk/server/static/assets/{diagram-LMA3HP47-DozUGgee.js → diagram-LMA3HP47-BhLk6ZtA.js} +1 -1
  248. ksadk/server/static/assets/{diagram-OG6HWLK6-ZOYsKlru.js → diagram-OG6HWLK6-D4GNGvuu.js} +1 -1
  249. ksadk/server/static/assets/{dist-DmFaq_Iy.js → dist-6CVKuTAe.js} +1 -1
  250. ksadk/server/static/assets/{dist-8EEyGgDx.js → dist-BUHRxvDG.js} +1 -1
  251. ksadk/server/static/assets/{dist-B0NP_Z0z.js → dist-BZ9n9AjO.js} +1 -1
  252. ksadk/server/static/assets/{dist-DMezvBGJ.js → dist-BibcG1V9.js} +1 -1
  253. ksadk/server/static/assets/{dist-C3HIIaN5.js → dist-Bs-jQcRX.js} +1 -1
  254. ksadk/server/static/assets/{dist-BrCcQ47T.js → dist-C2xjE7cO.js} +1 -1
  255. ksadk/server/static/assets/{dist-Dp0k7bWI.js → dist-C7-3jInC.js} +1 -1
  256. ksadk/server/static/assets/{dist-D-xOD048.js → dist-C99THtIA.js} +1 -1
  257. ksadk/server/static/assets/{dist-CkEKJFtk.js → dist-CGcp2ex8.js} +1 -1
  258. ksadk/server/static/assets/{dist-DyOkZmze.js → dist-CVQRZjPu.js} +1 -1
  259. ksadk/server/static/assets/{dist-BssVmjIo.js → dist-Cf23NY4L.js} +1 -1
  260. ksadk/server/static/assets/{dist-BIJVDMuB.js → dist-CgF3fj15.js} +1 -1
  261. ksadk/server/static/assets/{dist-2hInLS_J.js → dist-Cwt7koer.js} +1 -1
  262. ksadk/server/static/assets/{dist-DyWsb78Q.js → dist-D82mtD2s.js} +1 -1
  263. ksadk/server/static/assets/{dist-D-JMdWPQ.js → dist-DF06ORQo.js} +1 -1
  264. ksadk/server/static/assets/{dist-BmlMPsCc.js → dist-DHn6nBzr.js} +1 -1
  265. ksadk/server/static/assets/{dist-gX6GOLKq.js → dist-Djgl2wVZ.js} +1 -1
  266. ksadk/server/static/assets/{dist-DpKtt4Bo.js → dist-DlzCRy0S.js} +1 -1
  267. ksadk/server/static/assets/{dist-8_SfK1IP.js → dist-DqNnNFrw.js} +1 -1
  268. ksadk/server/static/assets/{dist-D57wnGWd.js → dist-DyvYLMW9.js} +1 -1
  269. ksadk/server/static/assets/{dist-CPBtqRTW.js → dist-eoW6tZXA.js} +1 -1
  270. ksadk/server/static/assets/{dist-DL_NKc_z.js → dist-ivOya1LD.js} +1 -1
  271. ksadk/server/static/assets/{erDiagram-TEJ5UH35-Bk-9bgE5.js → erDiagram-TEJ5UH35-CnfRcY2M.js} +1 -1
  272. ksadk/server/static/assets/eventmodeling-FCH6USID-ChYO-ijM.js +1 -0
  273. ksadk/server/static/assets/{flowDiagram-I6XJVG4X-Dn9kZVuZ.js → flowDiagram-I6XJVG4X-DGaJjGNJ.js} +1 -1
  274. ksadk/server/static/assets/{ganttDiagram-6RSMTGT7-BGxXlJqm.js → ganttDiagram-6RSMTGT7-DpCoB2g9.js} +1 -1
  275. ksadk/server/static/assets/gitGraph-WXDBUCRP-BN_0Fk-j.js +1 -0
  276. ksadk/server/static/assets/{gitGraphDiagram-PVQCEYII-C7Q0X-wi.js → gitGraphDiagram-PVQCEYII-9IKVFBVT.js} +1 -1
  277. ksadk/server/static/assets/index-QSwCHuB8.js +177 -0
  278. ksadk/server/static/assets/index-jOPmTOZH.css +2 -0
  279. ksadk/server/static/assets/info-J43DQDTF-Cp6o3vId.js +1 -0
  280. ksadk/server/static/assets/{infoDiagram-5YYISTIA-BO_CSqq5.js → infoDiagram-5YYISTIA-CYIIsb8y.js} +1 -1
  281. ksadk/server/static/assets/{ishikawaDiagram-YF4QCWOH-eYLPLd46.js → ishikawaDiagram-YF4QCWOH-DLOHGvWw.js} +1 -1
  282. ksadk/server/static/assets/{journeyDiagram-JHISSGLW-De9geSb0.js → journeyDiagram-JHISSGLW-BIzKeejT.js} +1 -1
  283. ksadk/server/static/assets/{kanban-definition-UN3LZRKU-Cs80kQto.js → kanban-definition-UN3LZRKU-BWHoFSw2.js} +1 -1
  284. ksadk/server/static/assets/{katex-DSrCFD8n.js → katex-DATssjp1.js} +1 -1
  285. ksadk/server/static/assets/{linear-CN9sbKTF.js → linear-CvMBw9cA.js} +1 -1
  286. ksadk/server/static/assets/{mermaid-parser.core-DlgSBU8l.js → mermaid-parser.core-mGAcEwcq.js} +2 -2
  287. ksadk/server/static/assets/{mindmap-definition-RKZ34NQL-9afz7Oug.js → mindmap-definition-RKZ34NQL-CSAQxEAe.js} +1 -1
  288. ksadk/server/static/assets/packet-YPE3B663-wQzct3cT.js +1 -0
  289. ksadk/server/static/assets/pie-LRSECV5Y-BgTQiv-9.js +1 -0
  290. ksadk/server/static/assets/{pieDiagram-4H26LBE5-DPv_VstN.js → pieDiagram-4H26LBE5-By-ra07M.js} +1 -1
  291. ksadk/server/static/assets/{quadrantDiagram-W4KKPZXB-o77wZ1XK.js → quadrantDiagram-W4KKPZXB-CxIR4JXI.js} +1 -1
  292. ksadk/server/static/assets/radar-GUYGQ44K-BIq5fXsn.js +1 -0
  293. ksadk/server/static/assets/{requirementDiagram-4Y6WPE33-BYVw81VC.js → requirementDiagram-4Y6WPE33-DpW90iu3.js} +1 -1
  294. ksadk/server/static/assets/{sankeyDiagram-5OEKKPKP-B7nZFMKT.js → sankeyDiagram-5OEKKPKP-DpGa6EAV.js} +1 -1
  295. ksadk/server/static/assets/{sequenceDiagram-3UESZ5HK-BGRRrFw5.js → sequenceDiagram-3UESZ5HK-NTKNGGe5.js} +1 -1
  296. ksadk/server/static/assets/{stateDiagram-AJRCARHV-BUfHCoPs.js → stateDiagram-AJRCARHV-DGpd9yFG.js} +1 -1
  297. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-B3o579IQ.js +1 -0
  298. ksadk/server/static/assets/{timeline-definition-PNZ67QCA-FbCTGrf9.js → timeline-definition-PNZ67QCA-jqoYs3jQ.js} +1 -1
  299. ksadk/server/static/assets/treeView-BLDUP644-Dqi-E0EM.js +1 -0
  300. ksadk/server/static/assets/treemap-LRROVOQU-ClQP9CJ9.js +1 -0
  301. ksadk/server/static/assets/{vennDiagram-CIIHVFJN-DWgwtPsJ.js → vennDiagram-CIIHVFJN-l3Z7-wbP.js} +1 -1
  302. ksadk/server/static/assets/wardley-L42UT6IY-8XLvnNIs.js +1 -0
  303. ksadk/server/static/assets/{wardleyDiagram-YWT4CUSO-2x8G-tTM.js → wardleyDiagram-YWT4CUSO-BR54GPmr.js} +1 -1
  304. ksadk/server/static/assets/{xychartDiagram-2RQKCTM6-Drma3AYl.js → xychartDiagram-2RQKCTM6-SkiH8GsK.js} +1 -1
  305. ksadk/server/static/index.html +2 -2
  306. ksadk/server/terminal_sessions.py +111 -58
  307. ksadk/sessions/__init__.py +69 -19
  308. ksadk/sessions/base.py +31 -11
  309. ksadk/sessions/continuity.py +2 -3
  310. ksadk/sessions/in_memory.py +46 -2
  311. ksadk/sessions/local_service.py +148 -17
  312. ksadk/sessions/postgres_service.py +143 -25
  313. ksadk/sessions/resilient.py +36 -8
  314. ksadk/skills/models.py +17 -5
  315. ksadk/skills/package_store.py +5 -2
  316. ksadk/skills/runtime/agent.py +20 -5
  317. ksadk/skills/runtime/artifacts.py +1 -5
  318. ksadk/skills/runtime/backends/e2b.py +10 -4
  319. ksadk/skills/runtime/backends/local.py +15 -3
  320. ksadk/skills/runtime/base.py +1 -2
  321. ksadk/skills/runtime/executor.py +10 -3
  322. ksadk/skills/runtime/factory.py +4 -2
  323. ksadk/skills/runtime/loader.py +1 -2
  324. ksadk/skills/runtime/registry.py +15 -10
  325. ksadk/skills/runtime/request.py +3 -1
  326. ksadk/skills/service_client.py +38 -17
  327. ksadk/skills/tool_defs.py +15 -10
  328. ksadk/terminal_exec_policy.py +3 -4
  329. ksadk/tools/gateway.py +92 -15
  330. ksadk/tools/result_budget.py +12 -4
  331. ksadk/toolsets/__init__.py +134 -36
  332. ksadk/toolsets/platform.py +21 -5
  333. ksadk/toolsets/sandbox.py +82 -16
  334. ksadk/toolsets/skills.py +200 -39
  335. ksadk/toolsets/web.py +123 -26
  336. ksadk/toolsets/workspace.py +212 -101
  337. ksadk/tracing/exporters/inmemory_exporter.py +62 -51
  338. ksadk/tracing/exporters/langfuse_exporter.py +91 -76
  339. ksadk/tracing/setup.py +69 -53
  340. ksadk/tracing/span_utils.py +5 -2
  341. ksadk/tui/loop.py +78 -30
  342. ksadk/tui/stream_render.py +1 -0
  343. ksadk/ui_config.py +5 -3
  344. ksadk/version.py +1 -1
  345. ksadk_runtime_common/schemas/runtime_event_v1.json +95 -0
  346. agentengine_sdk_python-0.7.0.dist-info/RECORD +0 -482
  347. ksadk/server/static/assets/CodeBlock-P16VOLYi.js +0 -9
  348. ksadk/server/static/assets/MathMessageMarkdown-CdGiQWHR.js +0 -8
  349. ksadk/server/static/assets/MermaidBlock-IOcal8cm.js +0 -303
  350. ksadk/server/static/assets/NativeTerminalPanel-DGSDWsei.js +0 -1
  351. ksadk/server/static/assets/architecture-7EHR7CIX-BvUlsA6l.js +0 -1
  352. ksadk/server/static/assets/channel-CTuydARX.js +0 -1
  353. ksadk/server/static/assets/chunk-QZHKN3VN-BnCydivS.js +0 -1
  354. ksadk/server/static/assets/classDiagram-4FO5ZUOK-BNHg45Be.js +0 -1
  355. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-BNHg45Be.js +0 -1
  356. ksadk/server/static/assets/eventmodeling-FCH6USID-DsAgWnlf.js +0 -1
  357. ksadk/server/static/assets/gitGraph-WXDBUCRP-BIao9Yjg.js +0 -1
  358. ksadk/server/static/assets/index-C00Lwg3L.js +0 -165
  359. ksadk/server/static/assets/index-DAURbCsP.css +0 -1
  360. ksadk/server/static/assets/info-J43DQDTF-CyipqGxU.js +0 -1
  361. ksadk/server/static/assets/packet-YPE3B663-CGkyRxlg.js +0 -1
  362. ksadk/server/static/assets/pie-LRSECV5Y-M0uWAf4n.js +0 -1
  363. ksadk/server/static/assets/radar-GUYGQ44K-Bdbm24-x.js +0 -1
  364. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-8xBN_gLM.js +0 -1
  365. ksadk/server/static/assets/treeView-BLDUP644-npMo0ak1.js +0 -1
  366. ksadk/server/static/assets/treemap-LRROVOQU-CHdzrrdo.js +0 -1
  367. ksadk/server/static/assets/wardley-L42UT6IY-BEQz7wyy.js +0 -1
  368. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/WHEEL +0 -0
  369. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/entry_points.txt +0 -0
  370. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/licenses/LICENSE +0 -0
  371. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/top_level.txt +0 -0
@@ -6,38 +6,37 @@ Serverless Provider - 金山云 Serverless 计算引擎 (AgentEngine 托管)
6
6
  - Deploy 阶段: 客户端调用 AgentEngine Server API 发起部署
7
7
  """
8
8
 
9
- import os
10
9
  import json
11
10
  import logging
12
- import shutil
11
+ import os
13
12
  import time
14
- import yaml
15
13
  from pathlib import Path
16
- from typing import Dict, Any, List, Optional
14
+ from typing import Any, Dict, List, Optional
15
+
17
16
  import click
17
+ import yaml
18
18
 
19
- from ksadk.builders.ks3_uploader import KS3Uploader
19
+ from ksadk.api import AgentEngineClient, DryRunExit
20
20
  from ksadk.builders.code_builder import CodeBuilder
21
+ from ksadk.builders.container_builder import (
22
+ ContainerBuilder,
23
+ registry_kind_label,
24
+ resolve_registry_credentials,
25
+ )
26
+ from ksadk.builders.ks3_uploader import KS3Uploader
27
+ from ksadk.configs.env_registry import ENV_VAR_REGISTRY
28
+ from ksadk.configs.global_config import get_env_from_global_config
29
+ from ksadk.configs.settings import DEFAULT_RUNTIME_TIMEZONE
21
30
  from ksadk.deployment.agent_access import get_latest_agent_access
22
31
  from ksadk.deployment.base import (
23
32
  BaseDeployProvider,
24
- DeployTarget,
25
33
  DeployResult,
26
34
  DeployStatus,
35
+ DeployTarget,
27
36
  PackageInfo,
28
37
  )
29
38
  from ksadk.deployment.registry import DeployProviderRegistry
30
39
  from ksadk.deployment.ui_config import resolve_ui_config, ui_config_to_state_fields
31
- from ksadk.builders.container_builder import (
32
- ContainerBuilder,
33
- registry_kind_label,
34
- resolve_registry_credentials,
35
- )
36
- from ksadk.configs.settings import DEFAULT_RUNTIME_TIMEZONE
37
- from ksadk.configs.env_registry import ENV_VAR_REGISTRY
38
- from ksadk.configs.global_config import get_env_from_global_config
39
- from ksadk.api import AgentEngineClient, DryRunExit
40
-
41
40
 
42
41
  logger = logging.getLogger(__name__)
43
42
 
@@ -71,11 +70,7 @@ _DEPLOY_PROCESS_ENV_ALLOWLIST = frozenset(
71
70
  )
72
71
  _DEPLOY_PROCESS_ENV_PREFIXES = ("KSADK_", "OPENAI_", "KSYUN_", "E2B_")
73
72
  _DEPLOY_PROCESS_ENV_DENYLIST = frozenset(
74
- {
75
- spec.name
76
- for spec in ENV_VAR_REGISTRY
77
- if spec.module in {"builders", "cli", "configs", "web"}
78
- }
73
+ {spec.name for spec in ENV_VAR_REGISTRY if spec.module in {"builders", "cli", "configs", "web"}}
79
74
  ) | frozenset(
80
75
  {
81
76
  "KSADK_GLOBAL_CONFIG_ENV_KEYS",
@@ -96,7 +91,7 @@ def _should_forward_process_env(name: str) -> bool:
96
91
  @DeployProviderRegistry.register("kce")
97
92
  class ServerlessProvider(BaseDeployProvider):
98
93
  """金山云 Serverless 计算引擎 (AgentEngine Server 托管)
99
-
94
+
100
95
  重构后直接继承 BaseDeployProvider,不再依赖 DockerProvider。
101
96
  Container 模式使用 ContainerBuilder 进行打包和构建。
102
97
  """
@@ -109,7 +104,7 @@ class ServerlessProvider(BaseDeployProvider):
109
104
  supports_scaling = True
110
105
  requires_image_registry = False
111
106
 
112
- def __init__(self, config: Dict[str, Any] = None):
107
+ def __init__(self, config: Optional[Dict[str, Any]] = None):
113
108
  self.config = config or {}
114
109
 
115
110
  @staticmethod
@@ -124,13 +119,15 @@ class ServerlessProvider(BaseDeployProvider):
124
119
 
125
120
  if password and not username and registry_kind != "personal_kcr":
126
121
  click.secho(
127
- f" ⚠️ 检测到 KCR_PASSWORD 但缺少 KCR_USERNAME,已忽略{registry_kind_label(registry_kind)}镜像凭证;"
122
+ f" ⚠️ 检测到 KCR_PASSWORD 但缺少 KCR_USERNAME,"
123
+ f"已忽略{registry_kind_label(registry_kind)}镜像凭证;"
128
124
  "企业版 KCR 和第三方镜像仓库必须配置 KCR_USERNAME + KCR_PASSWORD",
129
125
  fg="yellow",
130
126
  )
131
127
  elif registry_kind == "personal_kcr":
132
128
  click.secho(
133
- " ⚠️ 未配置个人版 KCR 镜像凭证 (KSYUN_ACCOUNT_ID/KCR_PASSWORD),私有镜像可能无法拉取",
129
+ " ⚠️ 未配置个人版 KCR 镜像凭证 "
130
+ "(KSYUN_ACCOUNT_ID/KCR_PASSWORD),私有镜像可能无法拉取",
134
131
  fg="yellow",
135
132
  )
136
133
  else:
@@ -269,7 +266,7 @@ class ServerlessProvider(BaseDeployProvider):
269
266
  return None
270
267
 
271
268
  public_access = getattr(network, "enable_public_access", None)
272
- # 三态:None=未指定。create 默认开公网;update 未指定则不发 network 字段(保留服务端现有配置)。
269
+ # 三态:None=未指定。create 默认开公网;update 未指定则不发 network 字段。
273
270
  if public_access is None:
274
271
  public_value: Optional[bool] = None if is_update else True
275
272
  else:
@@ -317,19 +314,19 @@ class ServerlessProvider(BaseDeployProvider):
317
314
  seconds = int(elapsed % 60)
318
315
  return f"{minutes}m{seconds:02d}s"
319
316
 
320
-
321
317
  async def validate_config(self, target: DeployTarget) -> tuple[bool, str]:
322
318
  """验证配置: 确保已配置 AgentEngine Server"""
323
-
319
+
324
320
  server_url = os.getenv("AGENTENGINE_SERVER_URL")
325
-
321
+
326
322
  if not server_url:
327
323
  click.echo("⚠️ 未配置 AGENTENGINE_SERVER_URL,将尝试使用默认 Region 配置")
328
-
324
+
329
325
  # Container 模式: 检查 Docker 是否可用
330
326
  artifact_type = target.extra.get("artifact_type", "Code")
331
327
  if artifact_type == "Container":
332
328
  import subprocess
329
+
333
330
  try:
334
331
  result = subprocess.run(["docker", "version"], capture_output=True, timeout=10)
335
332
  if result.returncode != 0:
@@ -341,14 +338,19 @@ class ServerlessProvider(BaseDeployProvider):
341
338
 
342
339
  return True, ""
343
340
 
344
- async def package(self, project_dir: str, detection_result: Any, config: Dict[str, Any] = None) -> PackageInfo:
341
+ async def package(
342
+ self,
343
+ project_dir: str,
344
+ detection_result: Any,
345
+ config: Optional[Dict[str, Any]] = None,
346
+ ) -> PackageInfo:
345
347
  """打包项目
346
-
348
+
347
349
  Code 模式: 返回基本 PackageInfo,实际构建在 build() 中进行
348
350
  Container 模式: 使用 ContainerBuilder 打包
349
351
  """
350
352
  project_path = Path(project_dir)
351
-
353
+
352
354
  # 创建基本 PackageInfo
353
355
  package_info = PackageInfo(
354
356
  name=detection_result.name or project_path.name,
@@ -356,14 +358,15 @@ class ServerlessProvider(BaseDeployProvider):
356
358
  build_dir=str(project_path / ".agentengine" / "build"),
357
359
  project_dir=str(project_path),
358
360
  entry_point=detection_result.entry_point,
359
- metadata={}
361
+ metadata={},
360
362
  )
361
-
363
+
362
364
  # 尝试加载之前保存的构建元数据 (ks3_path 等)
363
365
  try:
364
366
  metadata_file = project_path / ".agentengine" / "build-metadata.json"
365
367
  if metadata_file.exists():
366
368
  import json
369
+
367
370
  with open(metadata_file, "r") as f:
368
371
  saved_data = json.load(f)
369
372
  if "metadata" in saved_data:
@@ -376,15 +379,32 @@ class ServerlessProvider(BaseDeployProvider):
376
379
  click.echo(f" 📦 已加载上次构建元数据: {count} 项")
377
380
  except Exception as e:
378
381
  click.secho(f"⚠️ 加载构建元数据失败: {e}", fg="yellow")
379
-
380
- return package_info
381
-
382
382
 
383
+ return package_info
383
384
 
384
385
  async def build(self, package_info: PackageInfo, target: DeployTarget) -> PackageInfo:
385
386
  """构建 & 上传 (客户端直传 KS3)"""
386
387
  artifact_type = target.extra.get("artifact_type", "Code")
387
388
 
389
+ if artifact_type == "ManagedRuntime":
390
+ # Declarative runtimes are delivered by Server -> Runtime Service as
391
+ # an inline manifest. Keep a local bundle only for inspection; do
392
+ # not acquire credentials or upload it to KS3.
393
+ from ksadk.builders.managed_runtime_builder import ManagedRuntimeBuilder
394
+
395
+ builder = ManagedRuntimeBuilder(
396
+ Path(package_info.project_dir),
397
+ config=target.extra.copy(),
398
+ runtime_version=str(target.extra.get("runtime_version") or ""),
399
+ )
400
+ build_result = builder.build()
401
+ if not build_result.success:
402
+ raise Exception(f"构建失败: {build_result.error_message}")
403
+ package_info.metadata.update(build_result.metadata)
404
+ if build_result.artifact_path is not None:
405
+ package_info.metadata["managed_manifest_path"] = str(build_result.artifact_path)
406
+ return package_info
407
+
388
408
  if artifact_type == "Code":
389
409
  # 1. 检查是否已有 KS3 路径
390
410
  # 优先级: CLI传入 > Metadata缓存 (仅当 !no_cache)
@@ -392,58 +412,73 @@ class ServerlessProvider(BaseDeployProvider):
392
412
  cached_ks3_path = package_info.metadata.get("ks3_path")
393
413
  no_cache = target.extra.get("no_cache", False)
394
414
  repackage = target.extra.get("repackage", False)
395
-
415
+
396
416
  # 如果显式传入了 ks3-path,直接使用
397
417
  if cli_ks3_path:
398
418
  package_info.metadata["ks3_path"] = cli_ks3_path
399
419
  return package_info
400
-
420
+
401
421
  # 如果没有 no_cache 且有缓存,才使用缓存
402
422
  if not no_cache and not repackage and cached_ks3_path:
403
423
  logger.info(f"Using cached bundle: {cached_ks3_path}")
404
424
  return package_info
405
425
 
406
- # 2. 构建 ZIP 包 (委托给 CodeBuilder)
407
-
426
+ # 2. 构建 ZIP 包
427
+
408
428
  # 传递配置,包括 no_cache
409
429
  builder_config = target.extra.copy()
410
430
  builder_config["no_cache"] = no_cache
411
431
  builder_config["repackage"] = repackage
412
-
413
- # 实例化 Builder
414
- # 注意: CodeBuilder 目前设计为直接操作 project_dir,
415
- # 这里传入原始 project_dir (package_info.project_dir)
416
- builder = CodeBuilder(Path(package_info.project_dir), config=builder_config)
417
-
432
+
433
+ if artifact_type == "ManagedRuntime":
434
+ from ksadk.builders.managed_runtime_builder import ManagedRuntimeBuilder
435
+
436
+ builder = ManagedRuntimeBuilder(
437
+ Path(package_info.project_dir),
438
+ config=builder_config,
439
+ runtime_version=str(target.extra.get("runtime_version") or ""),
440
+ )
441
+ else:
442
+ # CodeBuilder 直接操作原始 project_dir。
443
+ builder = CodeBuilder(Path(package_info.project_dir), config=builder_config)
444
+
418
445
  # 执行构建
419
446
  build_result = builder.build()
420
-
447
+
421
448
  if not build_result.success:
422
449
  raise Exception(f"构建失败: {build_result.error_message}")
423
-
450
+
424
451
  zip_path = build_result.artifact_path
452
+ if zip_path is None:
453
+ raise RuntimeError("代码构建成功但未生成 artifact_path")
454
+ package_info.metadata.update(build_result.metadata)
455
+ if build_result.metadata.get("manifest_sha256"):
456
+ target.extra["manifest_sha256"] = build_result.metadata["manifest_sha256"]
425
457
  # click.echo(f" ✅ ZIP 已生成: {zip_path}")
426
-
458
+
427
459
  # 3. 直接上传 KS3 (使用本地 AK/SK)
428
460
  # 3. 直接上传 KS3 (使用本地 AK/SK)
429
- click.echo("\n正在上传代码包到 KS3...")
461
+ artifact_label = "Runtime manifest" if artifact_type == "ManagedRuntime" else "代码包"
462
+ click.echo(f"\n正在上传{artifact_label}到 KS3...")
430
463
  upload_started_at = time.monotonic()
431
-
464
+
432
465
  ks3_bucket = target.extra.get("ks3_bucket")
433
466
  upload_region = "cn-beijing-6" if target.region == "pre-online" else target.region
434
-
467
+
435
468
  uploader = KS3Uploader(region=upload_region, bucket=ks3_bucket)
436
-
469
+
437
470
  # 使用时间戳确保每次上传的代码包路径唯一,支持真正的版本回滚
438
471
  from datetime import datetime
472
+
439
473
  timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
440
- object_key = f"agents/{package_info.name}/code_{timestamp}.zip"
441
-
474
+ object_prefix = "runtime" if artifact_type == "ManagedRuntime" else "code"
475
+ object_key = f"agents/{package_info.name}/{object_prefix}_{timestamp}.zip"
476
+
442
477
  ks3_path = await uploader.upload(zip_path, object_key)
443
-
478
+
444
479
  if not ks3_path:
445
480
  raise Exception("KS3 上传失败")
446
-
481
+
447
482
  logger.info(f"Upload success: {ks3_path}")
448
483
  click.echo(f" ✓ 上传耗时: {self._format_elapsed(upload_started_at)}")
449
484
  package_info.metadata["ks3_path"] = ks3_path
@@ -466,45 +501,47 @@ class ServerlessProvider(BaseDeployProvider):
466
501
  logger.info(f"Using cached image: {cached_image}")
467
502
  package_info.image = cached_image
468
503
  return package_info
469
-
470
- builder = ContainerBuilder(
504
+
505
+ container_builder = ContainerBuilder(
471
506
  project_dir=Path(package_info.project_dir),
472
507
  tag=tag,
473
508
  registry=registry,
474
- no_cache=no_cache
509
+ no_cache=no_cache,
475
510
  )
476
-
511
+
477
512
  # 构建镜像
478
- build_result = builder.build()
513
+ build_result = container_builder.build()
479
514
  if not build_result.success:
480
515
  raise Exception(f"镜像构建失败: {build_result.error_message}")
481
-
482
- image_name = build_result.metadata.get("image")
516
+
517
+ image_name = str(build_result.metadata.get("image") or "").strip()
518
+ if not image_name:
519
+ raise RuntimeError("容器构建成功但未生成 image")
483
520
  package_info.image = image_name
484
521
  package_info.metadata["image"] = image_name
485
-
522
+
486
523
  # 推送镜像
487
- if not builder.push(image_name):
524
+ if not container_builder.push(image_name):
488
525
  raise Exception("镜像推送失败")
489
-
526
+
490
527
  click.secho(f"✅ 镜像已推送: {image_name}", fg="green")
491
528
 
492
529
  self._persist_build_metadata(package_info)
493
-
530
+
494
531
  return package_info
495
532
 
496
533
  async def deploy(self, package_info: PackageInfo, target: DeployTarget) -> DeployResult:
497
534
  """通过 AgentEngine Server 部署
498
-
535
+
499
536
  逻辑:
500
537
  - 读取本地 .agentengine.state 文件获取 agent_id
501
538
  - 如果有 agent_id → 执行更新 (endpoint 不变)
502
539
  - 如果没有 → 创建新 Agent,保存 agent_id 到状态文件
503
540
  """
504
-
541
+
505
542
  server_url = os.getenv("AGENTENGINE_SERVER_URL")
506
543
  click.echo(f"\n🚀 开始部署到 Serverless (Managed by {server_url})...")
507
-
544
+
508
545
  # 读取本地状态文件
509
546
  project_dir = package_info.project_dir
510
547
  state_file = Path(project_dir) / ".agentengine.state"
@@ -527,26 +564,29 @@ class ServerlessProvider(BaseDeployProvider):
527
564
  ui_state["ui_bundle_path"] = project_config.get("ui_bundle_path")
528
565
  if project_config.get("ui_bundle_dir") and not ui_state.get("ui_bundle_dir"):
529
566
  ui_state["ui_bundle_dir"] = project_config.get("ui_bundle_dir")
530
-
567
+
531
568
  # 构造请求 payload
532
569
  artifact_type = target.extra.get("artifact_type", "Code")
533
570
  artifact_path = ""
534
- if artifact_type == "Code":
571
+ code_backed = artifact_type == "Code"
572
+ if code_backed:
535
573
  original_artifact_path = package_info.metadata.get("ks3_path", "")
536
574
  artifact_path = original_artifact_path
537
-
575
+
538
576
  # 转换为内网地址 (如果 serverless 无法解析 ks3://)
539
577
  if artifact_path.startswith("ks3://"):
540
578
  try:
541
579
  from ksadk.common.constants import get_ks3_endpoints
542
-
580
+
543
581
  # 确定 KS3 Region code (pre-online -> cn-beijing)
544
582
  ks3_region = target.extra.get("ks3_region")
545
583
  if not ks3_region:
546
- ks3_region = "cn-beijing-6" if target.region == "pre-online" else target.region
547
-
584
+ ks3_region = (
585
+ "cn-beijing-6" if target.region == "pre-online" else target.region
586
+ )
587
+
548
588
  _, internal_endpoint = get_ks3_endpoints(ks3_region)
549
-
589
+
550
590
  if internal_endpoint:
551
591
  # ks3://bucket/key -> http://bucket.internal_endpoint/key
552
592
  bucket, key = self._parse_code_artifact_path(artifact_path)
@@ -555,32 +595,39 @@ class ServerlessProvider(BaseDeployProvider):
555
595
  click.echo(f" Converted artifact path: {artifact_path}")
556
596
  except Exception as e:
557
597
  logger.warning(f"Failed to convert ks3 path to internal URL: {e}")
558
-
598
+
559
599
  if not artifact_path:
560
600
  raise ValueError(
561
- "❌ 未找到代码包路径 (ks3_path)。\n"
562
- " 在 Serverless 模式下,必须先上传代码包。\n"
563
- " 👉 请先执行: agentengine build --mode code --push\n"
601
+ "❌ 未找到 KS3 artifact 路径 (ks3_path)。\n"
602
+ " 在 Serverless 模式下,必须先上传构建产物。\n"
603
+ " 👉 请先执行: agentengine build --push\n"
564
604
  " 或者在 deploy 命令中使用 --ks3-path 指定路径。"
565
605
  )
566
606
 
567
- parsed_bucket, parsed_object_key = self._parse_code_artifact_path(original_artifact_path)
607
+ parsed_bucket, parsed_object_key = self._parse_code_artifact_path(
608
+ original_artifact_path
609
+ )
568
610
  if not parsed_bucket or not parsed_object_key:
569
611
  raise ValueError(
570
- "❌ ks3_path 格式无效,缺少代码包对象路径。\n"
612
+ "❌ ks3_path 格式无效,缺少 artifact 对象路径。\n"
571
613
  f" 当前值: {original_artifact_path or '(empty)'}\n"
572
614
  " 期望格式: ks3://<bucket>/<object-key>\n"
573
- " 👉 请重新执行: agentengine build --mode code --push\n"
615
+ " 👉 请重新执行: agentengine build --push\n"
574
616
  " 或者传入完整的 --ks3-path。"
575
617
  )
576
-
577
- else:
578
- artifact_path = package_info.image
579
-
618
+
619
+ elif artifact_type == "Container":
620
+ artifact_path = str(package_info.image or "").strip()
621
+ if not artifact_path:
622
+ raise ValueError("Container 部署缺少 image")
623
+ elif artifact_type != "ManagedRuntime":
624
+ raise ValueError(f"Unsupported artifact type: {artifact_type}")
625
+
580
626
  # 构建 KS3 凭证
581
627
  ks3_config = None
582
- if artifact_type == "Code":
628
+ if code_backed:
583
629
  from ksadk.common.auth import AWSV4Auth
630
+
584
631
  auth = AWSV4Auth() # 读取本地 AK/SK
585
632
  if auth.access_key_id and auth.secret_access_key:
586
633
  # 智能推断 Bucket 和 Region
@@ -589,7 +636,7 @@ class ServerlessProvider(BaseDeployProvider):
589
636
  bucket_name, _ = self._parse_code_artifact_path(
590
637
  package_info.metadata.get("ks3_path", "")
591
638
  )
592
-
639
+
593
640
  # 如果没有提供,尝试从 artifact_path 解析
594
641
  if not bucket_name:
595
642
  if artifact_path.startswith("ks3://"):
@@ -599,35 +646,38 @@ class ServerlessProvider(BaseDeployProvider):
599
646
  logger.info(f"Extracted bucket from ks3:// path: {bucket_name}")
600
647
  except IndexError:
601
648
  pass
602
- elif artifact_path.startswith("http") and "." in artifact_path:
649
+ elif artifact_path.startswith("http") and "." in artifact_path:
603
650
  try:
604
651
  # http://bucket.endpoint/key -> bucket
605
652
  from urllib.parse import urlparse
653
+
606
654
  parsed = urlparse(artifact_path)
607
655
  bucket_name = parsed.netloc.split(".")[0]
608
656
  logger.info(f"Extracted bucket from HTTP URL: {bucket_name}")
609
657
  except Exception as e:
610
658
  logger.warning(f"Failed to extract bucket from URL: {e}")
611
-
659
+
612
660
  # 如果仍然没有,使用智能默认值(与 KS3Uploader 逻辑一致)
613
661
  if not bucket_name:
614
662
  account_id = os.getenv("KSYUN_ACCOUNT_ID")
615
- upload_region = "cn-beijing-6" if target.region == "pre-online" else target.region
616
-
663
+ upload_region = (
664
+ "cn-beijing-6" if target.region == "pre-online" else target.region
665
+ )
666
+
617
667
  if not account_id:
618
668
  raise ValueError(
619
669
  "❌ 缺少 KSYUN_ACCOUNT_ID 环境变量\n"
620
670
  " Bucket 名称格式必须为: agentengine-{account_id}-{region}\n"
621
671
  " 请在 .env 文件中设置: KSYUN_ACCOUNT_ID=你的账号ID"
622
672
  )
623
-
673
+
624
674
  bucket_name = f"agentengine-{account_id}-{upload_region}"
625
675
  logger.info(f"Using default bucket: {bucket_name}")
626
-
676
+
627
677
  # Region 逻辑需与 Build 阶段保持一致 (pre-online -> cn-beijing-6)
628
678
  ks3_region = target.extra.get("ks3_region")
629
679
  if not ks3_region:
630
- ks3_region = "cn-beijing-6" if target.region == "pre-online" else target.region
680
+ ks3_region = "cn-beijing-6" if target.region == "pre-online" else target.region
631
681
 
632
682
  ks3_config = {
633
683
  "access_key": auth.access_key_id,
@@ -636,18 +686,31 @@ class ServerlessProvider(BaseDeployProvider):
636
686
  "bucket": bucket_name,
637
687
  }
638
688
  logger.info(f"📦 KS3 Config: bucket={bucket_name}, region={ks3_region}")
639
-
689
+
690
+ runtime_config = None
691
+ if artifact_type == "ManagedRuntime":
692
+ runtime_config = {
693
+ "name": str(target.extra.get("runtime_name") or "").strip(),
694
+ "version": str(target.extra.get("runtime_version") or "").strip(),
695
+ }
696
+ missing = [key for key, value in runtime_config.items() if not value]
697
+ if missing:
698
+ raise ValueError(
699
+ "ManagedRuntime 部署缺少 "
700
+ + ", ".join(f"runtime_config.{key}" for key in missing)
701
+ )
702
+
640
703
  try:
641
704
  # 获取 dry_run 标识
642
705
  is_dry_run = target.extra.get("dry_run", False)
643
706
 
644
707
  async with AgentEngineClient(region=target.region, dry_run=is_dry_run) as client:
645
708
  agent_exists = False
646
-
709
+
647
710
  if existing_agent_id:
648
711
  # 有本地状态 → 先检查服务器上是否存在
649
712
  click.echo(f" 检测到本地状态: {existing_agent_id}")
650
-
713
+
651
714
  try:
652
715
  # 尝试获取 agent,确认是否存在
653
716
  existing_agent = await client.get_agent(existing_agent_id)
@@ -657,32 +720,37 @@ class ServerlessProvider(BaseDeployProvider):
657
720
  # Agent 不存在或查询失败
658
721
  err_msg = str(e).lower()
659
722
  if "not found" in err_msg or "404" in err_msg or "不存在" in err_msg:
660
- click.secho(f" ⚠️ 服务器上未找到 Agent {existing_agent_id},将创建新 Agent", fg="yellow")
723
+ click.secho(
724
+ f" ⚠️ 服务器上未找到 Agent {existing_agent_id},将创建新 Agent",
725
+ fg="yellow",
726
+ )
661
727
  agent_exists = False
662
- # 如果是 DryRun 抛出的异常(表明请求本来会发出去但被拦截了),我们认为 Agent 可能存在也可能不存在
663
- # 但为了安全起见,在 DryRun 模式下我们假设它存在并走更新路径,或者简单地打印日志
728
+ # DryRun 异常表示真实请求被拦截,无法确认 Agent 是否存在。
729
+ # 为安全起见,DryRun 假设它存在并走更新路径。
664
730
  elif "Dry Run" in str(e):
665
- click.secho(f" [Dry Run] 假设 Agent {existing_agent_id} 存在", fg="cyan")
666
- agent_exists = True
731
+ click.secho(
732
+ f" [Dry Run] 假设 Agent {existing_agent_id} 存在", fg="cyan"
733
+ )
734
+ agent_exists = True
667
735
  else:
668
736
  # 其他错误,重新抛出
669
737
  raise
670
-
738
+
671
739
  if agent_exists:
672
740
  # Agent 存在 → 执行更新
673
- click.echo(f" 执行热更新 (endpoint 保持不变)...")
674
-
741
+ click.echo(" 执行热更新 (endpoint 保持不变)...")
742
+
675
743
  update_data = {
676
744
  "artifact_type": artifact_type,
677
745
  "artifact_path": artifact_path,
678
746
  "resources": {
679
747
  "cpu": target.resources.cpu,
680
- "memory": target.resources.memory
748
+ "memory": target.resources.memory,
681
749
  },
682
750
  "scaling": {
683
751
  "min_replicas": target.scaling.min_replicas,
684
752
  "max_replicas": target.scaling.max_replicas,
685
- "concurrency": target.scaling.concurrency
753
+ "concurrency": target.scaling.concurrency,
686
754
  },
687
755
  "observability": {
688
756
  "langfuse_enabled": target.extra.get("enable_observability", True)
@@ -693,16 +761,20 @@ class ServerlessProvider(BaseDeployProvider):
693
761
  "url": resolved_ui.url,
694
762
  },
695
763
  }
696
-
764
+ if runtime_config:
765
+ update_data["runtime_config"] = runtime_config
766
+
697
767
  if ks3_config:
698
768
  update_data["ks3"] = ks3_config
699
769
  elif artifact_type == "Container":
700
770
  image_credential = self._image_credential_from_env(artifact_path)
701
771
  if image_credential:
702
772
  update_data["image_credential"] = image_credential
703
- click.echo(
704
- f" 🔑 镜像凭证: {image_credential['username']}@{image_credential['endpoint']}"
773
+ credential_target = (
774
+ f"{image_credential['username']}@"
775
+ f"{image_credential['endpoint']}"
705
776
  )
777
+ click.echo(f" 🔑 镜像凭证: {credential_target}")
706
778
 
707
779
  # 加载全局配置 + 本地 .env,并通过部署参数注入到运行时环境变量。
708
780
  env_vars, env_file_exists, project_env_count = self._load_deploy_env_vars(
@@ -727,17 +799,19 @@ class ServerlessProvider(BaseDeployProvider):
727
799
  storage_config = self._serialize_storage_config(target)
728
800
  if storage_config:
729
801
  update_data["storage"] = storage_config
730
-
802
+
731
803
  # 注入更新时间戳,强制触发 Rolling Update (Pod 重启)
732
804
  if "env_vars" not in update_data:
733
805
  update_data["env_vars"] = {}
734
-
806
+
735
807
  import time
808
+
736
809
  update_data["env_vars"]["KSADK_UPDATED_AT"] = str(int(time.time()))
737
-
810
+
738
811
  # DEBUG: 打印 Payload 确认 trigger 是否存在
739
- click.echo(f" 🔄 更新 Trigger: KSADK_UPDATED_AT={update_data['env_vars']['KSADK_UPDATED_AT']}")
740
-
812
+ updated_at_value = update_data["env_vars"]["KSADK_UPDATED_AT"]
813
+ click.echo(f" 🔄 更新 Trigger: KSADK_UPDATED_AT={updated_at_value}")
814
+
741
815
  res = await client.update_agent(existing_agent_id, update_data)
742
816
  latest_access = {}
743
817
  if not is_dry_run:
@@ -751,38 +825,40 @@ class ServerlessProvider(BaseDeployProvider):
751
825
  exc,
752
826
  ),
753
827
  )
754
-
828
+
755
829
  # 如果是 Dry Run,手动构造假响应以避免崩溃
756
830
  if is_dry_run and not res:
757
831
  res = {"name": package_info.name, "endpoint": "http://dry-run-endpoint"}
758
-
832
+
759
833
  # 更新本地状态 (保留旧字段如 api_key)
760
834
  new_state = local_state.copy()
761
- new_state.update({
762
- "agent_id": latest_access.get("agent_id") or existing_agent_id,
763
- "name": latest_access.get("name") or res.get("name"),
764
- "region": target.region,
765
- "endpoint": latest_access.get("endpoint") or res.get("endpoint"),
766
- "updated_at": self._now_iso(),
767
- **ui_state,
768
- })
835
+ new_state.update(
836
+ {
837
+ "agent_id": latest_access.get("agent_id") or existing_agent_id,
838
+ "name": latest_access.get("name") or res.get("name"),
839
+ "region": target.region,
840
+ "endpoint": latest_access.get("endpoint") or res.get("endpoint"),
841
+ "updated_at": self._now_iso(),
842
+ **ui_state,
843
+ }
844
+ )
769
845
  if latest_access.get("api_key"):
770
846
  new_state["api_key"] = latest_access["api_key"]
771
847
  self._save_state(state_file, new_state)
772
-
848
+
773
849
  return DeployResult(
774
- status=DeployStatus.DEPLOYING,
850
+ status=DeployStatus.DEPLOYING,
775
851
  agent_id=existing_agent_id,
776
852
  agent_name=res.get("name"),
777
853
  endpoint=res.get("endpoint"),
778
- message=f"✅ Agent 已更新: {existing_agent_id}"
854
+ message=f"✅ Agent 已更新: {existing_agent_id}",
779
855
  )
780
856
  # else: agent_exists = False,继续执行创建逻辑
781
-
857
+
782
858
  # 没有本地状态,或本地状态对应的 Agent 在服务器上不存在 → 创建新 Agent
783
859
  if not existing_agent_id or not agent_exists:
784
860
  click.echo(f" 创建新 Agent: {package_info.name}")
785
-
861
+
786
862
  request_data = {
787
863
  "name": package_info.name,
788
864
  "framework": package_info.framework,
@@ -792,12 +868,12 @@ class ServerlessProvider(BaseDeployProvider):
792
868
  "instance_id": target.extra.get("instance_id", "default"),
793
869
  "resources": {
794
870
  "cpu": target.resources.cpu,
795
- "memory": target.resources.memory
871
+ "memory": target.resources.memory,
796
872
  },
797
873
  "scaling": {
798
874
  "min_replicas": target.scaling.min_replicas,
799
875
  "max_replicas": target.scaling.max_replicas,
800
- "concurrency": target.scaling.concurrency
876
+ "concurrency": target.scaling.concurrency,
801
877
  },
802
878
  "observability": {
803
879
  "langfuse_enabled": target.extra.get("enable_observability", True)
@@ -808,7 +884,9 @@ class ServerlessProvider(BaseDeployProvider):
808
884
  "url": resolved_ui.url,
809
885
  },
810
886
  }
811
-
887
+ if runtime_config:
888
+ request_data["runtime_config"] = runtime_config
889
+
812
890
  if ks3_config:
813
891
  request_data["ks3"] = ks3_config
814
892
 
@@ -817,9 +895,10 @@ class ServerlessProvider(BaseDeployProvider):
817
895
  image_credential = self._image_credential_from_env(artifact_path)
818
896
  if image_credential:
819
897
  request_data["image_credential"] = image_credential
820
- click.echo(
821
- f" 🔑 镜像凭证: {image_credential['username']}@{image_credential['endpoint']}"
898
+ credential_target = (
899
+ f"{image_credential['username']}@" f"{image_credential['endpoint']}"
822
900
  )
901
+ click.echo(f" 🔑 镜像凭证: {credential_target}")
823
902
 
824
903
  # 加载全局配置 + 本地 .env,并通过部署参数注入到运行时环境变量。
825
904
  env_vars, env_file_exists, project_env_count = self._load_deploy_env_vars(
@@ -837,7 +916,7 @@ class ServerlessProvider(BaseDeployProvider):
837
916
  click.echo(f" 📦 加载环境变量: {len(env_vars)} 项 from 全局配置")
838
917
 
839
918
  if env_vars:
840
- request_data["env_vars"] = env_vars
919
+ request_data["env_vars"] = env_vars
841
920
 
842
921
  network_config = self._serialize_network_config(target, is_update=False)
843
922
  if network_config:
@@ -852,20 +931,22 @@ class ServerlessProvider(BaseDeployProvider):
852
931
  ksyun_account_id = os.getenv("KSYUN_ACCOUNT_ID")
853
932
  if ksyun_account_id:
854
933
  extra_headers["X-Ksc-Account-Id"] = ksyun_account_id
855
-
934
+
856
935
  # 重新构造一个带 Header 的 client
857
- async with AgentEngineClient(region=target.region, extra_headers=extra_headers, dry_run=is_dry_run) as new_client:
936
+ async with AgentEngineClient(
937
+ region=target.region, extra_headers=extra_headers, dry_run=is_dry_run
938
+ ) as new_client:
858
939
  res = await new_client.create_agent(request_data)
859
-
940
+
860
941
  # 如果是 Dry Run,手动构造假响应
861
942
  if is_dry_run and not res:
862
943
  res = {
863
- "agent_id": "dry-run-agent-id",
864
- "name": package_info.name,
865
- "endpoint": "http://dry-run-endpoint",
866
- "api_key": "dry-run-key"
944
+ "agent_id": "dry-run-agent-id",
945
+ "name": package_info.name,
946
+ "endpoint": "http://dry-run-endpoint",
947
+ "api_key": "dry-run-key",
867
948
  }
868
-
949
+
869
950
  # CreateAgentProduct 返回 order_id,需要轮询 list_agents 获取 agent_id
870
951
  new_agent_id = res.get("agent_id")
871
952
  order_id = res.get("order_id")
@@ -876,10 +957,13 @@ class ServerlessProvider(BaseDeployProvider):
876
957
  if order_id and not new_agent_id:
877
958
  click.echo(f" 📋 订单已创建: {order_id},等待实例创建...")
878
959
  import time
960
+
879
961
  for i in range(12): # 最多等 60s
880
962
  time.sleep(5)
881
963
  try:
882
- detail = await client.get_agent(name=package_info.name, include_api_key=True)
964
+ detail = await client.get_agent(
965
+ name=package_info.name, include_api_key=True
966
+ )
883
967
  qa = detail.get("quick_access", {})
884
968
  basic = detail.get("basic", {})
885
969
  new_agent_id = basic.get("agent_id")
@@ -894,7 +978,10 @@ class ServerlessProvider(BaseDeployProvider):
894
978
  click.echo(f" ⏳ 等待中... ({(i+1)*5}s)")
895
979
 
896
980
  if not new_agent_id:
897
- click.secho(" ⚠️ 实例仍在创建中,稍后使用 'agentengine status' 查看", fg="yellow")
981
+ click.secho(
982
+ " ⚠️ 实例仍在创建中,稍后使用 'agentengine status' 查看",
983
+ fg="yellow",
984
+ )
898
985
 
899
986
  latest_access = {}
900
987
  if new_agent_id and not is_dry_run:
@@ -913,54 +1000,63 @@ class ServerlessProvider(BaseDeployProvider):
913
1000
  agent_name = latest_access.get("name") or agent_name
914
1001
  agent_endpoint = latest_access.get("endpoint") or agent_endpoint
915
1002
  agent_api_key = latest_access.get("api_key") or agent_api_key
916
-
1003
+
917
1004
  # 保存 agent_id 到本地状态文件
918
- self._save_state(state_file, {
919
- "agent_id": new_agent_id,
920
- "name": agent_name,
921
- "region": target.region,
922
- "endpoint": agent_endpoint,
923
- "api_key": agent_api_key, # 只在首次保存
924
- "order_id": order_id,
925
- "created_at": self._now_iso(),
926
- **ui_state,
927
- })
928
-
929
- click.echo(f" 💾 已保存状态到 .agentengine.state")
930
-
1005
+ self._save_state(
1006
+ state_file,
1007
+ {
1008
+ "agent_id": new_agent_id,
1009
+ "name": agent_name,
1010
+ "region": target.region,
1011
+ "endpoint": agent_endpoint,
1012
+ "api_key": agent_api_key, # 只在首次保存
1013
+ "order_id": order_id,
1014
+ "created_at": self._now_iso(),
1015
+ **ui_state,
1016
+ },
1017
+ )
1018
+
1019
+ click.echo(" 💾 已保存状态到 .agentengine.state")
1020
+
931
1021
  return DeployResult(
932
- status=DeployStatus.DEPLOYING,
1022
+ status=DeployStatus.DEPLOYING,
933
1023
  agent_id=new_agent_id,
934
1024
  agent_name=agent_name,
935
- endpoint=agent_endpoint,
1025
+ endpoint=agent_endpoint,
936
1026
  api_key=agent_api_key,
937
- message=f"✅ Agent ID: {new_agent_id or '(创建中)'} (首次部署, 订单: {order_id or '-'})"
1027
+ message=(
1028
+ f"✅ Agent ID: {new_agent_id or '(创建中)'} "
1029
+ f"(首次部署, 订单: {order_id or '-'})"
1030
+ ),
938
1031
  )
939
1032
 
1033
+ return DeployResult(
1034
+ status=DeployStatus.FAILED,
1035
+ message="部署流程未返回 Agent 状态",
1036
+ )
1037
+
940
1038
  except DryRunExit as e:
941
1039
  return DeployResult(
942
1040
  status=DeployStatus.SKIPPED,
943
1041
  message="✅ Dry Run Completed: 请求已打印,未执行实际变更。",
944
1042
  metadata={"dry_run_request": e.payload or {}},
945
1043
  )
946
-
1044
+
947
1045
  except Exception as e:
948
1046
  logger.error(f"Deploy failed: {e}")
949
-
1047
+
950
1048
  # 检测名称冲突
951
1049
  err_msg = str(e)
952
1050
  if "Conflict" in err_msg or "409" in err_msg or "already exists" in err_msg:
953
1051
  return DeployResult(
954
1052
  status=DeployStatus.FAILED,
955
1053
  message=f"❌ 部署失败: Agent 名称 '{package_info.name}' 已存在。\n"
956
- f" 提示: 请检查是否重复创建。\n"
957
- f" 👉 解决方法: 请在 agentengine.yaml 中修改 'name' 字段 (如添加后缀) 后重试。"
1054
+ f" 提示: 请检查是否重复创建。\n"
1055
+ " 👉 解决方法: 请在 agentengine.yaml 中修改 'name' 字段 "
1056
+ "(如添加后缀) 后重试。",
958
1057
  )
959
-
960
- return DeployResult(
961
- status=DeployStatus.FAILED,
962
- message=f"Server 请求失败: {str(e)}"
963
- )
1058
+
1059
+ return DeployResult(status=DeployStatus.FAILED, message=f"Server 请求失败: {str(e)}")
964
1060
 
965
1061
  async def get_status(self, agent_id: str, target: DeployTarget) -> DeployResult:
966
1062
  """获取 Agent 状态"""
@@ -968,7 +1064,7 @@ class ServerlessProvider(BaseDeployProvider):
968
1064
  try:
969
1065
  async with AgentEngineClient(region=target.region, dry_run=dry_run) as client:
970
1066
  res = await client.get_agent(agent_id)
971
-
1067
+
972
1068
  status_map = {
973
1069
  "running": DeployStatus.RUNNING,
974
1070
  "ready": DeployStatus.RUNNING,
@@ -978,9 +1074,9 @@ class ServerlessProvider(BaseDeployProvider):
978
1074
  "scaling": DeployStatus.UPDATING,
979
1075
  "failed": DeployStatus.FAILED,
980
1076
  "error": DeployStatus.FAILED,
981
- "unknown": DeployStatus.UNKNOWN
1077
+ "unknown": DeployStatus.UNKNOWN,
982
1078
  }
983
-
1079
+
984
1080
  # 使状态匹配不区分大小写,以兼容服务端的改动 (Creating -> CREATING)
985
1081
  current_status = (res.get("status") or "").lower()
986
1082
  return DeployResult(
@@ -988,21 +1084,20 @@ class ServerlessProvider(BaseDeployProvider):
988
1084
  agent_id=res.get("agent_id"),
989
1085
  agent_name=res.get("name"),
990
1086
  endpoint=res.get("endpoint"),
991
- message=f"Status: {res.get('status')} ({res.get('phase')})"
1087
+ message=f"Status: {res.get('status')} ({res.get('phase')})",
992
1088
  )
993
1089
  except DryRunExit:
994
1090
  return DeployResult(status=DeployStatus.SKIPPED, message="Dry Run executed.")
995
1091
  except Exception as e:
996
- return DeployResult(
997
- status=DeployStatus.UNKNOWN,
998
- message=f"查询失败: {e}"
999
- )
1092
+ return DeployResult(status=DeployStatus.UNKNOWN, message=f"查询失败: {e}")
1000
1093
 
1001
1094
  async def destroy(self, agent_id: str, target: DeployTarget) -> bool:
1002
1095
  """销毁 Agent"""
1003
1096
  dry_run = target.extra.get("dry_run", False)
1004
1097
  project_dir = str(target.extra.get("project_dir") or "").strip()
1005
- state_file = (Path(project_dir).resolve() if project_dir else Path(".").resolve()) / ".agentengine.state"
1098
+ state_file = (
1099
+ Path(project_dir).resolve() if project_dir else Path(".").resolve()
1100
+ ) / ".agentengine.state"
1006
1101
 
1007
1102
  try:
1008
1103
  async with AgentEngineClient(region=target.region, dry_run=dry_run) as client:
@@ -1015,8 +1110,10 @@ class ServerlessProvider(BaseDeployProvider):
1015
1110
  os.remove(state_file)
1016
1111
  logger.info(f"Deleted local state file: {state_file}")
1017
1112
  except Exception as cleanup_error:
1018
- logger.warning(f"Failed to delete local state file {state_file}: {cleanup_error}")
1019
- return success
1113
+ logger.warning(
1114
+ f"Failed to delete local state file {state_file}: {cleanup_error}"
1115
+ )
1116
+ return bool(success)
1020
1117
  except DryRunExit:
1021
1118
  # 让异常冒泡给 CLI 处理
1022
1119
  raise
@@ -1030,19 +1127,27 @@ class ServerlessProvider(BaseDeployProvider):
1030
1127
  try:
1031
1128
  async with AgentEngineClient(region=target.region, dry_run=dry_run) as client:
1032
1129
  res = await client.list_agents()
1033
-
1130
+
1034
1131
  results = []
1035
1132
  for agent in res.get("Agents", []):
1036
1133
  current_status = (agent.get("status") or "").lower()
1037
- results.append(DeployResult(
1038
- status=DeployStatus.RUNNING if current_status in ("running", "ready") else (
1039
- DeployStatus.DEPLOYING if current_status == "creating" else DeployStatus.UNKNOWN
1040
- ),
1041
- agent_id=agent.get("agent_id"),
1042
- agent_name=agent.get("name"),
1043
- endpoint=agent.get("endpoint"),
1044
- message=agent.get("status")
1045
- ))
1134
+ results.append(
1135
+ DeployResult(
1136
+ status=(
1137
+ DeployStatus.RUNNING
1138
+ if current_status in ("running", "ready")
1139
+ else (
1140
+ DeployStatus.DEPLOYING
1141
+ if current_status == "creating"
1142
+ else DeployStatus.UNKNOWN
1143
+ )
1144
+ ),
1145
+ agent_id=agent.get("agent_id"),
1146
+ agent_name=agent.get("name"),
1147
+ endpoint=agent.get("endpoint"),
1148
+ message=agent.get("status"),
1149
+ )
1150
+ )
1046
1151
  return results
1047
1152
  except DryRunExit:
1048
1153
  raise
@@ -1056,7 +1161,7 @@ class ServerlessProvider(BaseDeployProvider):
1056
1161
  try:
1057
1162
  async with AgentEngineClient(region=target.region, dry_run=dry_run) as client:
1058
1163
  response = await client.chat(agent_id, message, stream=False)
1059
- return response.get("output", "")
1164
+ return str(response.get("output", ""))
1060
1165
  except DryRunExit:
1061
1166
  raise
1062
1167
  except Exception as e:
@@ -1066,7 +1171,7 @@ class ServerlessProvider(BaseDeployProvider):
1066
1171
  """读取本地状态文件"""
1067
1172
  if state_file.exists():
1068
1173
  try:
1069
- with open(state_file, 'r', encoding='utf-8') as f:
1174
+ with open(state_file, "r", encoding="utf-8") as f:
1070
1175
  return yaml.safe_load(f) or {}
1071
1176
  except Exception as e:
1072
1177
  logger.warning(f"Failed to load state file: {e}")
@@ -1102,8 +1207,9 @@ class ServerlessProvider(BaseDeployProvider):
1102
1207
  def _save_state(self, state_file: Path, state: Dict[str, Any]) -> None:
1103
1208
  """保存状态到本地文件"""
1104
1209
  import yaml
1210
+
1105
1211
  try:
1106
- with open(state_file, 'w', encoding='utf-8') as f:
1212
+ with open(state_file, "w", encoding="utf-8") as f:
1107
1213
  yaml.dump(state, f, default_flow_style=False, allow_unicode=True)
1108
1214
  logger.debug(f"State saved to {state_file}")
1109
1215
  except Exception as e:
@@ -1112,4 +1218,5 @@ class ServerlessProvider(BaseDeployProvider):
1112
1218
  def _now_iso(self) -> str:
1113
1219
  """返回当前时间 ISO 格式"""
1114
1220
  from datetime import datetime
1221
+
1115
1222
  return datetime.now().isoformat()