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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (371) hide show
  1. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/METADATA +36 -20
  2. agentengine_sdk_python-0.8.0.dist-info/RECORD +578 -0
  3. ksadk/a2a/__init__.py +178 -11
  4. ksadk/a2a/bootstrap.py +334 -0
  5. ksadk/a2a/card.py +120 -0
  6. ksadk/a2a/context_store.py +203 -0
  7. ksadk/a2a/control_plane.py +818 -0
  8. ksadk/a2a/credential.py +99 -0
  9. ksadk/a2a/event_adapter.py +149 -0
  10. ksadk/a2a/executor.py +406 -89
  11. ksadk/a2a/external_transport.py +516 -0
  12. ksadk/a2a/identity.py +304 -0
  13. ksadk/a2a/ids.py +22 -0
  14. ksadk/a2a/langgraph.py +285 -0
  15. ksadk/a2a/resume_store.py +201 -0
  16. ksadk/a2a/routes.py +105 -0
  17. ksadk/a2a/server.py +107 -60
  18. ksadk/a2a/space_client.py +1101 -0
  19. ksadk/a2a/task_adapter.py +423 -0
  20. ksadk/a2a/task_event_dispatcher.py +167 -0
  21. ksadk/a2a/task_event_outbox.py +326 -0
  22. ksadk/a2a/task_store.py +206 -0
  23. ksadk/a2ui/__init__.py +27 -0
  24. ksadk/a2ui/core.py +186 -0
  25. ksadk/a2ui/models.py +166 -0
  26. ksadk/a2ui/renderer.py +198 -0
  27. ksadk/agui/__init__.py +9 -0
  28. ksadk/agui/a2ui_projection.py +92 -0
  29. ksadk/agui/agent.py +857 -0
  30. ksadk/agui/config.py +86 -0
  31. ksadk/agui/routes.py +55 -0
  32. ksadk/api/client.py +233 -191
  33. ksadk/builders/__init__.py +2 -0
  34. ksadk/builders/base.py +16 -14
  35. ksadk/builders/code_builder.py +318 -236
  36. ksadk/builders/container_builder.py +187 -167
  37. ksadk/builders/framework_requirements.py +29 -11
  38. ksadk/builders/ks3_uploader.py +58 -27
  39. ksadk/builders/managed_runtime_builder.py +145 -0
  40. ksadk/builders/mcp_builder.py +91 -92
  41. ksadk/builders/requirements_utils.py +1 -5
  42. ksadk/cli/__init__.py +89 -171
  43. ksadk/cli/cmd_a2a.py +254 -70
  44. ksadk/cli/cmd_agent.py +19 -5
  45. ksadk/cli/cmd_build.py +158 -29
  46. ksadk/cli/cmd_completion.py +47 -35
  47. ksadk/cli/cmd_config.py +267 -198
  48. ksadk/cli/cmd_create.py +500 -720
  49. ksadk/cli/cmd_dashboard.py +120 -45
  50. ksadk/cli/cmd_deploy.py +117 -58
  51. ksadk/cli/cmd_destroy.py +44 -14
  52. ksadk/cli/cmd_files.py +63 -24
  53. ksadk/cli/cmd_hermes.py +168 -89
  54. ksadk/cli/cmd_invoke.py +184 -122
  55. ksadk/cli/cmd_launch.py +64 -28
  56. ksadk/cli/cmd_mcp.py +98 -64
  57. ksadk/cli/cmd_model.py +14 -5
  58. ksadk/cli/cmd_openclaw.py +483 -227
  59. ksadk/cli/cmd_replay.py +71 -0
  60. ksadk/cli/cmd_run.py +33 -10
  61. ksadk/cli/cmd_status.py +80 -31
  62. ksadk/cli/cmd_version.py +20 -13
  63. ksadk/cli/cmd_web.py +89 -13
  64. ksadk/cli/deploy_utils.py +20 -20
  65. ksadk/cli/dry_run.py +5 -3
  66. ksadk/cli/error_utils.py +37 -12
  67. ksadk/cli/global_options.py +1 -2
  68. ksadk/cli/local_runtime.py +1 -2
  69. ksadk/cli/model_catalog.py +6 -2
  70. ksadk/cli/network_options.py +34 -14
  71. ksadk/cli/resource_common.py +6 -2
  72. ksadk/cli/storage.py +0 -1
  73. ksadk/cli/ui.py +5 -3
  74. ksadk/cli/workflow_common.py +51 -17
  75. ksadk/codex/__init__.py +12 -0
  76. ksadk/codex/client.py +408 -0
  77. ksadk/codex/phase.py +143 -0
  78. ksadk/codex/runtime.py +449 -0
  79. ksadk/common/aicp_env.py +0 -1
  80. ksadk/common/auth.py +2 -2
  81. ksadk/common/constants.py +1 -3
  82. ksadk/common/llm_utils.py +17 -13
  83. ksadk/compat/__init__.py +5 -0
  84. ksadk/compat/adk_compat.py +200 -0
  85. ksadk/compat/copilotkit_a2ui.py +330 -0
  86. ksadk/configs/__init__.py +12 -12
  87. ksadk/configs/env_registry.py +500 -100
  88. ksadk/configs/global_config.py +2 -1
  89. ksadk/configs/settings.py +151 -124
  90. ksadk/conversations/__init__.py +7 -5
  91. ksadk/conversations/attachment_storage.py +16 -11
  92. ksadk/conversations/attachments.py +44 -36
  93. ksadk/conversations/compaction_pipeline.py +12 -12
  94. ksadk/conversations/compaction_prompt.py +9 -5
  95. ksadk/conversations/context.py +221 -6
  96. ksadk/conversations/message_projection.py +438 -51
  97. ksadk/conversations/model_context.py +12 -6
  98. ksadk/conversations/model_options.py +0 -1
  99. ksadk/conversations/normalize.py +20 -16
  100. ksadk/conversations/reasoning_markup.py +1 -1
  101. ksadk/conversations/runtime.py +339 -5255
  102. ksadk/conversations/runtime_compaction.py +333 -0
  103. ksadk/conversations/runtime_constants.py +27 -0
  104. ksadk/conversations/runtime_governance.py +185 -0
  105. ksadk/conversations/runtime_input.py +652 -0
  106. ksadk/conversations/runtime_invocation.py +395 -0
  107. ksadk/conversations/runtime_metadata.py +475 -0
  108. ksadk/conversations/runtime_observability.py +355 -0
  109. ksadk/conversations/runtime_payloads.py +272 -0
  110. ksadk/conversations/runtime_persistence.py +440 -0
  111. ksadk/conversations/runtime_preparation.py +418 -0
  112. ksadk/conversations/runtime_resume.py +816 -0
  113. ksadk/conversations/runtime_stream_events.py +902 -0
  114. ksadk/conversations/runtime_streaming.py +547 -0
  115. ksadk/conversations/semantic_summary.py +17 -5
  116. ksadk/conversations/session_title.py +6 -3
  117. ksadk/deployment/__init__.py +15 -16
  118. ksadk/deployment/agent_access.py +12 -23
  119. ksadk/deployment/base.py +51 -38
  120. ksadk/deployment/manager.py +63 -65
  121. ksadk/deployment/providers/serverless.py +309 -202
  122. ksadk/deployment/registry.py +38 -32
  123. ksadk/deployment/state.py +11 -11
  124. ksadk/deployment/ui_config.py +1 -1
  125. ksadk/detection/__init__.py +1 -1
  126. ksadk/detection/detector.py +146 -83
  127. ksadk/detection/mcp_detector.py +9 -6
  128. ksadk/events/__init__.py +25 -0
  129. ksadk/events/parser.py +191 -0
  130. ksadk/events/replay.py +37 -0
  131. ksadk/events/runtime_event.py +264 -0
  132. ksadk/events/store.py +317 -0
  133. ksadk/harness/__init__.py +34 -0
  134. ksadk/harness/app.py +278 -0
  135. ksadk/harness/config.py +181 -0
  136. ksadk/harness/reasoner.py +105 -0
  137. ksadk/harness/runner.py +211 -0
  138. ksadk/harness/sandbox.py +141 -0
  139. ksadk/harness/tools.py +222 -0
  140. ksadk/hermes_terminal.py +23 -12
  141. ksadk/identity/resolver.py +15 -9
  142. ksadk/ids.py +32 -0
  143. ksadk/knowledge_base/adk_tool.py +1 -1
  144. ksadk/knowledge_base/client.py +23 -29
  145. ksadk/managed_runtime.py +188 -0
  146. ksadk/markdown.py +5 -2
  147. ksadk/mcp_runtime/__init__.py +9 -6
  148. ksadk/memory/__init__.py +1 -1
  149. ksadk/memory/adk/__init__.py +2 -0
  150. ksadk/memory/adk/backends/base_ltm_backend.py +2 -6
  151. ksadk/memory/adk/backends/http_ltm_backend.py +13 -21
  152. ksadk/memory/adk/backends/inmemory_ltm_backend.py +7 -13
  153. ksadk/memory/adk/backends/sdk_ltm_backend.py +26 -33
  154. ksadk/memory/adk/long_term_memory.py +31 -35
  155. ksadk/memory/adk/resilient_session_service.py +4 -5
  156. ksadk/memory/adk/short_term_memory.py +12 -21
  157. ksadk/memory/adk_tool.py +3 -2
  158. ksadk/memory/backends/base.py +19 -19
  159. ksadk/memory/backends/memory.py +24 -25
  160. ksadk/memory/backends/redis.py +31 -30
  161. ksadk/memory/langchain_tool.py +2 -1
  162. ksadk/memory/manager.py +52 -47
  163. ksadk/memory/service.py +10 -8
  164. ksadk/model_policy.py +15 -7
  165. ksadk/model_proxy/__init__.py +51 -0
  166. ksadk/model_proxy/bootstrap.py +80 -0
  167. ksadk/model_proxy/cache.py +165 -0
  168. ksadk/model_proxy/config.py +45 -0
  169. ksadk/model_proxy/demo_webui.py +115 -0
  170. ksadk/model_proxy/detect.py +145 -0
  171. ksadk/model_proxy/gate.py +68 -0
  172. ksadk/model_proxy/namespace.py +173 -0
  173. ksadk/model_proxy/protocol_proxy.py +22 -0
  174. ksadk/model_proxy/server.py +300 -0
  175. ksadk/model_proxy/transform.py +691 -0
  176. ksadk/openclaw_gateway.py +29 -14
  177. ksadk/runners/adk_runner.py +345 -120
  178. ksadk/runners/base_runner.py +46 -29
  179. ksadk/runners/codex_runner.py +132 -0
  180. ksadk/runners/deepagents_runner.py +0 -1
  181. ksadk/runners/factory.py +17 -5
  182. ksadk/runners/langchain_runner.py +29 -742
  183. ksadk/runners/langgraph_runner.py +352 -90
  184. ksadk/runners/patch_langchain.py +16 -16
  185. ksadk/runners/remote_runner.py +134 -33
  186. ksadk/runners/usage_accumulator.py +1 -0
  187. ksadk/runners/utils/langfuse.py +3 -3
  188. ksadk/runners/utils/loader.py +7 -7
  189. ksadk/runtime/__init__.py +41 -0
  190. ksadk/runtime/adapter.py +345 -0
  191. ksadk/runtime/framework_adapters.py +124 -0
  192. ksadk/runtime/preprocessing.py +118 -0
  193. ksadk/runtime/runner_adapter.py +873 -0
  194. ksadk/runtime_context.py +18 -3
  195. ksadk/runtime_state.py +0 -1
  196. ksadk/sandbox/__init__.py +4 -1
  197. ksadk/sandbox/backends/__init__.py +4 -1
  198. ksadk/sandbox/backends/e2b.py +13 -5
  199. ksadk/sandbox/backends/local_process.py +11 -3
  200. ksadk/sandbox/base.py +10 -15
  201. ksadk/sandbox/factory.py +14 -4
  202. ksadk/sandbox/registry.py +57 -6
  203. ksadk/server/api_models.py +15 -5
  204. ksadk/server/app.py +455 -3885
  205. ksadk/server/composition.py +21 -0
  206. ksadk/server/factory.py +624 -0
  207. ksadk/server/routes/__init__.py +1 -0
  208. ksadk/server/routes/checkpoint_resolution.py +116 -0
  209. ksadk/server/routes/common.py +713 -0
  210. ksadk/server/routes/control.py +327 -0
  211. ksadk/server/routes/dependencies.py +98 -0
  212. ksadk/server/routes/misc.py +448 -0
  213. ksadk/server/routes/models.py +443 -0
  214. ksadk/server/routes/openai_compat.py +207 -0
  215. ksadk/server/routes/projection.py +795 -0
  216. ksadk/server/routes/routers.py +52 -0
  217. ksadk/server/routes/run.py +726 -0
  218. ksadk/server/routes/sessions.py +649 -0
  219. ksadk/server/routes/streaming.py +223 -0
  220. ksadk/server/routes/workspace.py +381 -0
  221. ksadk/server/static/assets/{ArtifactsPanel-D-SSn2ee.js → ArtifactsPanel-Cjnqt-8W.js} +1 -1
  222. ksadk/server/static/assets/CodeBlock-BqyqZfuB.js +9 -0
  223. ksadk/server/static/assets/MathMessageMarkdown-BpH7jiFM.js +8 -0
  224. ksadk/server/static/assets/MermaidBlock-DWuxETaJ.js +303 -0
  225. ksadk/server/static/assets/NativeTerminalPanel-MDTopWMO.js +1 -0
  226. ksadk/server/static/assets/{arc-BA13sHc9.js → arc-CFKwSk_B.js} +1 -1
  227. ksadk/server/static/assets/architecture-7EHR7CIX-CynqOWjZ.js +1 -0
  228. ksadk/server/static/assets/{architectureDiagram-3BPJPVTR-DzJzgVoL.js → architectureDiagram-3BPJPVTR-Dej8jX8c.js} +1 -1
  229. ksadk/server/static/assets/{blockDiagram-GPEHLZMM-UTdVcZhn.js → blockDiagram-GPEHLZMM-1F64jqvy.js} +1 -1
  230. ksadk/server/static/assets/{c4Diagram-AAUBKEIU-Dix0GD4m.js → c4Diagram-AAUBKEIU-9q7AUAKb.js} +1 -1
  231. ksadk/server/static/assets/channel-iUGv2N24.js +1 -0
  232. ksadk/server/static/assets/{chunk-2J33WTMH-C2JxuZ42.js → chunk-2J33WTMH-6qgwJm7Q.js} +1 -1
  233. ksadk/server/static/assets/{chunk-4BX2VUAB-Be57QPgD.js → chunk-4BX2VUAB-CsWIQRhc.js} +1 -1
  234. ksadk/server/static/assets/{chunk-55IACEB6-WjSuy4nv.js → chunk-55IACEB6-BK8paA20.js} +1 -1
  235. ksadk/server/static/assets/{chunk-727SXJPM-BOovP-b5.js → chunk-727SXJPM-B-JEhy7h.js} +1 -1
  236. ksadk/server/static/assets/{chunk-AQP2D5EJ-DOmZNmWj.js → chunk-AQP2D5EJ-DYBvMHAa.js} +1 -1
  237. ksadk/server/static/assets/{chunk-FMBD7UC4-DzwlodkU.js → chunk-FMBD7UC4-BGhvzDYt.js} +1 -1
  238. ksadk/server/static/assets/{chunk-ND2GUHAM-DMqAikEU.js → chunk-ND2GUHAM-D98vPd-E.js} +1 -1
  239. ksadk/server/static/assets/chunk-QZHKN3VN-YQIEXeF6.js +1 -0
  240. ksadk/server/static/assets/classDiagram-4FO5ZUOK-CDAUuoXK.js +1 -0
  241. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-CDAUuoXK.js +1 -0
  242. ksadk/server/static/assets/{cose-bilkent-S5V4N54A-Zhy2GBnP.js → cose-bilkent-S5V4N54A-CX3yotHq.js} +1 -1
  243. ksadk/server/static/assets/{dagre-BM42HDAG-CbKrtIUz.js → dagre-BM42HDAG-C7TguAWo.js} +1 -1
  244. ksadk/server/static/assets/{diagram-2AECGRRQ-BRApgQRK.js → diagram-2AECGRRQ-Dd17_kws.js} +1 -1
  245. ksadk/server/static/assets/{diagram-5GNKFQAL-D0xbnDiK.js → diagram-5GNKFQAL-DVIClIil.js} +1 -1
  246. ksadk/server/static/assets/{diagram-KO2AKTUF-CVugVI9L.js → diagram-KO2AKTUF-Df_3gYQa.js} +1 -1
  247. ksadk/server/static/assets/{diagram-LMA3HP47-DozUGgee.js → diagram-LMA3HP47-BhLk6ZtA.js} +1 -1
  248. ksadk/server/static/assets/{diagram-OG6HWLK6-ZOYsKlru.js → diagram-OG6HWLK6-D4GNGvuu.js} +1 -1
  249. ksadk/server/static/assets/{dist-DmFaq_Iy.js → dist-6CVKuTAe.js} +1 -1
  250. ksadk/server/static/assets/{dist-8EEyGgDx.js → dist-BUHRxvDG.js} +1 -1
  251. ksadk/server/static/assets/{dist-B0NP_Z0z.js → dist-BZ9n9AjO.js} +1 -1
  252. ksadk/server/static/assets/{dist-DMezvBGJ.js → dist-BibcG1V9.js} +1 -1
  253. ksadk/server/static/assets/{dist-C3HIIaN5.js → dist-Bs-jQcRX.js} +1 -1
  254. ksadk/server/static/assets/{dist-BrCcQ47T.js → dist-C2xjE7cO.js} +1 -1
  255. ksadk/server/static/assets/{dist-Dp0k7bWI.js → dist-C7-3jInC.js} +1 -1
  256. ksadk/server/static/assets/{dist-D-xOD048.js → dist-C99THtIA.js} +1 -1
  257. ksadk/server/static/assets/{dist-CkEKJFtk.js → dist-CGcp2ex8.js} +1 -1
  258. ksadk/server/static/assets/{dist-DyOkZmze.js → dist-CVQRZjPu.js} +1 -1
  259. ksadk/server/static/assets/{dist-BssVmjIo.js → dist-Cf23NY4L.js} +1 -1
  260. ksadk/server/static/assets/{dist-BIJVDMuB.js → dist-CgF3fj15.js} +1 -1
  261. ksadk/server/static/assets/{dist-2hInLS_J.js → dist-Cwt7koer.js} +1 -1
  262. ksadk/server/static/assets/{dist-DyWsb78Q.js → dist-D82mtD2s.js} +1 -1
  263. ksadk/server/static/assets/{dist-D-JMdWPQ.js → dist-DF06ORQo.js} +1 -1
  264. ksadk/server/static/assets/{dist-BmlMPsCc.js → dist-DHn6nBzr.js} +1 -1
  265. ksadk/server/static/assets/{dist-gX6GOLKq.js → dist-Djgl2wVZ.js} +1 -1
  266. ksadk/server/static/assets/{dist-DpKtt4Bo.js → dist-DlzCRy0S.js} +1 -1
  267. ksadk/server/static/assets/{dist-8_SfK1IP.js → dist-DqNnNFrw.js} +1 -1
  268. ksadk/server/static/assets/{dist-D57wnGWd.js → dist-DyvYLMW9.js} +1 -1
  269. ksadk/server/static/assets/{dist-CPBtqRTW.js → dist-eoW6tZXA.js} +1 -1
  270. ksadk/server/static/assets/{dist-DL_NKc_z.js → dist-ivOya1LD.js} +1 -1
  271. ksadk/server/static/assets/{erDiagram-TEJ5UH35-Bk-9bgE5.js → erDiagram-TEJ5UH35-CnfRcY2M.js} +1 -1
  272. ksadk/server/static/assets/eventmodeling-FCH6USID-ChYO-ijM.js +1 -0
  273. ksadk/server/static/assets/{flowDiagram-I6XJVG4X-Dn9kZVuZ.js → flowDiagram-I6XJVG4X-DGaJjGNJ.js} +1 -1
  274. ksadk/server/static/assets/{ganttDiagram-6RSMTGT7-BGxXlJqm.js → ganttDiagram-6RSMTGT7-DpCoB2g9.js} +1 -1
  275. ksadk/server/static/assets/gitGraph-WXDBUCRP-BN_0Fk-j.js +1 -0
  276. ksadk/server/static/assets/{gitGraphDiagram-PVQCEYII-C7Q0X-wi.js → gitGraphDiagram-PVQCEYII-9IKVFBVT.js} +1 -1
  277. ksadk/server/static/assets/index-QSwCHuB8.js +177 -0
  278. ksadk/server/static/assets/index-jOPmTOZH.css +2 -0
  279. ksadk/server/static/assets/info-J43DQDTF-Cp6o3vId.js +1 -0
  280. ksadk/server/static/assets/{infoDiagram-5YYISTIA-BO_CSqq5.js → infoDiagram-5YYISTIA-CYIIsb8y.js} +1 -1
  281. ksadk/server/static/assets/{ishikawaDiagram-YF4QCWOH-eYLPLd46.js → ishikawaDiagram-YF4QCWOH-DLOHGvWw.js} +1 -1
  282. ksadk/server/static/assets/{journeyDiagram-JHISSGLW-De9geSb0.js → journeyDiagram-JHISSGLW-BIzKeejT.js} +1 -1
  283. ksadk/server/static/assets/{kanban-definition-UN3LZRKU-Cs80kQto.js → kanban-definition-UN3LZRKU-BWHoFSw2.js} +1 -1
  284. ksadk/server/static/assets/{katex-DSrCFD8n.js → katex-DATssjp1.js} +1 -1
  285. ksadk/server/static/assets/{linear-CN9sbKTF.js → linear-CvMBw9cA.js} +1 -1
  286. ksadk/server/static/assets/{mermaid-parser.core-DlgSBU8l.js → mermaid-parser.core-mGAcEwcq.js} +2 -2
  287. ksadk/server/static/assets/{mindmap-definition-RKZ34NQL-9afz7Oug.js → mindmap-definition-RKZ34NQL-CSAQxEAe.js} +1 -1
  288. ksadk/server/static/assets/packet-YPE3B663-wQzct3cT.js +1 -0
  289. ksadk/server/static/assets/pie-LRSECV5Y-BgTQiv-9.js +1 -0
  290. ksadk/server/static/assets/{pieDiagram-4H26LBE5-DPv_VstN.js → pieDiagram-4H26LBE5-By-ra07M.js} +1 -1
  291. ksadk/server/static/assets/{quadrantDiagram-W4KKPZXB-o77wZ1XK.js → quadrantDiagram-W4KKPZXB-CxIR4JXI.js} +1 -1
  292. ksadk/server/static/assets/radar-GUYGQ44K-BIq5fXsn.js +1 -0
  293. ksadk/server/static/assets/{requirementDiagram-4Y6WPE33-BYVw81VC.js → requirementDiagram-4Y6WPE33-DpW90iu3.js} +1 -1
  294. ksadk/server/static/assets/{sankeyDiagram-5OEKKPKP-B7nZFMKT.js → sankeyDiagram-5OEKKPKP-DpGa6EAV.js} +1 -1
  295. ksadk/server/static/assets/{sequenceDiagram-3UESZ5HK-BGRRrFw5.js → sequenceDiagram-3UESZ5HK-NTKNGGe5.js} +1 -1
  296. ksadk/server/static/assets/{stateDiagram-AJRCARHV-BUfHCoPs.js → stateDiagram-AJRCARHV-DGpd9yFG.js} +1 -1
  297. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-B3o579IQ.js +1 -0
  298. ksadk/server/static/assets/{timeline-definition-PNZ67QCA-FbCTGrf9.js → timeline-definition-PNZ67QCA-jqoYs3jQ.js} +1 -1
  299. ksadk/server/static/assets/treeView-BLDUP644-Dqi-E0EM.js +1 -0
  300. ksadk/server/static/assets/treemap-LRROVOQU-ClQP9CJ9.js +1 -0
  301. ksadk/server/static/assets/{vennDiagram-CIIHVFJN-DWgwtPsJ.js → vennDiagram-CIIHVFJN-l3Z7-wbP.js} +1 -1
  302. ksadk/server/static/assets/wardley-L42UT6IY-8XLvnNIs.js +1 -0
  303. ksadk/server/static/assets/{wardleyDiagram-YWT4CUSO-2x8G-tTM.js → wardleyDiagram-YWT4CUSO-BR54GPmr.js} +1 -1
  304. ksadk/server/static/assets/{xychartDiagram-2RQKCTM6-Drma3AYl.js → xychartDiagram-2RQKCTM6-SkiH8GsK.js} +1 -1
  305. ksadk/server/static/index.html +2 -2
  306. ksadk/server/terminal_sessions.py +111 -58
  307. ksadk/sessions/__init__.py +69 -19
  308. ksadk/sessions/base.py +31 -11
  309. ksadk/sessions/continuity.py +2 -3
  310. ksadk/sessions/in_memory.py +46 -2
  311. ksadk/sessions/local_service.py +148 -17
  312. ksadk/sessions/postgres_service.py +143 -25
  313. ksadk/sessions/resilient.py +36 -8
  314. ksadk/skills/models.py +17 -5
  315. ksadk/skills/package_store.py +5 -2
  316. ksadk/skills/runtime/agent.py +20 -5
  317. ksadk/skills/runtime/artifacts.py +1 -5
  318. ksadk/skills/runtime/backends/e2b.py +10 -4
  319. ksadk/skills/runtime/backends/local.py +15 -3
  320. ksadk/skills/runtime/base.py +1 -2
  321. ksadk/skills/runtime/executor.py +10 -3
  322. ksadk/skills/runtime/factory.py +4 -2
  323. ksadk/skills/runtime/loader.py +1 -2
  324. ksadk/skills/runtime/registry.py +15 -10
  325. ksadk/skills/runtime/request.py +3 -1
  326. ksadk/skills/service_client.py +38 -17
  327. ksadk/skills/tool_defs.py +15 -10
  328. ksadk/terminal_exec_policy.py +3 -4
  329. ksadk/tools/gateway.py +92 -15
  330. ksadk/tools/result_budget.py +12 -4
  331. ksadk/toolsets/__init__.py +134 -36
  332. ksadk/toolsets/platform.py +21 -5
  333. ksadk/toolsets/sandbox.py +82 -16
  334. ksadk/toolsets/skills.py +200 -39
  335. ksadk/toolsets/web.py +123 -26
  336. ksadk/toolsets/workspace.py +212 -101
  337. ksadk/tracing/exporters/inmemory_exporter.py +62 -51
  338. ksadk/tracing/exporters/langfuse_exporter.py +91 -76
  339. ksadk/tracing/setup.py +69 -53
  340. ksadk/tracing/span_utils.py +5 -2
  341. ksadk/tui/loop.py +78 -30
  342. ksadk/tui/stream_render.py +1 -0
  343. ksadk/ui_config.py +5 -3
  344. ksadk/version.py +1 -1
  345. ksadk_runtime_common/schemas/runtime_event_v1.json +95 -0
  346. agentengine_sdk_python-0.7.0.dist-info/RECORD +0 -482
  347. ksadk/server/static/assets/CodeBlock-P16VOLYi.js +0 -9
  348. ksadk/server/static/assets/MathMessageMarkdown-CdGiQWHR.js +0 -8
  349. ksadk/server/static/assets/MermaidBlock-IOcal8cm.js +0 -303
  350. ksadk/server/static/assets/NativeTerminalPanel-DGSDWsei.js +0 -1
  351. ksadk/server/static/assets/architecture-7EHR7CIX-BvUlsA6l.js +0 -1
  352. ksadk/server/static/assets/channel-CTuydARX.js +0 -1
  353. ksadk/server/static/assets/chunk-QZHKN3VN-BnCydivS.js +0 -1
  354. ksadk/server/static/assets/classDiagram-4FO5ZUOK-BNHg45Be.js +0 -1
  355. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-BNHg45Be.js +0 -1
  356. ksadk/server/static/assets/eventmodeling-FCH6USID-DsAgWnlf.js +0 -1
  357. ksadk/server/static/assets/gitGraph-WXDBUCRP-BIao9Yjg.js +0 -1
  358. ksadk/server/static/assets/index-C00Lwg3L.js +0 -165
  359. ksadk/server/static/assets/index-DAURbCsP.css +0 -1
  360. ksadk/server/static/assets/info-J43DQDTF-CyipqGxU.js +0 -1
  361. ksadk/server/static/assets/packet-YPE3B663-CGkyRxlg.js +0 -1
  362. ksadk/server/static/assets/pie-LRSECV5Y-M0uWAf4n.js +0 -1
  363. ksadk/server/static/assets/radar-GUYGQ44K-Bdbm24-x.js +0 -1
  364. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-8xBN_gLM.js +0 -1
  365. ksadk/server/static/assets/treeView-BLDUP644-npMo0ak1.js +0 -1
  366. ksadk/server/static/assets/treemap-LRROVOQU-CHdzrrdo.js +0 -1
  367. ksadk/server/static/assets/wardley-L42UT6IY-BEQz7wyy.js +0 -1
  368. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/WHEEL +0 -0
  369. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/entry_points.txt +0 -0
  370. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/licenses/LICENSE +0 -0
  371. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/top_level.txt +0 -0
ksadk/api/client.py CHANGED
@@ -4,17 +4,17 @@ AgentEngine Server API 客户端
4
4
  支持 AWS V4 签名认证,用于通过 KOP 网关访问 AgentEngine Server。
5
5
  """
6
6
 
7
- import os
8
- import re
9
7
  import json
10
- import uuid
11
- import socket
12
8
  import logging
13
9
  import mimetypes
10
+ import os
11
+ import re
12
+ import socket
13
+ import uuid
14
14
  from contextlib import contextmanager
15
15
  from dataclasses import dataclass
16
16
  from pathlib import Path
17
- from typing import Optional, Dict, Any, Sequence, Callable, Iterator
17
+ from typing import Any, Callable, Dict, Iterator, Optional, Sequence
18
18
  from urllib.parse import quote, unquote, urlparse, urlsplit
19
19
 
20
20
  import requests
@@ -38,7 +38,9 @@ class AttachmentContent:
38
38
  class DryRunExit(Exception):
39
39
  """DryRun 模式退出异常。"""
40
40
 
41
- def __init__(self, message: str = "Dry Run finished.", *, payload: Optional[Dict[str, Any]] = None):
41
+ def __init__(
42
+ self, message: str = "Dry Run finished.", *, payload: Optional[Dict[str, Any]] = None
43
+ ):
42
44
  self.payload = payload or {}
43
45
  super().__init__(message)
44
46
 
@@ -54,6 +56,7 @@ class AgentEngineAPIError(Exception):
54
56
  details: Optional[Dict[str, Any]] = None,
55
57
  ):
56
58
  self.raw_code = code
59
+ self.code: Optional[int]
57
60
  try:
58
61
  self.code = int(code)
59
62
  except (TypeError, ValueError):
@@ -69,9 +72,9 @@ class AgentEngineAPIError(Exception):
69
72
 
70
73
  class AgentEngineClient:
71
74
  """AgentEngine Server API 客户端
72
-
75
+
73
76
  使用 AWS V4 签名认证访问 KOP 网关后的 AgentEngine Server。
74
-
77
+
75
78
  凭证来源 (优先级从高到低):
76
79
  1. 构造函数参数
77
80
  2. 环境变量 KSYUN_ACCESS_KEY / KSYUN_SECRET_KEY
@@ -85,8 +88,8 @@ class AgentEngineClient:
85
88
  _permission_probe_cache: dict[tuple[str, str, str], bool] = {}
86
89
 
87
90
  def __init__(
88
- self,
89
- base_url: Optional[str] = None,
91
+ self,
92
+ base_url: Optional[str] = None,
90
93
  access_key: Optional[str] = None,
91
94
  secret_key: Optional[str] = None,
92
95
  region: str = "cn-beijing-6",
@@ -95,13 +98,9 @@ class AgentEngineClient:
95
98
  dry_run: bool = False,
96
99
  extra_headers: Optional[Dict[str, str]] = None,
97
100
  ):
98
- self.base_url = (
99
- base_url
100
- or os.getenv("AGENTENGINE_SERVER_URL")
101
- )
102
- if not self.base_url:
103
- self.base_url = self._detect_default_base_url()
104
-
101
+ resolved_base_url = base_url or os.getenv("AGENTENGINE_SERVER_URL")
102
+ self.base_url: str = resolved_base_url or self._detect_default_base_url()
103
+
105
104
  # 本地调试覆盖 (如果需要)
106
105
  # self.base_url = "http://localhost:8081"
107
106
  self.timeout = timeout
@@ -111,8 +110,8 @@ class AgentEngineClient:
111
110
  self.dry_run = bool(dry_run or self._is_global_dry_run_enabled())
112
111
  self.extra_headers = extra_headers or {}
113
112
  # 签名 service 可通过环境变量覆盖(例如 aicp)
114
- self.service = service or os.getenv("AGENTENGINE_SIGN_SERVICE", "aicp")
115
-
113
+ self.service: str = service or os.getenv("AGENTENGINE_SIGN_SERVICE") or "aicp"
114
+
116
115
  # AWS V4 签名
117
116
  self._auth = AWSV4Auth(
118
117
  access_key_id=access_key or "",
@@ -120,12 +119,12 @@ class AgentEngineClient:
120
119
  region=self.region,
121
120
  service=self.service,
122
121
  )
123
-
122
+
124
123
  if self._auth.is_enabled:
125
124
  logger.debug(f"AgentEngineClient initialized with V4Auth: {self.base_url}")
126
125
  else:
127
126
  logger.debug("AgentEngineClient: No credentials, signing disabled")
128
-
127
+
129
128
  self._session: Optional[requests.Session] = None
130
129
  self._http_error_log_suppressors: list[HttpErrorLogSuppressor] = []
131
130
  # 反查身份的实例缓存(避免同会话重复调 IAM);None=未尝试,ResolvedIdentity|None=已反查
@@ -135,10 +134,10 @@ class AgentEngineClient:
135
134
  @staticmethod
136
135
  def _ssl_verify_enabled() -> bool:
137
136
  insecure = (
138
- os.getenv("AGENTENGINE_SSL_INSECURE")
139
- or os.getenv("CURL_SSL_INSECURE")
140
- or ""
141
- ).strip().lower()
137
+ (os.getenv("AGENTENGINE_SSL_INSECURE") or os.getenv("CURL_SSL_INSECURE") or "")
138
+ .strip()
139
+ .lower()
140
+ )
142
141
  if insecure in {"1", "true", "yes", "on"}:
143
142
  urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
144
143
  return False
@@ -303,7 +302,9 @@ class AgentEngineClient:
303
302
  @staticmethod
304
303
  def _is_auth_related_error_details(details: Dict[str, Any]) -> bool:
305
304
  remote_code = str(details.get("remote_error_code") or "").strip().lower()
306
- remote_message = str(details.get("remote_error_message") or details.get("message") or "").strip().lower()
305
+ remote_message = (
306
+ str(details.get("remote_error_message") or details.get("message") or "").strip().lower()
307
+ )
307
308
  if remote_code in {
308
309
  "missingaccesskey",
309
310
  "missingsecretkey",
@@ -336,7 +337,9 @@ class AgentEngineClient:
336
337
  @staticmethod
337
338
  def _is_inner_account_intranet_error(details: Dict[str, Any]) -> bool:
338
339
  remote_code = str(details.get("remote_error_code") or "").strip().lower()
339
- remote_message = str(details.get("remote_error_message") or details.get("message") or "").strip().lower()
340
+ remote_message = (
341
+ str(details.get("remote_error_message") or details.get("message") or "").strip().lower()
342
+ )
340
343
  return (
341
344
  remote_code == "inneraccountcanonlyaccessthroughintranet"
342
345
  or "inner account can only access through intranet" in remote_message
@@ -356,7 +359,9 @@ class AgentEngineClient:
356
359
  )
357
360
  self.base_url = self._INNER_AICP_BASE_URL
358
361
 
359
- def _build_action_request_target(self, path: str, action: str) -> tuple[bool, Dict[str, str], str]:
362
+ def _build_action_request_target(
363
+ self, path: str, action: str
364
+ ) -> tuple[bool, Dict[str, str], str]:
360
365
  kop_mode = self._is_kop_mode()
361
366
  headers = self._build_headers(action=action, kop_mode=kop_mode)
362
367
  if kop_mode:
@@ -366,14 +371,17 @@ class AgentEngineClient:
366
371
  full_url = f"{self.base_url}{path}"
367
372
  return kop_mode, headers, full_url
368
373
 
369
- def _build_raw_action_request_target(self, action: str, accept: str, has_files: bool) -> tuple[bool, Dict[str, str], str]:
374
+ def _build_raw_action_request_target(
375
+ self, action: str, accept: str, has_files: bool
376
+ ) -> tuple[bool, Dict[str, str], str]:
370
377
  kop_mode = self._is_kop_mode()
371
378
  headers = self._build_headers(action=action, kop_mode=kop_mode)
372
379
  headers["Accept"] = accept
373
380
  if has_files:
374
381
  headers.pop("Content-Type", None)
382
+ version = os.getenv("AGENTENGINE_API_VERSION", "2024-06-12")
375
383
  full_url = (
376
- f"{self.base_url.rstrip('/')}/?Action={action}&Version={os.getenv('AGENTENGINE_API_VERSION', '2024-06-12')}"
384
+ f"{self.base_url.rstrip('/')}/?Action={action}&Version={version}"
377
385
  if kop_mode
378
386
  else f"{self.base_url}/agentengine/api/v1/{action}"
379
387
  )
@@ -394,7 +402,9 @@ class AgentEngineClient:
394
402
  if self._http_error_log_suppressors:
395
403
  self._http_error_log_suppressors.pop()
396
404
 
397
- def _log_http_error(self, *, method: str, full_url: str, status_code: int, details: Dict[str, Any]) -> None:
405
+ def _log_http_error(
406
+ self, *, method: str, full_url: str, status_code: int, details: Dict[str, Any]
407
+ ) -> None:
398
408
  for suppressor in reversed(self._http_error_log_suppressors):
399
409
  try:
400
410
  if suppressor(
@@ -433,7 +443,9 @@ class AgentEngineClient:
433
443
  message = " ".join(message.split())[:200]
434
444
  return f"{code}: {message}" if code else message
435
445
 
436
- def _build_headers(self, request_id: str = "", action: str = "", kop_mode: bool = False) -> Dict[str, str]:
446
+ def _build_headers(
447
+ self, request_id: str = "", action: str = "", kop_mode: bool = False
448
+ ) -> Dict[str, str]:
437
449
  if not request_id:
438
450
  request_id = str(uuid.uuid4())
439
451
  headers = {
@@ -508,9 +520,7 @@ class AgentEngineClient:
508
520
  # dry-run 不联网,只读缓存
509
521
  self._resolved_identity = get_cached_identity(ak)
510
522
  else:
511
- self._resolved_identity = resolve_identity(
512
- access_key=ak, secret_key=sk
513
- )
523
+ self._resolved_identity = resolve_identity(access_key=ak, secret_key=sk)
514
524
  except Exception as e:
515
525
  logger.warning("反查子账号身份失败: %s", e)
516
526
  self._resolved_identity = None
@@ -536,9 +546,7 @@ class AgentEngineClient:
536
546
  access = params.get("Access") if isinstance(params, dict) else None
537
547
  if isinstance(access, dict):
538
548
  explicit_role = (
539
- access.get("IamRole")
540
- or access.get("iamRole")
541
- or access.get("iam_role")
549
+ access.get("IamRole") or access.get("iamRole") or access.get("iam_role")
542
550
  )
543
551
  if str(explicit_role or "").strip():
544
552
  return str(explicit_role).strip()
@@ -597,9 +605,9 @@ class AgentEngineClient:
597
605
  self._permission_probe_cache[cache_key] = True
598
606
 
599
607
  def _request(
600
- self,
608
+ self,
601
609
  method: str,
602
- path: str,
610
+ path: str,
603
611
  body: Optional[Dict[str, Any]] = None,
604
612
  *,
605
613
  ignore_dry_run: bool = False,
@@ -608,7 +616,7 @@ class AgentEngineClient:
608
616
  action = path.rstrip("/").split("/")[-1] if path else ""
609
617
  _kop_mode, headers, full_url = self._build_action_request_target(path, action)
610
618
  body_str = json.dumps(body, ensure_ascii=False) if body else ""
611
-
619
+
612
620
  # DryRun 模式
613
621
  if self.dry_run and not ignore_dry_run:
614
622
  signed_headers = headers
@@ -622,9 +630,9 @@ class AgentEngineClient:
622
630
  )
623
631
 
624
632
  # 生成 Curl 命令
625
- curl_cmd = f"curl -X {method} \"{full_url}\" \\\n"
633
+ curl_cmd = f'curl -X {method} "{full_url}" \\\n'
626
634
  for k, v in signed_headers.items():
627
- curl_cmd += f" -H \"{k}: {v}\" \\\n"
635
+ curl_cmd += f' -H "{k}: {v}" \\\n'
628
636
  if body_str:
629
637
  curl_cmd += f" -d '{body_str}'"
630
638
 
@@ -639,7 +647,7 @@ class AgentEngineClient:
639
647
  "curl": curl_cmd,
640
648
  },
641
649
  )
642
-
650
+
643
651
  session = self._get_session()
644
652
 
645
653
  retried_inner_endpoint = False
@@ -685,31 +693,36 @@ class AgentEngineClient:
685
693
 
686
694
  if response.text:
687
695
  try:
688
- return response.json()
696
+ payload = response.json()
689
697
  except Exception as e:
690
698
  raise Exception(f"Invalid JSON response from {full_url}: {response.text}") from e
699
+ if not isinstance(payload, dict):
700
+ raise Exception(f"Invalid JSON response from {full_url}: expected an object")
701
+ return payload
691
702
  return {}
692
-
703
+
693
704
  # Async 包装 (保持兼容性)
694
705
  async def close(self):
695
706
  if self._session:
696
707
  self._session.close()
697
708
  self._session = None
698
-
709
+
699
710
  async def __aenter__(self):
700
711
  return self
701
-
712
+
702
713
  async def __aexit__(self, exc_type, exc_val, exc_tb):
703
714
  await self.close()
704
715
 
705
716
  # ===== Action API (推荐使用) =====
706
-
717
+
707
718
  @staticmethod
708
719
  def _pascal_key(key: str) -> str:
709
720
  """PascalCase/camelCase 键名转 snake_case"""
710
721
  # "MCPs" -> "mcps", "AgentId" -> "agent_id", "QuickAccess" -> "quick_access"
711
- s1 = re.sub('([A-Z]+)([A-Z][a-z])', r'\1_\2', key)
712
- s2 = re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1)
722
+ if re.fullmatch(r"[A-Z]+s", key):
723
+ return key.lower()
724
+ s1 = re.sub("([A-Z]+)([A-Z][a-z])", r"\1_\2", key)
725
+ s2 = re.sub("([a-z0-9])([A-Z])", r"\1_\2", s1)
713
726
  return s2.lower()
714
727
 
715
728
  @classmethod
@@ -747,7 +760,7 @@ class AgentEngineClient:
747
760
  image = raw
748
761
  for prefix in ("http://", "https://"):
749
762
  if image.startswith(prefix):
750
- image = image[len(prefix):]
763
+ image = image[len(prefix) :]
751
764
  break
752
765
 
753
766
  image_no_tag = image
@@ -798,9 +811,8 @@ class AgentEngineClient:
798
811
  img_ns, img_repo, img_ver = cls._parse_container_image_ref(artifact)
799
812
 
800
813
  inferred_enterprise_instance = cls._enterprise_instance_from_image_ref(artifact)
801
- image_type = (
802
- container.get("image_type")
803
- or ("Enterprise" if inferred_enterprise_instance else "Personal")
814
+ image_type = container.get("image_type") or (
815
+ "Enterprise" if inferred_enterprise_instance else "Personal"
804
816
  )
805
817
  params: Dict[str, Any] = {
806
818
  "ImageType": image_type,
@@ -860,14 +872,13 @@ class AgentEngineClient:
860
872
  if not isinstance(detail, dict):
861
873
  return {}
862
874
 
863
- basic = detail.get("basic") if isinstance(detail.get("basic"), dict) else {}
864
- quick = detail.get("quick_access") if isinstance(detail.get("quick_access"), dict) else {}
865
- deployment = detail.get("deployment") if isinstance(detail.get("deployment"), dict) else {}
866
- framework = (
867
- deployment.get("framework")
868
- or basic.get("framework")
869
- or detail.get("framework")
870
- )
875
+ basic_value = detail.get("basic")
876
+ quick_value = detail.get("quick_access")
877
+ deployment_value = detail.get("deployment")
878
+ basic: Dict[str, Any] = basic_value if isinstance(basic_value, dict) else {}
879
+ quick: Dict[str, Any] = quick_value if isinstance(quick_value, dict) else {}
880
+ deployment: Dict[str, Any] = deployment_value if isinstance(deployment_value, dict) else {}
881
+ framework = deployment.get("framework") or basic.get("framework") or detail.get("framework")
871
882
  return {
872
883
  "agent_id": basic.get("agent_id") or detail.get("agent_id"),
873
884
  "name": basic.get("name") or detail.get("name"),
@@ -896,18 +907,13 @@ class AgentEngineClient:
896
907
  payload = None
897
908
  if isinstance(payload, dict):
898
909
  message = (
899
- str(payload.get("detail") or payload.get("Message") or message).strip()
900
- or message
910
+ str(payload.get("detail") or payload.get("Message") or message).strip() or message
901
911
  )
902
912
  return AgentEngineAPIError(response.status_code, message)
903
913
 
904
914
  @staticmethod
905
915
  def _compact_params(params: Dict[str, Any] | None) -> Dict[str, Any]:
906
- return {
907
- key: value
908
- for key, value in (params or {}).items()
909
- if value is not None
910
- }
916
+ return {key: value for key, value in (params or {}).items() if value is not None}
911
917
 
912
918
  @staticmethod
913
919
  def _workspace_prefers_action_proxy(detail: Dict[str, Any] | None) -> bool:
@@ -938,13 +944,15 @@ class AgentEngineClient:
938
944
  },
939
945
  }
940
946
 
941
- detail = await self.get_agent(agent_id=agent_id, name=name, include_api_key=True)
947
+ detail = await self.get_agent(
948
+ agent_id=agent_id,
949
+ name=name,
950
+ include_api_key=True,
951
+ )
942
952
  access = self._extract_runtime_access(detail)
943
953
  resolved_agent_id = str(access.get("agent_id") or agent_id or "").strip() or None
944
954
  resolved_name = str(access.get("name") or name or "").strip() or None
945
- resolved_api_key = api_key_value or (
946
- str(access.get("api_key") or "").strip() or None
947
- )
955
+ resolved_api_key = api_key_value or (str(access.get("api_key") or "").strip() or None)
948
956
  if self._workspace_prefers_action_proxy(detail):
949
957
  return {
950
958
  "mode": "action",
@@ -1039,8 +1047,13 @@ class AgentEngineClient:
1039
1047
  api_key=api_key,
1040
1048
  )
1041
1049
  if transport["mode"] != "runtime":
1042
- raise AgentEngineAPIError(400, "Workspace runtime direct access is unavailable for this agent")
1043
- return transport["access"]
1050
+ raise AgentEngineAPIError(
1051
+ 400, "Workspace runtime direct access is unavailable for this agent"
1052
+ )
1053
+ access = transport.get("access")
1054
+ if not isinstance(access, dict):
1055
+ raise AgentEngineAPIError(502, "Workspace runtime access payload is invalid")
1056
+ return access
1044
1057
 
1045
1058
  def _workspace_runtime_request(
1046
1059
  self,
@@ -1075,8 +1088,7 @@ class AgentEngineClient:
1075
1088
  payload = response.json()
1076
1089
  except Exception as exc:
1077
1090
  url = str(
1078
- getattr(response, "_ksadk_workspace_url", "")
1079
- or getattr(response, "url", "")
1091
+ getattr(response, "_ksadk_workspace_url", "") or getattr(response, "url", "")
1080
1092
  ).strip()
1081
1093
  body = (response.text or "").strip()
1082
1094
  body_preview = body[:200] if body else "<empty response body>"
@@ -1093,10 +1105,15 @@ class AgentEngineClient:
1093
1105
  "workspace_runtime_body_preview": body_preview,
1094
1106
  },
1095
1107
  ) from exc
1096
- return self._to_snake_case(payload)
1108
+ normalized = self._to_snake_case(payload)
1109
+ if not isinstance(normalized, dict):
1110
+ raise AgentEngineAPIError(502, "workspace runtime returned a non-object JSON payload")
1111
+ return normalized
1097
1112
 
1098
1113
  @staticmethod
1099
- def _annotate_workspace_payload(payload: Dict[str, Any], *, transport_mode: str) -> Dict[str, Any]:
1114
+ def _annotate_workspace_payload(
1115
+ payload: Dict[str, Any], *, transport_mode: str
1116
+ ) -> Dict[str, Any]:
1100
1117
  annotated = dict(payload or {})
1101
1118
  annotated["transport_mode"] = transport_mode
1102
1119
  return annotated
@@ -1117,7 +1134,7 @@ class AgentEngineClient:
1117
1134
  def _action(
1118
1135
  self,
1119
1136
  action: str,
1120
- params: Dict[str, Any] = None,
1137
+ params: Optional[Dict[str, Any]] = None,
1121
1138
  *,
1122
1139
  ignore_dry_run: bool = False,
1123
1140
  ) -> Dict[str, Any]:
@@ -1126,24 +1143,31 @@ class AgentEngineClient:
1126
1143
  self._maybe_precheck_permission(action, body)
1127
1144
  request_kwargs = {"ignore_dry_run": True} if ignore_dry_run else {}
1128
1145
  result = self._request("POST", f"/agentengine/api/v1/{action}", body, **request_kwargs)
1129
-
1146
+
1130
1147
  # 检查错误 (统一返回格式 {"Code": 0, ...})
1131
1148
  code = result.get("Code", 0)
1132
1149
  if code != 0:
1133
1150
  msg = result.get("Message", "Unknown API error")
1134
- raise AgentEngineAPIError(code=code, message=msg)
1135
-
1151
+ details = {}
1152
+ if result.get("RequestId"):
1153
+ details["request_id"] = str(result["RequestId"])
1154
+ if result.get("Action"):
1155
+ details["action"] = str(result["Action"])
1156
+ raise AgentEngineAPIError(code=code, message=msg, details=details)
1157
+
1136
1158
  if result.get("Error"):
1137
1159
  raise Exception(result["Error"].get("Message", "Unknown error"))
1138
-
1160
+
1139
1161
  # 提取 Data 并统一转换为 snake_case
1140
1162
  data = result.get("Data") if result.get("Data") is not None else result
1141
1163
  data = self._to_snake_case(data)
1142
-
1164
+
1143
1165
  # 预发环境 endpoint 协议归一化: https -> http
1144
1166
  if self.logical_region and self.logical_region.strip().lower() == "pre-online":
1145
1167
  data = self._fix_endpoints_protocol(data)
1146
-
1168
+
1169
+ if not isinstance(data, dict):
1170
+ raise AgentEngineAPIError(502, "Action API returned a non-object payload")
1147
1171
  return data
1148
1172
 
1149
1173
  def download_attachment_content(self, file_uri: str) -> AttachmentContent:
@@ -1182,7 +1206,12 @@ class AgentEngineClient:
1182
1206
 
1183
1207
  payload: Dict[str, Any] = {
1184
1208
  "EnablePublicAccess": bool(
1185
- _pick("enable_public_access", "enablePublicAccess", "EnablePublicAccess", default=False)
1209
+ _pick(
1210
+ "enable_public_access",
1211
+ "enablePublicAccess",
1212
+ "EnablePublicAccess",
1213
+ default=False,
1214
+ )
1186
1215
  ),
1187
1216
  "EnableVpcAccess": bool(
1188
1217
  _pick("enable_vpc_access", "enableVpcAccess", "EnableVpcAccess", default=False)
@@ -1203,7 +1232,9 @@ class AgentEngineClient:
1203
1232
  return payload
1204
1233
 
1205
1234
  @staticmethod
1206
- def _normalize_ui_config_payload(ui_config: Optional[Dict[str, Any]]) -> Optional[Dict[str, Any]]:
1235
+ def _normalize_ui_config_payload(
1236
+ ui_config: Optional[Dict[str, Any]],
1237
+ ) -> Optional[Dict[str, Any]]:
1207
1238
  if not isinstance(ui_config, dict):
1208
1239
  return None
1209
1240
 
@@ -1234,10 +1265,7 @@ class AgentEngineClient:
1234
1265
  return None
1235
1266
 
1236
1267
  mount_path = str(
1237
- storage.get("mount_path")
1238
- or storage.get("mountPath")
1239
- or storage.get("MountPath")
1240
- or ""
1268
+ storage.get("mount_path") or storage.get("mountPath") or storage.get("MountPath") or ""
1241
1269
  ).strip()
1242
1270
  size_gi = storage.get("size_gi", storage.get("sizeGi", storage.get("SizeGi")))
1243
1271
  if not mount_path and size_gi is None:
@@ -1251,14 +1279,14 @@ class AgentEngineClient:
1251
1279
  return payload
1252
1280
 
1253
1281
  @staticmethod
1254
- def _normalize_memory_config_payload(memory_config: Optional[Dict[str, Any]]) -> Optional[Dict[str, Any]]:
1282
+ def _normalize_memory_config_payload(
1283
+ memory_config: Optional[Dict[str, Any]],
1284
+ ) -> Optional[Dict[str, Any]]:
1255
1285
  if not isinstance(memory_config, dict):
1256
1286
  return None
1257
1287
 
1258
1288
  memory_system = str(
1259
- memory_config.get("memory_system")
1260
- or memory_config.get("MemorySystem")
1261
- or ""
1289
+ memory_config.get("memory_system") or memory_config.get("MemorySystem") or ""
1262
1290
  ).strip()
1263
1291
  if not memory_system:
1264
1292
  return None
@@ -1268,17 +1296,12 @@ class AgentEngineClient:
1268
1296
  }
1269
1297
  field_mapping = {
1270
1298
  "Mem0InstanceId": (
1271
- memory_config.get("mem0_instance_id")
1272
- or memory_config.get("Mem0InstanceId")
1299
+ memory_config.get("mem0_instance_id") or memory_config.get("Mem0InstanceId")
1273
1300
  ),
1274
1301
  "Mem0InstanceName": (
1275
- memory_config.get("mem0_instance_name")
1276
- or memory_config.get("Mem0InstanceName")
1277
- ),
1278
- "Mem0Region": (
1279
- memory_config.get("mem0_region")
1280
- or memory_config.get("Mem0Region")
1302
+ memory_config.get("mem0_instance_name") or memory_config.get("Mem0InstanceName")
1281
1303
  ),
1304
+ "Mem0Region": (memory_config.get("mem0_region") or memory_config.get("Mem0Region")),
1282
1305
  }
1283
1306
  for key, value in field_mapping.items():
1284
1307
  text = str(value or "").strip()
@@ -1297,7 +1320,9 @@ class AgentEngineClient:
1297
1320
  "Region": self._normalize_payload_region(data.get("region", "cn-beijing-6")),
1298
1321
  "Resource": {
1299
1322
  "Cpu": int(float(data.get("resources", {}).get("cpu", 2))),
1300
- "Memory": int(str(data.get("resources", {}).get("memory", "4Gi")).replace("Gi", ""))
1323
+ "Memory": int(
1324
+ str(data.get("resources", {}).get("memory", "4Gi")).replace("Gi", "")
1325
+ ),
1301
1326
  },
1302
1327
  "Scaling": {
1303
1328
  "MinReplicas": int(data.get("scaling", {}).get("min_replicas", 1)),
@@ -1331,7 +1356,7 @@ class AgentEngineClient:
1331
1356
  "IamRole": data.get("iam_role", "KsyunAgentEngineDefaultRole"),
1332
1357
  }
1333
1358
 
1334
- if params["DeploymentType"] == "Code":
1359
+ if params["DeploymentType"] in {"Code", "ManagedRuntime"}:
1335
1360
  ks3 = data.get("ks3", {})
1336
1361
  params["CodeConfig"] = {
1337
1362
  "Path": data.get("artifact_path", ""),
@@ -1340,6 +1365,13 @@ class AgentEngineClient:
1340
1365
  "Region": self._normalize_payload_region(ks3.get("region", "cn-beijing-6")),
1341
1366
  "Bucket": ks3.get("bucket"),
1342
1367
  }
1368
+ if params["DeploymentType"] == "ManagedRuntime":
1369
+ runtime_config = data.get("runtime_config") or {}
1370
+ params["RuntimeConfig"] = {
1371
+ "Name": runtime_config.get("name"),
1372
+ "Version": runtime_config.get("version"),
1373
+ "ManifestSha256": runtime_config.get("manifest_sha256"),
1374
+ }
1343
1375
  else:
1344
1376
  ic = data.get("image_credential", {}) or {}
1345
1377
  artifact = (data.get("artifact_path", "") or "").strip()
@@ -1371,7 +1403,12 @@ class AgentEngineClient:
1371
1403
 
1372
1404
  return self._action("CreateAgentProduct", params)
1373
1405
 
1374
- async def get_agent(self, agent_id: str = None, name: str = None, include_api_key: bool = False) -> Dict[str, Any]:
1406
+ async def get_agent(
1407
+ self,
1408
+ agent_id: Optional[str] = None,
1409
+ name: Optional[str] = None,
1410
+ include_api_key: bool = False,
1411
+ ) -> Dict[str, Any]:
1375
1412
  """获取 Agent 详情(支持 AgentId 或 Name 查询)"""
1376
1413
  if agent_id:
1377
1414
  params: Dict[str, Any] = {"AgentId": agent_id}
@@ -1382,7 +1419,7 @@ class AgentEngineClient:
1382
1419
  except Exception as e:
1383
1420
  # 兼容旧控制面:极少数版本仍使用 Id 字段
1384
1421
  if self._should_fallback_get_agent_with_legacy_id(e):
1385
- fallback = {"Id": agent_id}
1422
+ fallback: Dict[str, Any] = {"Id": agent_id}
1386
1423
  if include_api_key:
1387
1424
  fallback["IncludeApiKey"] = True
1388
1425
  return self._action("GetAgent", fallback)
@@ -1512,7 +1549,7 @@ class AgentEngineClient:
1512
1549
  async def delete_dashboard_access_link(self, *, link_id: str) -> Dict[str, Any]:
1513
1550
  """删除 Dashboard 短链接。"""
1514
1551
  return self._action("DeleteDashboardAccessLink", {"LinkId": link_id})
1515
-
1552
+
1516
1553
  async def list_agents(
1517
1554
  self,
1518
1555
  region: Optional[str] = None,
@@ -1595,17 +1632,18 @@ class AgentEngineClient:
1595
1632
  self._action("DeleteAgent", {"AgentId": agent_id})
1596
1633
  return True
1597
1634
 
1598
-
1599
-
1600
1635
  async def update_agent(self, agent_id: str, data: Dict[str, Any]) -> Dict[str, Any]:
1601
1636
  """更新 Agent (热更新)"""
1602
- params = {"AgentId": agent_id}
1637
+ params: Dict[str, Any] = {"AgentId": agent_id}
1638
+ artifact_type = data.get("artifact_type")
1639
+ if artifact_type:
1640
+ params["DeploymentType"] = artifact_type
1603
1641
  if data.get("description"):
1604
1642
  params["Description"] = data["description"]
1605
-
1643
+
1606
1644
  if data.get("artifact_path"):
1607
1645
  artifact = (data.get("artifact_path", "") or "").strip()
1608
- if (data.get("artifact_type") or "").lower() == "container":
1646
+ if (artifact_type or "").lower() == "container":
1609
1647
  ic = data.get("image_credential", {}) or {}
1610
1648
  params["ContainerConfig"] = self._build_container_config_payload(
1611
1649
  artifact=artifact,
@@ -1620,20 +1658,27 @@ class AgentEngineClient:
1620
1658
  "Region": self._normalize_payload_region(ks3.get("region", "cn-beijing-6")),
1621
1659
  "Bucket": ks3.get("bucket"),
1622
1660
  }
1623
-
1661
+ if artifact_type == "ManagedRuntime":
1662
+ runtime_config = data.get("runtime_config") or {}
1663
+ params["RuntimeConfig"] = {
1664
+ "Name": runtime_config.get("name"),
1665
+ "Version": runtime_config.get("version"),
1666
+ "ManifestSha256": runtime_config.get("manifest_sha256"),
1667
+ }
1668
+
1624
1669
  if data.get("resources"):
1625
1670
  params["Resource"] = {
1626
1671
  "Cpu": int(float(data["resources"].get("cpu", 2))),
1627
- "Memory": int(str(data["resources"].get("memory", "4Gi")).replace("Gi", ""))
1672
+ "Memory": int(str(data["resources"].get("memory", "4Gi")).replace("Gi", "")),
1628
1673
  }
1629
-
1674
+
1630
1675
  if data.get("scaling"):
1631
1676
  params["Scaling"] = {
1632
1677
  "MinReplicas": int(data["scaling"].get("min_replicas", 1)),
1633
1678
  "MaxReplicas": int(data["scaling"].get("max_replicas", 10)),
1634
1679
  "Concurrency": int(data["scaling"].get("concurrency", 20)),
1635
1680
  }
1636
-
1681
+
1637
1682
  envs = data.get("env_vars") or data.get("environment_variables")
1638
1683
  if envs:
1639
1684
  env_vars = []
@@ -1683,27 +1728,27 @@ class AgentEngineClient:
1683
1728
  advanced["ProjectId"] = project_id
1684
1729
  if advanced:
1685
1730
  params["Advanced"] = advanced
1686
-
1731
+
1687
1732
  return self._action("UpdateAgent", params)
1688
1733
 
1689
1734
  # ===== Session Actions =====
1690
-
1691
- async def create_session(self, agent_id: str, user_id: Optional[str] = None, expires_hours: int = 24) -> Dict[str, Any]:
1735
+
1736
+ async def create_session(
1737
+ self, agent_id: str, user_id: Optional[str] = None, expires_hours: int = 24
1738
+ ) -> Dict[str, Any]:
1692
1739
  """创建会话"""
1693
- return self._action("CreateSession", {
1694
- "AgentId": agent_id,
1695
- "UserId": user_id,
1696
- "ExpiresHours": expires_hours
1697
- })
1698
-
1740
+ return self._action(
1741
+ "CreateSession", {"AgentId": agent_id, "UserId": user_id, "ExpiresHours": expires_hours}
1742
+ )
1743
+
1699
1744
  async def get_session(self, session_id: str) -> Dict[str, Any]:
1700
1745
  """获取会话详情"""
1701
1746
  return self._action("GetSession", {"Id": session_id})
1702
-
1747
+
1703
1748
  async def list_sessions(self, agent_id: str, page: int = 1, size: int = 20) -> Dict[str, Any]:
1704
1749
  """列出会话"""
1705
1750
  return self._action("ListSessions", {"AgentId": agent_id, "Page": page, "PageSize": size})
1706
-
1751
+
1707
1752
  async def delete_session(self, session_id: str) -> bool:
1708
1753
  """删除会话"""
1709
1754
  try:
@@ -1866,14 +1911,14 @@ class AgentEngineClient:
1866
1911
  },
1867
1912
  accept="application/octet-stream",
1868
1913
  )
1869
- return response.content
1914
+ return bytes(response.content)
1870
1915
  access = transport["access"]
1871
1916
  response = self._workspace_runtime_request(
1872
1917
  access=access,
1873
1918
  method="GET",
1874
1919
  path=f"files/{self._encode_workspace_runtime_path(remote_path)}",
1875
1920
  )
1876
- return response.content
1921
+ return bytes(response.content)
1877
1922
 
1878
1923
  async def delete_workspace_file(
1879
1924
  self,
@@ -1944,13 +1989,17 @@ class AgentEngineClient:
1944
1989
  return int(float(raw))
1945
1990
 
1946
1991
  @staticmethod
1947
- def _normalize_mcp_deployment_type(value: Optional[str], default: Optional[str] = None) -> Optional[str]:
1992
+ def _normalize_mcp_deployment_type(
1993
+ value: Optional[str], default: Optional[str] = None
1994
+ ) -> Optional[str]:
1948
1995
  raw = str(value or default or "").strip()
1949
1996
  if not raw:
1950
1997
  return None
1951
1998
  return "Container" if raw.lower() == "container" else "Code"
1952
1999
 
1953
- def _infer_mcp_deployment_type(self, data: Dict[str, Any], default: Optional[str] = None) -> Optional[str]:
2000
+ def _infer_mcp_deployment_type(
2001
+ self, data: Dict[str, Any], default: Optional[str] = None
2002
+ ) -> Optional[str]:
1954
2003
  explicit = self._normalize_mcp_deployment_type(
1955
2004
  data.get("deployment_type") or data.get("artifact_type"),
1956
2005
  default=default,
@@ -2018,11 +2067,14 @@ class AgentEngineClient:
2018
2067
  async def create_mcp(self, data: Dict[str, Any]) -> Dict[str, Any]:
2019
2068
  """创建 MCP"""
2020
2069
  if self._looks_like_nested_mcp_payload(data):
2021
- params = dict(data)
2022
- params["Region"] = self._normalize_payload_region(
2023
- params.get("Region") or data.get("region") or self.logical_region or "cn-beijing-6"
2070
+ nested_params = dict(data)
2071
+ nested_params["Region"] = self._normalize_payload_region(
2072
+ nested_params.get("Region")
2073
+ or data.get("region")
2074
+ or self.logical_region
2075
+ or "cn-beijing-6"
2024
2076
  )
2025
- return self._action("CreateMCP", params)
2077
+ return self._action("CreateMCP", nested_params)
2026
2078
 
2027
2079
  deployment_type = self._infer_mcp_deployment_type(data, default="Code") or "Code"
2028
2080
  params: Dict[str, Any] = {
@@ -2043,11 +2095,11 @@ class AgentEngineClient:
2043
2095
  if network_payload:
2044
2096
  params["Network"] = network_payload
2045
2097
  return self._action("CreateMCP", params)
2046
-
2098
+
2047
2099
  async def get_mcp(self, mcp_id: str) -> Dict[str, Any]:
2048
2100
  """获取 MCP 详情"""
2049
2101
  return self._action("GetMCP", {"Id": mcp_id})
2050
-
2102
+
2051
2103
  async def list_mcps(
2052
2104
  self,
2053
2105
  region: Optional[str] = None,
@@ -2055,24 +2107,23 @@ class AgentEngineClient:
2055
2107
  page_size: int = 20,
2056
2108
  ) -> Dict[str, Any]:
2057
2109
  """列出 MCP (注册中心)"""
2058
- params = {"Page": int(page), "PageSize": int(page_size)}
2110
+ params: Dict[str, Any] = {"Page": int(page), "PageSize": int(page_size)}
2059
2111
  if region:
2060
2112
  params["Region"] = self._normalize_payload_region(region)
2061
2113
  result = self._action("ListMCPs", params)
2062
- # _action 已统一转 snake_case: "MCPs" -> "m_c_ps"...
2063
- # 实际上 MCPs -> mcps, Total -> total
2114
+ # _action 已统一转 snake_case: MCPs -> mcps, Total -> total
2064
2115
  return {"mcps": result.get("mcps", []), "total": result.get("total", 0)}
2065
-
2116
+
2066
2117
  async def update_mcp(self, mcp_id: str, data: Dict[str, Any]) -> Dict[str, Any]:
2067
2118
  """更新 MCP (热更新)"""
2068
2119
  if self._looks_like_nested_mcp_payload(data):
2069
- params = dict(data)
2070
- params.setdefault("Id", mcp_id)
2071
- if "Region" in params or data.get("region") or self.logical_region:
2072
- params["Region"] = self._normalize_payload_region(
2073
- params.get("Region") or data.get("region") or self.logical_region
2120
+ nested_params = dict(data)
2121
+ nested_params.setdefault("Id", mcp_id)
2122
+ if "Region" in nested_params or data.get("region") or self.logical_region:
2123
+ nested_params["Region"] = self._normalize_payload_region(
2124
+ nested_params.get("Region") or data.get("region") or self.logical_region
2074
2125
  )
2075
- return self._action("UpdateMCP", params)
2126
+ return self._action("UpdateMCP", nested_params)
2076
2127
 
2077
2128
  params: Dict[str, Any] = {"Id": mcp_id}
2078
2129
  deployment_type = self._infer_mcp_deployment_type(data)
@@ -2096,7 +2147,9 @@ class AgentEngineClient:
2096
2147
  }
2097
2148
 
2098
2149
  scaling = data.get("scaling", {}) or {}
2099
- if any(scaling.get(key) is not None for key in ("min_replicas", "max_replicas", "concurrency")):
2150
+ if any(
2151
+ scaling.get(key) is not None for key in ("min_replicas", "max_replicas", "concurrency")
2152
+ ):
2100
2153
  params["Scaling"] = {
2101
2154
  "MinReplicas": int(scaling.get("min_replicas", 1)),
2102
2155
  "MaxReplicas": int(scaling.get("max_replicas", 5)),
@@ -2119,16 +2172,15 @@ class AgentEngineClient:
2119
2172
  if data.get("region") is not None:
2120
2173
  params["Region"] = self._normalize_payload_region(data.get("region"))
2121
2174
  return self._action("UpdateMCP", params)
2122
-
2175
+
2123
2176
  async def delete_mcp(self, mcp_id: str) -> bool:
2124
2177
  """删除 MCP"""
2125
- try:
2126
- self._action("DeleteMCP", {"Id": mcp_id})
2127
- return True
2128
- except Exception:
2129
- return False
2130
-
2131
- async def get_mcp_by_name(self, name: str, region: Optional[str] = None) -> Optional[Dict[str, Any]]:
2178
+ result = self._action("DeleteMCP", {"Id": mcp_id})
2179
+ return bool(result.get("deleted"))
2180
+
2181
+ async def get_mcp_by_name(
2182
+ self, name: str, region: Optional[str] = None
2183
+ ) -> Optional[Dict[str, Any]]:
2132
2184
  """按名称查询 MCP"""
2133
2185
  # 使用 ListMCPs 然后过滤 (Action API 暂不支持 by-name)
2134
2186
  try:
@@ -2138,7 +2190,7 @@ class AgentEngineClient:
2138
2190
  result = await self.list_mcps(region=region, page=page, page_size=page_size)
2139
2191
  mcps = result.get("mcps", [])
2140
2192
  for mcp in mcps:
2141
- if mcp.get("name") == name:
2193
+ if isinstance(mcp, dict) and mcp.get("name") == name:
2142
2194
  return mcp
2143
2195
  if len(mcps) < page_size:
2144
2196
  break
@@ -2148,39 +2200,38 @@ class AgentEngineClient:
2148
2200
  return None
2149
2201
 
2150
2202
  # ===== Upload Actions =====
2151
-
2203
+
2152
2204
  async def get_presigned_url(self, filename: str) -> Dict[str, Any]:
2153
2205
  """获取 KS3 预签名上传 URL"""
2154
2206
  return self._action("GetPresignedUrl", {"Filename": filename})
2155
2207
 
2156
2208
  # ===== Chat Actions =====
2157
-
2158
- async def chat(self, agent_id: str, message: str, session_id: Optional[str] = None) -> Dict[str, Any]:
2209
+
2210
+ async def chat(
2211
+ self, agent_id: str, message: str, session_id: Optional[str] = None
2212
+ ) -> Dict[str, Any]:
2159
2213
  """调用 Agent"""
2160
2214
  params = {
2161
2215
  "AgentId": agent_id,
2162
2216
  "Messages": [{"role": "user", "content": message}],
2163
- "Stream": False
2217
+ "Stream": False,
2164
2218
  }
2165
2219
  if session_id:
2166
2220
  params["SessionId"] = session_id
2167
2221
  return self._action("RunAgent", params)
2168
2222
 
2169
2223
  # ===== Version Actions =====
2170
-
2224
+
2171
2225
  async def release_version(
2172
- self,
2173
- agent_id: str,
2174
- tag: Optional[str] = None,
2175
- description: Optional[str] = None
2226
+ self, agent_id: str, tag: Optional[str] = None, description: Optional[str] = None
2176
2227
  ) -> Dict[str, Any]:
2177
2228
  """发布新版本
2178
-
2229
+
2179
2230
  Args:
2180
2231
  agent_id: Agent ID
2181
2232
  tag: 版本标签,不填则自动生成
2182
2233
  description: 版本描述
2183
-
2234
+
2184
2235
  Returns:
2185
2236
  版本信息
2186
2237
  """
@@ -2190,46 +2241,37 @@ class AgentEngineClient:
2190
2241
  if description:
2191
2242
  params["Description"] = description
2192
2243
  return self._action("CreateVersion", params)
2193
-
2194
- async def list_versions(
2195
- self,
2196
- agent_id: str,
2197
- page: int = 1,
2198
- size: int = 10
2199
- ) -> Dict[str, Any]:
2244
+
2245
+ async def list_versions(self, agent_id: str, page: int = 1, size: int = 10) -> Dict[str, Any]:
2200
2246
  """列出版本历史
2201
-
2247
+
2202
2248
  Args:
2203
2249
  agent_id: Agent ID
2204
2250
  page: 页码
2205
2251
  size: 每页数量
2206
-
2252
+
2207
2253
  Returns:
2208
2254
  版本列表和分页信息
2209
2255
  """
2210
- return self._action("ListVersions", {
2211
- "AgentId": agent_id,
2212
- "Page": page,
2213
- "PageSize": size
2214
- })
2215
-
2256
+ return self._action("ListVersions", {"AgentId": agent_id, "Page": page, "PageSize": size})
2257
+
2216
2258
  async def rollback_version(
2217
- self,
2218
- agent_id: str,
2259
+ self,
2260
+ agent_id: str,
2219
2261
  target_version_id: Optional[str] = None,
2220
2262
  target_tag: Optional[str] = None,
2221
2263
  ks3_access_key: Optional[str] = None,
2222
2264
  ks3_secret_key: Optional[str] = None,
2223
2265
  ) -> Dict[str, Any]:
2224
2266
  """回滚到指定版本
2225
-
2267
+
2226
2268
  Args:
2227
2269
  agent_id: Agent ID
2228
2270
  target_version_id: 目标版本 ID(与 target_tag 二选一)
2229
2271
  target_tag: 目标版本标签(与 target_version_id 二选一)
2230
2272
  ks3_access_key: KS3 Access Key (可选)
2231
2273
  ks3_secret_key: KS3 Secret Key (可选)
2232
-
2274
+
2233
2275
  Returns:
2234
2276
  回滚结果
2235
2277
  """
@@ -2242,5 +2284,5 @@ class AgentEngineClient:
2242
2284
  params["KS3AccessKey"] = ks3_access_key
2243
2285
  if ks3_secret_key:
2244
2286
  params["KS3SecretKey"] = ks3_secret_key
2245
-
2287
+
2246
2288
  return self._action("RollbackVersion", params)