agentengine-sdk-python 0.6.9__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 (384) hide show
  1. {agentengine_sdk_python-0.6.9.dist-info → agentengine_sdk_python-0.8.0.dist-info}/METADATA +41 -23
  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 +252 -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 +533 -726
  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 +173 -90
  54. ksadk/cli/cmd_invoke.py +388 -159
  55. ksadk/cli/cmd_launch.py +64 -28
  56. ksadk/cli/cmd_mcp.py +103 -64
  57. ksadk/cli/cmd_model.py +14 -5
  58. ksadk/cli/cmd_openclaw.py +488 -228
  59. ksadk/cli/cmd_replay.py +71 -0
  60. ksadk/cli/cmd_run.py +44 -14
  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 +38 -16
  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 +501 -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 +656 -0
  97. ksadk/conversations/model_context.py +22 -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 -5187
  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 +52 -39
  120. ksadk/deployment/manager.py +63 -65
  121. ksadk/deployment/providers/serverless.py +326 -209
  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 +267 -0
  156. ksadk/memory/adk/short_term_memory.py +33 -27
  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 +1248 -164
  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 -530
  183. ksadk/runners/langgraph_runner.py +490 -95
  184. ksadk/runners/patch_langchain.py +16 -16
  185. ksadk/runners/remote_runner.py +264 -38
  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 -3743
  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-C0meuOdi.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-bj2rZnP5.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-2u1ltDIj.js → architectureDiagram-3BPJPVTR-Dej8jX8c.js} +1 -1
  229. ksadk/server/static/assets/{blockDiagram-GPEHLZMM-D6fvdK20.js → blockDiagram-GPEHLZMM-1F64jqvy.js} +1 -1
  230. ksadk/server/static/assets/{c4Diagram-AAUBKEIU-BK82L5n5.js → c4Diagram-AAUBKEIU-9q7AUAKb.js} +1 -1
  231. ksadk/server/static/assets/channel-iUGv2N24.js +1 -0
  232. ksadk/server/static/assets/{chunk-2J33WTMH-DLVdkeyQ.js → chunk-2J33WTMH-6qgwJm7Q.js} +1 -1
  233. ksadk/server/static/assets/{chunk-4BX2VUAB-BbwsYcbW.js → chunk-4BX2VUAB-CsWIQRhc.js} +1 -1
  234. ksadk/server/static/assets/{chunk-55IACEB6-DOairxzw.js → chunk-55IACEB6-BK8paA20.js} +1 -1
  235. ksadk/server/static/assets/{chunk-727SXJPM-hCO487gs.js → chunk-727SXJPM-B-JEhy7h.js} +1 -1
  236. ksadk/server/static/assets/{chunk-AQP2D5EJ-XU8vDOuG.js → chunk-AQP2D5EJ-DYBvMHAa.js} +1 -1
  237. ksadk/server/static/assets/{chunk-FMBD7UC4-PrapyfMu.js → chunk-FMBD7UC4-BGhvzDYt.js} +1 -1
  238. ksadk/server/static/assets/{chunk-ND2GUHAM-CboKhTZ3.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-_N8bJ-EU.js → cose-bilkent-S5V4N54A-CX3yotHq.js} +1 -1
  243. ksadk/server/static/assets/{dagre-BM42HDAG-FoDlo5J2.js → dagre-BM42HDAG-C7TguAWo.js} +1 -1
  244. ksadk/server/static/assets/{diagram-2AECGRRQ-BBp6ebBw.js → diagram-2AECGRRQ-Dd17_kws.js} +1 -1
  245. ksadk/server/static/assets/{diagram-5GNKFQAL-CqOvG1PR.js → diagram-5GNKFQAL-DVIClIil.js} +1 -1
  246. ksadk/server/static/assets/{diagram-KO2AKTUF-O9T3t6ba.js → diagram-KO2AKTUF-Df_3gYQa.js} +1 -1
  247. ksadk/server/static/assets/{diagram-LMA3HP47-CGG8ekBO.js → diagram-LMA3HP47-BhLk6ZtA.js} +1 -1
  248. ksadk/server/static/assets/{diagram-OG6HWLK6-4BmH1EEg.js → diagram-OG6HWLK6-D4GNGvuu.js} +1 -1
  249. ksadk/server/static/assets/{dist-CiZHB6ZW.js → dist-6CVKuTAe.js} +1 -1
  250. ksadk/server/static/assets/{dist-BMKM66B4.js → dist-BUHRxvDG.js} +1 -1
  251. ksadk/server/static/assets/{dist-CZ6C3x8B.js → dist-BZ9n9AjO.js} +1 -1
  252. ksadk/server/static/assets/{dist-DbaH3p5h.js → dist-BibcG1V9.js} +1 -1
  253. ksadk/server/static/assets/{dist-BVzcWa6D.js → dist-Bs-jQcRX.js} +1 -1
  254. ksadk/server/static/assets/{dist-D99wf6_X.js → dist-C2xjE7cO.js} +1 -1
  255. ksadk/server/static/assets/{dist-DLMjL01k.js → dist-C7-3jInC.js} +1 -1
  256. ksadk/server/static/assets/{dist-DI-oVAXw.js → dist-C99THtIA.js} +1 -1
  257. ksadk/server/static/assets/{dist-BkJjNih3.js → dist-CGcp2ex8.js} +1 -1
  258. ksadk/server/static/assets/{dist-D5JGcxBx.js → dist-CVQRZjPu.js} +1 -1
  259. ksadk/server/static/assets/{dist-CWiTDN_V.js → dist-Cf23NY4L.js} +1 -1
  260. ksadk/server/static/assets/{dist-DLeM1OCK.js → dist-CgF3fj15.js} +1 -1
  261. ksadk/server/static/assets/{dist-BmuTWcm7.js → dist-Cwt7koer.js} +1 -1
  262. ksadk/server/static/assets/{dist-C2DKRFVK.js → dist-D82mtD2s.js} +1 -1
  263. ksadk/server/static/assets/{dist-B67uF2uK.js → dist-DF06ORQo.js} +1 -1
  264. ksadk/server/static/assets/{dist-Cwhk4lwI.js → dist-DHn6nBzr.js} +1 -1
  265. ksadk/server/static/assets/{dist-S4klkK5W.js → dist-Djgl2wVZ.js} +1 -1
  266. ksadk/server/static/assets/{dist-DCpZrjaK.js → dist-DlzCRy0S.js} +1 -1
  267. ksadk/server/static/assets/{dist-Cp1_jKwf.js → dist-DqNnNFrw.js} +1 -1
  268. ksadk/server/static/assets/{dist-6kSZvCZh.js → dist-DyvYLMW9.js} +1 -1
  269. ksadk/server/static/assets/{dist-DM0rEQPk.js → dist-eoW6tZXA.js} +1 -1
  270. ksadk/server/static/assets/{dist-Bk1l05Ni.js → dist-ivOya1LD.js} +1 -1
  271. ksadk/server/static/assets/{erDiagram-TEJ5UH35-oJhaci7S.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-DtTmUan-.js → flowDiagram-I6XJVG4X-DGaJjGNJ.js} +1 -1
  274. ksadk/server/static/assets/{ganttDiagram-6RSMTGT7-BSsb_eij.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-BR5s6Pws.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-DYPc5cvh.js → infoDiagram-5YYISTIA-CYIIsb8y.js} +1 -1
  281. ksadk/server/static/assets/{ishikawaDiagram-YF4QCWOH-MoBdALDg.js → ishikawaDiagram-YF4QCWOH-DLOHGvWw.js} +1 -1
  282. ksadk/server/static/assets/{journeyDiagram-JHISSGLW-DgLiQT8l.js → journeyDiagram-JHISSGLW-BIzKeejT.js} +1 -1
  283. ksadk/server/static/assets/{kanban-definition-UN3LZRKU-CsFx112F.js → kanban-definition-UN3LZRKU-BWHoFSw2.js} +1 -1
  284. ksadk/server/static/assets/{katex-DRsiwpM2.js → katex-DATssjp1.js} +1 -1
  285. ksadk/server/static/assets/{linear-TNRQ5Orv.js → linear-CvMBw9cA.js} +1 -1
  286. ksadk/server/static/assets/{mermaid-parser.core-D2eMVOgo.js → mermaid-parser.core-mGAcEwcq.js} +2 -2
  287. ksadk/server/static/assets/{mindmap-definition-RKZ34NQL-BtByYFhL.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-DPnuCB8c.js → pieDiagram-4H26LBE5-By-ra07M.js} +1 -1
  291. ksadk/server/static/assets/{quadrantDiagram-W4KKPZXB-miFpCPv4.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-mjB_yYkW.js → requirementDiagram-4Y6WPE33-DpW90iu3.js} +1 -1
  294. ksadk/server/static/assets/{sankeyDiagram-5OEKKPKP-D7hSlZZZ.js → sankeyDiagram-5OEKKPKP-DpGa6EAV.js} +1 -1
  295. ksadk/server/static/assets/{sequenceDiagram-3UESZ5HK-D9Cx6hC3.js → sequenceDiagram-3UESZ5HK-NTKNGGe5.js} +1 -1
  296. ksadk/server/static/assets/{stateDiagram-AJRCARHV-D_zrg47o.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-CwSec0Wa.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-agCVobiF.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-TmrlhWNt.js → wardleyDiagram-YWT4CUSO-BR54GPmr.js} +1 -1
  304. ksadk/server/static/assets/{xychartDiagram-2RQKCTM6-DV71V-ah.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 +86 -40
  308. ksadk/sessions/base.py +31 -11
  309. ksadk/sessions/continuity.py +28 -5
  310. ksadk/sessions/in_memory.py +46 -2
  311. ksadk/sessions/local_service.py +148 -17
  312. ksadk/sessions/postgres_service.py +216 -35
  313. ksadk/sessions/resilience.py +52 -0
  314. ksadk/sessions/resilient.py +388 -0
  315. ksadk/skills/models.py +17 -5
  316. ksadk/skills/package_store.py +5 -2
  317. ksadk/skills/runtime/agent.py +20 -5
  318. ksadk/skills/runtime/artifacts.py +1 -5
  319. ksadk/skills/runtime/backends/e2b.py +10 -4
  320. ksadk/skills/runtime/backends/local.py +15 -3
  321. ksadk/skills/runtime/base.py +1 -2
  322. ksadk/skills/runtime/executor.py +10 -3
  323. ksadk/skills/runtime/factory.py +4 -2
  324. ksadk/skills/runtime/loader.py +1 -2
  325. ksadk/skills/runtime/registry.py +15 -10
  326. ksadk/skills/runtime/request.py +3 -1
  327. ksadk/skills/service_client.py +38 -17
  328. ksadk/skills/tool_defs.py +15 -10
  329. ksadk/terminal_exec_policy.py +3 -4
  330. ksadk/tools/gateway.py +92 -15
  331. ksadk/tools/result_budget.py +12 -4
  332. ksadk/toolsets/__init__.py +136 -36
  333. ksadk/toolsets/platform.py +21 -5
  334. ksadk/toolsets/sandbox.py +82 -16
  335. ksadk/toolsets/skills.py +200 -39
  336. ksadk/toolsets/web.py +123 -26
  337. ksadk/toolsets/workspace.py +264 -114
  338. ksadk/tracing/exporters/inmemory_exporter.py +62 -51
  339. ksadk/tracing/exporters/langfuse_exporter.py +91 -76
  340. ksadk/tracing/setup.py +132 -53
  341. ksadk/tracing/span_utils.py +5 -2
  342. ksadk/tui/__init__.py +22 -7
  343. ksadk/tui/loop.py +1925 -0
  344. ksadk/tui/stream_render.py +69 -0
  345. ksadk/ui_config.py +5 -3
  346. ksadk/version.py +1 -1
  347. ksadk_runtime_common/schemas/runtime_event_v1.json +95 -0
  348. agentengine_sdk_python-0.6.9.dist-info/RECORD +0 -487
  349. ksadk/server/static/assets/CodeBlock-BbI4HPtJ.js +0 -9
  350. ksadk/server/static/assets/MathMessageMarkdown-DMLQYoLp.js +0 -8
  351. ksadk/server/static/assets/MermaidBlock-DCR8WZ17.js +0 -303
  352. ksadk/server/static/assets/NativeTerminalPanel-CKUvWhUz.js +0 -1
  353. ksadk/server/static/assets/architecture-7EHR7CIX-Cr6Xz1_c.js +0 -1
  354. ksadk/server/static/assets/channel-BSSOwFIb.js +0 -1
  355. ksadk/server/static/assets/chunk-QZHKN3VN-XXpdiwUL.js +0 -1
  356. ksadk/server/static/assets/classDiagram-4FO5ZUOK-C5HvGiyK.js +0 -1
  357. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-C5HvGiyK.js +0 -1
  358. ksadk/server/static/assets/eventmodeling-FCH6USID-CIgwHJLL.js +0 -1
  359. ksadk/server/static/assets/gitGraph-WXDBUCRP-BVAJ7uo0.js +0 -1
  360. ksadk/server/static/assets/index-BH7-pC0B.js +0 -165
  361. ksadk/server/static/assets/index-DAURbCsP.css +0 -1
  362. ksadk/server/static/assets/info-J43DQDTF-MT80V4ge.js +0 -1
  363. ksadk/server/static/assets/packet-YPE3B663-BLKhbXZB.js +0 -1
  364. ksadk/server/static/assets/pie-LRSECV5Y-DFOikjSY.js +0 -1
  365. ksadk/server/static/assets/radar-GUYGQ44K-095b1Ikw.js +0 -1
  366. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-J9kCb0nC.js +0 -1
  367. ksadk/server/static/assets/treeView-BLDUP644-yinfJEY6.js +0 -1
  368. ksadk/server/static/assets/treemap-LRROVOQU-DosUqN1Q.js +0 -1
  369. ksadk/server/static/assets/wardley-L42UT6IY-Bvp7-5uH.js +0 -1
  370. ksadk/tui/app.py +0 -400
  371. ksadk/tui/clipboard.py +0 -100
  372. ksadk/tui/widgets/__init__.py +0 -22
  373. ksadk/tui/widgets/assistant.py +0 -89
  374. ksadk/tui/widgets/base.py +0 -54
  375. ksadk/tui/widgets/chat_input.py +0 -246
  376. ksadk/tui/widgets/history.py +0 -156
  377. ksadk/tui/widgets/system.py +0 -87
  378. ksadk/tui/widgets/thinking.py +0 -110
  379. ksadk/tui/widgets/tool_call.py +0 -161
  380. ksadk/tui/widgets/user.py +0 -37
  381. {agentengine_sdk_python-0.6.9.dist-info → agentengine_sdk_python-0.8.0.dist-info}/WHEEL +0 -0
  382. {agentengine_sdk_python-0.6.9.dist-info → agentengine_sdk_python-0.8.0.dist-info}/entry_points.txt +0 -0
  383. {agentengine_sdk_python-0.6.9.dist-info → agentengine_sdk_python-0.8.0.dist-info}/licenses/LICENSE +0 -0
  384. {agentengine_sdk_python-0.6.9.dist-info → agentengine_sdk_python-0.8.0.dist-info}/top_level.txt +0 -0
@@ -3,13 +3,12 @@ Container Builder - Docker 镜像构建
3
3
  """
4
4
 
5
5
  import os
6
- import subprocess
6
+ import platform
7
7
  import shutil
8
+ import subprocess
8
9
  import time
9
- import platform
10
- import asyncio
11
10
  from pathlib import Path
12
- from typing import Optional
11
+ from typing import TYPE_CHECKING, Optional
13
12
 
14
13
  import click
15
14
 
@@ -25,12 +24,15 @@ from ksadk.builders.requirements_utils import (
25
24
  parse_requirements_text,
26
25
  )
27
26
 
27
+ if TYPE_CHECKING:
28
+ from ksadk.deployment.base import PackageInfo
29
+
28
30
 
29
31
  def _registry_host(registry: str | None) -> str:
30
32
  value = str(registry or "").strip()
31
33
  for prefix in ("http://", "https://"):
32
34
  if value.startswith(prefix):
33
- value = value[len(prefix):]
35
+ value = value[len(prefix) :]
34
36
  break
35
37
  return value.split("/", 1)[0].strip()
36
38
 
@@ -100,8 +102,8 @@ def print_registry_credentials_help(registry: str | None, *, kind: str | None =
100
102
 
101
103
  def ensure_docker_running() -> bool:
102
104
  """确保 Docker 正在运行"""
103
- if not shutil.which('docker'):
104
- click.secho("❌ 未找到 docker 命令", fg='red')
105
+ if not shutil.which("docker"):
106
+ click.secho("❌ 未找到 docker 命令", fg="red")
105
107
  click.echo("")
106
108
  click.echo("请先安装 Docker:")
107
109
  if platform.system() == "Darwin":
@@ -113,36 +115,36 @@ def ensure_docker_running() -> bool:
113
115
  else:
114
116
  click.echo(" • 下载 Docker Desktop: https://www.docker.com/products/docker-desktop/")
115
117
  return False
116
-
118
+
117
119
  try:
118
- result = subprocess.run(['docker', 'info'], capture_output=True, timeout=10)
120
+ result = subprocess.run(["docker", "info"], capture_output=True, timeout=10)
119
121
  if result.returncode == 0:
120
122
  return True
121
- except:
123
+ except (OSError, subprocess.SubprocessError):
122
124
  pass
123
-
124
- click.secho("⚠️ Docker daemon 未运行", fg='yellow')
125
-
125
+
126
+ click.secho("⚠️ Docker daemon 未运行", fg="yellow")
127
+
126
128
  system_name = platform.system()
127
129
  if system_name == "Darwin":
128
130
  click.echo("🚀 正在启动 Docker Desktop...")
129
131
  try:
130
- subprocess.run(['open', '-a', 'Docker'], check=True)
132
+ subprocess.run(["open", "-a", "Docker"], check=True)
131
133
  for i in range(60):
132
134
  time.sleep(1)
133
135
  try:
134
- result = subprocess.run(['docker', 'info'], capture_output=True, timeout=5)
136
+ result = subprocess.run(["docker", "info"], capture_output=True, timeout=5)
135
137
  if result.returncode == 0:
136
- click.secho("✅ Docker Desktop 已启动", fg='green')
138
+ click.secho("✅ Docker Desktop 已启动", fg="green")
137
139
  return True
138
- except:
140
+ except (OSError, subprocess.SubprocessError):
139
141
  pass
140
142
  if i % 5 == 0 and i > 0:
141
143
  click.echo(f" 等待 Docker 启动中... ({i}秒)")
142
- click.secho("❌ Docker Desktop 启动超时", fg='red')
144
+ click.secho("❌ Docker Desktop 启动超时", fg="red")
143
145
  return False
144
- except:
145
- click.secho("❌ 无法启动 Docker Desktop", fg='red')
146
+ except (OSError, subprocess.SubprocessError):
147
+ click.secho("❌ 无法启动 Docker Desktop", fg="red")
146
148
  return False
147
149
  elif system_name == "Windows":
148
150
  click.echo("请启动 Docker Desktop,然后重试当前命令。")
@@ -154,81 +156,95 @@ def ensure_docker_running() -> bool:
154
156
 
155
157
  class ContainerBuilder(BaseBuilder):
156
158
  """Docker 镜像构建器"""
157
-
158
- def __init__(self, project_dir: Path, config: dict = None,
159
- tag: str = None, registry: str = None, no_cache: bool = False):
159
+
160
+ def __init__(
161
+ self,
162
+ project_dir: Path,
163
+ config: Optional[dict] = None,
164
+ tag: Optional[str] = None,
165
+ registry: Optional[str] = None,
166
+ no_cache: bool = False,
167
+ ):
160
168
  super().__init__(project_dir, config)
161
169
  self.tag = tag
162
170
  self.registry = registry
163
171
  self.no_cache = no_cache
164
-
172
+
165
173
  def _get_smart_kcr_endpoint(self, region: str) -> str:
166
174
  """智能选择 KCR endpoint
167
-
175
+
168
176
  使用企业版 KCR (hub.kce.ksyun.com/agentengine/)。
169
177
  优先使用内网 VPC endpoint,如果内网不可达则使用公网。
170
178
  """
171
179
  from ksadk.configs.settings import check_endpoint_reachable
172
-
180
+
173
181
  # 企业版 KCR 地址 (带 agentengine 命名空间)
174
182
  vpc_endpoint = "hub-vpc.kce.ksyun.com/agentengine"
175
183
  public_endpoint = "hub.kce.ksyun.com/agentengine"
176
-
177
- click.echo(f"🔍 检测 KCR 内网连通性...")
178
-
184
+
185
+ click.echo("🔍 检测 KCR 内网连通性...")
186
+
179
187
  # 检测 VPC 内网是否可达 (端口 443 for HTTPS registry)
180
188
  if check_endpoint_reachable("hub-vpc.kce.ksyun.com", port=443, timeout=2.0):
181
- click.secho(f" ✅ 使用内网: {vpc_endpoint}", fg='green')
189
+ click.secho(f" ✅ 使用内网: {vpc_endpoint}", fg="green")
182
190
  return vpc_endpoint
183
191
  else:
184
192
  click.echo(f" ℹ️ 使用公网: {public_endpoint}")
185
193
  return public_endpoint
186
-
194
+
187
195
  def _optimize_kcr_endpoint(self, registry: str) -> str:
188
196
  """优化 KCR endpoint
189
-
197
+
190
198
  如果是金山云 KCR 公网地址,且内网可达,则替换为内网地址。
191
199
  """
192
200
  from ksadk.configs.settings import check_endpoint_reachable
193
-
201
+
202
+ registry_text = str(registry).strip()
203
+ scheme, separator, reference = registry_text.partition("://")
204
+ prefix = f"{scheme}://" if separator else ""
205
+ target = reference if separator else registry_text
206
+ host, slash, remainder = target.partition("/")
207
+ normalized_host = host.lower()
208
+
194
209
  # 已经是内网地址
195
- if 'hub-vpc' in registry:
210
+ if normalized_host == "hub-vpc.kce.ksyun.com":
196
211
  return registry
197
-
198
- # 匹配企业版 KCR: hub.kce.ksyun.com
199
- if 'hub.kce.ksyun.com' in registry:
200
- click.echo(f"🔍 检测 KCR 内网连通性...")
212
+
213
+ # 仅匹配完整 registry host,避免改写路径或攻击者域名中的同名子串。
214
+ if normalized_host == "hub.kce.ksyun.com":
215
+ click.echo("🔍 检测 KCR 内网连通性...")
201
216
  if check_endpoint_reachable("hub-vpc.kce.ksyun.com", port=443, timeout=2.0):
202
- optimized = registry.replace("hub.kce.ksyun.com", "hub-vpc.kce.ksyun.com")
203
- click.secho(f" ✅ 优化为内网: {optimized}", fg='green')
217
+ optimized = f"{prefix}hub-vpc.kce.ksyun.com{slash}{remainder}"
218
+ click.secho(f" ✅ 优化为内网: {optimized}", fg="green")
204
219
  return optimized
205
220
  else:
206
221
  click.echo(f" ℹ️ 使用公网: {registry}")
207
-
222
+
208
223
  return registry
209
-
210
- def _package(self, detection_result) -> 'PackageInfo':
224
+
225
+ def _package(self, detection_result) -> "PackageInfo":
211
226
  """打包项目 - 复制文件并生成 Dockerfile/requirements/entrypoint"""
212
227
  from ksadk.deployment.base import PackageInfo
213
-
228
+
214
229
  project_path = self.project_dir
215
230
  output_dir = project_path / ".agentengine" / "build"
216
231
  output_dir.mkdir(parents=True, exist_ok=True)
217
-
232
+
218
233
  package_name = Path(detection_result.package_path).name
219
234
  is_container_first_template = (
220
235
  getattr(getattr(detection_result, "type", None), "value", "") == "hermes"
221
236
  and (project_path / "Dockerfile").exists()
222
237
  and (project_path / "entrypoint.sh").exists()
223
238
  )
224
-
239
+
225
240
  # 复制项目文件。真实 .env 只通过 deploy payload 注入,不进入镜像上下文。
226
241
  for item in project_path.iterdir():
227
242
  if CodeBuilder._is_real_dotenv_file(item.name):
228
243
  continue
229
- if (
230
- (item.name.startswith('.') and item.name != '.env.example')
231
- or item.name in ('__pycache__', '.git', 'node_modules')
244
+ if (item.name.startswith(".") and item.name != ".env.example") or item.name in (
245
+ "__pycache__",
246
+ ".git",
247
+ "node_modules",
232
248
  ):
233
249
  continue
234
250
  dest = output_dir / item.name
@@ -249,9 +265,10 @@ class ContainerBuilder(BaseBuilder):
249
265
  )
250
266
  else:
251
267
  shutil.copy2(item, dest)
252
-
268
+
253
269
  # 复制 ksadk 源码 (确保容器内可用)
254
270
  import ksadk
271
+
255
272
  ksadk_src = Path(ksadk.__file__).parent
256
273
  ksadk_dest = output_dir / "ksadk"
257
274
  if ksadk_dest.exists():
@@ -274,14 +291,15 @@ class ContainerBuilder(BaseBuilder):
274
291
  return ignored
275
292
 
276
293
  shutil.copytree(
277
- ksadk_src,
278
- ksadk_dest,
294
+ ksadk_src,
295
+ ksadk_dest,
279
296
  ignore=_ignore_ksadk_source,
280
297
  )
281
298
 
282
299
  # 复制 ksadk_runtime_common (如果存在)
283
300
  try:
284
301
  import ksadk_runtime_common
302
+
285
303
  runtime_common_src = Path(ksadk_runtime_common.__file__).parent
286
304
  runtime_common_dest = output_dir / "ksadk_runtime_common"
287
305
  if runtime_common_dest.exists():
@@ -305,21 +323,22 @@ class ContainerBuilder(BaseBuilder):
305
323
  ignore=shutil.ignore_patterns("__pycache__", "*.pyc"),
306
324
  )
307
325
  else:
308
- click.echo(click.style(
309
- "⚠️ 警告: 未找到 ksadk_runtime_common,镜像可能无法正常运行",
310
- fg="yellow"
311
- ))
312
-
326
+ click.echo(
327
+ click.style(
328
+ "⚠️ 警告: 未找到 ksadk_runtime_common,镜像可能无法正常运行", fg="yellow"
329
+ )
330
+ )
331
+
313
332
  dockerfile_path = output_dir / "Dockerfile"
314
333
  if not is_container_first_template:
315
334
  dockerfile = self._generate_dockerfile(detection_result)
316
335
  dockerfile_path.write_text(dockerfile)
317
-
336
+
318
337
  # 生成 requirements.txt (合并用户依赖)
319
338
  requirements = self._generate_requirements(detection_result, project_path)
320
339
  requirements_path = output_dir / "requirements.txt"
321
340
  requirements_path.write_text(requirements)
322
-
341
+
323
342
  # 生成启动脚本
324
343
  if is_container_first_template:
325
344
  entrypoint_path = output_dir / "entrypoint.sh"
@@ -327,7 +346,7 @@ class ContainerBuilder(BaseBuilder):
327
346
  entrypoint = self._generate_entrypoint(detection_result, package_name)
328
347
  entrypoint_path = output_dir / "entrypoint.py"
329
348
  entrypoint_path.write_text(entrypoint)
330
-
349
+
331
350
  return PackageInfo(
332
351
  name=detection_result.name or project_path.name,
333
352
  framework=detection_result.type.value,
@@ -339,14 +358,14 @@ class ContainerBuilder(BaseBuilder):
339
358
  "package_name": package_name,
340
359
  "requirements": str(requirements_path),
341
360
  "entrypoint": str(entrypoint_path),
342
- }
361
+ },
343
362
  )
344
-
363
+
345
364
  def _generate_dockerfile(self, detection_result) -> str:
346
365
  """生成优化的 Dockerfile"""
347
366
  base_image = "python:3.12-slim"
348
-
349
- return f'''FROM {base_image}
367
+
368
+ return f"""FROM {base_image}
350
369
 
351
370
  # 设置环境变量
352
371
  ENV PYTHONUNBUFFERED=1 \\
@@ -373,9 +392,9 @@ EXPOSE 8080
373
392
 
374
393
  # 使用 exec 形式确保信号正确传递
375
394
  CMD ["python", "entrypoint.py"]
376
- '''
377
-
378
- def _generate_requirements(self, detection_result, project_path: Path = None) -> str:
395
+ """
396
+
397
+ def _generate_requirements(self, detection_result, project_path: Optional[Path] = None) -> str:
379
398
  """生成 requirements.txt"""
380
399
  base_deps = [
381
400
  # Core
@@ -392,7 +411,7 @@ CMD ["python", "entrypoint.py"]
392
411
  "openinference-instrumentation-langchain>=0.1.0",
393
412
  "langfuse>=2.0.0",
394
413
  ]
395
-
414
+
396
415
  framework = detection_result.type.value
397
416
  base_deps += requirements_for_framework(framework)
398
417
 
@@ -400,20 +419,26 @@ CMD ["python", "entrypoint.py"]
400
419
  base_deps,
401
420
  CodeBuilder(project_path or self.project_dir)._bundled_runtime_requirements(),
402
421
  )
403
-
422
+
404
423
  # 合并用户 requirements.txt (如果存在)
405
424
  if project_path:
406
425
  user_requirements = project_path / "requirements.txt"
407
426
  if user_requirements.exists():
408
427
  user_content = user_requirements.read_text()
428
+ parsed_user_requirements = parse_requirements_text(user_content)
429
+ bundled_builder = CodeBuilder(project_path or self.project_dir)
430
+ base_deps = merge_requirement_lists(
431
+ base_deps,
432
+ bundled_builder._bundled_ksadk_extra_requirements(parsed_user_requirements),
433
+ )
409
434
  user_deps = exclude_requirement_names(
410
- parse_requirements_text(user_content),
435
+ parsed_user_requirements,
411
436
  excluded_names={"ksadk"},
412
437
  )
413
438
  base_deps = merge_requirement_lists(base_deps, user_deps)
414
-
439
+
415
440
  return "\n".join(base_deps)
416
-
441
+
417
442
  def _generate_entrypoint(self, detection_result, package_name: str) -> str:
418
443
  """生成 entrypoint.py"""
419
444
  return f'''"""
@@ -504,14 +529,17 @@ detection_result = DetectionResult(
504
529
  entry_point="{detection_result.entry_point}",
505
530
  package_path="/app/{package_name}",
506
531
  agent_variable="{detection_result.agent_variable}",
507
- runner_class="{getattr(detection_result, 'runner_class', '')}"
532
+ runner_class="{getattr(detection_result, "runner_class", "")}"
508
533
  )
509
534
 
510
535
  logger.info(f"框架: {{detection_result.name}}")
511
536
  logger.info(f"入口: {{detection_result.entry_point}}")
512
537
 
513
538
  # 初始化 Tracing (如果配置了 Langfuse、标准 OTLP HTTP 或 CloudMonitor OTLP)
514
- has_otlp = bool(os.environ.get("OTEL_EXPORTER_OTLP_ENDPOINT") or os.environ.get("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT"))
539
+ has_otlp = bool(
540
+ os.environ.get("OTEL_EXPORTER_OTLP_ENDPOINT")
541
+ or os.environ.get("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT")
542
+ )
515
543
  has_cloud_monitor_otlp = bool(
516
544
  os.environ.get("CLOUD_MONITOR_APP_KEY")
517
545
  or os.environ.get("CLOUD_MONITOR_OTLP_ENDPOINT")
@@ -522,10 +550,18 @@ has_cloud_monitor_langfuse = bool(
522
550
  or os.environ.get("CLOUD_MONITOR_LANGFUSE_SECRET_KEY")
523
551
  or os.environ.get("CLOUD_MONITOR_LANGFUSE_HOST")
524
552
  )
525
- if os.environ.get("LANGFUSE_PUBLIC_KEY") or has_otlp or has_cloud_monitor_otlp or has_cloud_monitor_langfuse:
553
+ if (
554
+ os.environ.get("LANGFUSE_PUBLIC_KEY")
555
+ or has_otlp
556
+ or has_cloud_monitor_otlp
557
+ or has_cloud_monitor_langfuse
558
+ ):
526
559
  try:
527
560
  from ksadk.tracing import setup_tracing
528
- use_callback_only = os.environ.get("LANGFUSE_USE_CALLBACK", "").strip().lower() in ("1", "true", "yes", "on")
561
+ use_callback_only = (
562
+ os.environ.get("LANGFUSE_USE_CALLBACK", "").strip().lower()
563
+ in ("1", "true", "yes", "on")
564
+ )
529
565
  setup_tracing(use_callback_only=use_callback_only)
530
566
  logger.info(
531
567
  f"Tracing 已启用 (OTLP={{has_otlp}}, "
@@ -540,7 +576,7 @@ if os.environ.get("LANGFUSE_PUBLIC_KEY") or has_otlp or has_cloud_monitor_otlp o
540
576
  logger.info("正在加载 Agent...")
541
577
  runner = create_runner(detection_result, "/app")
542
578
  runner.load_agent()
543
- set_runner(runner)
579
+ set_runner(runner, loaded=True)
544
580
  logger.info("Agent 加载成功!")
545
581
 
546
582
  if __name__ == "__main__":
@@ -548,77 +584,69 @@ if __name__ == "__main__":
548
584
  logger.info(f"启动 HTTP Server: 0.0.0.0:{{port}}")
549
585
  uvicorn.run(app, host="0.0.0.0", port=port, log_level=LOG_LEVEL.lower())
550
586
  '''
551
-
587
+
552
588
  def build(self) -> BuildResult:
553
589
  """构建 Docker 镜像"""
554
590
  from ksadk.detection import FrameworkDetector
555
-
591
+
556
592
  self._load_dotenv()
557
593
  config = self._load_config()
558
-
594
+
559
595
  # 检测框架
560
596
  detector = FrameworkDetector(str(self.project_dir))
561
597
  result = detector.detect()
562
-
598
+
563
599
  if result.type.value == "unknown":
564
- return BuildResult(
565
- success=False,
566
- error_message="未检测到支持的框架"
567
- )
568
-
600
+ return BuildResult(success=False, error_message="未检测到支持的框架")
601
+
569
602
  click.echo(f"📦 框架: {click.style(result.name, fg='green')}")
570
-
603
+
571
604
  # 确定镜像名称
572
- image_name = config.get('name', self.project_dir.name).replace('-', '_').replace('.', '_')
573
-
605
+ image_name = config.get("name", self.project_dir.name).replace("-", "_").replace(".", "_")
606
+
574
607
  # Tag 优先级: 命令行 > agentengine.yaml version > config image.tag > latest
575
608
  image_tag = self.tag
576
609
  if not image_tag:
577
- image_tag = config.get('version', '') # 使用项目版本作为 tag
610
+ image_tag = config.get("version", "") # 使用项目版本作为 tag
578
611
  if not image_tag:
579
- image_tag = config.get('image', {}).get('tag', 'latest')
580
-
612
+ image_tag = config.get("image", {}).get("tag", "latest")
613
+
581
614
  # Registry 优先级: 命令行 > .env KCR_REGISTRY > agentengine.yaml > 默认企业版 KCR
582
615
  import os
616
+
583
617
  image_registry = self.registry
584
618
  if not image_registry:
585
- image_registry = os.getenv('KCR_REGISTRY', '')
619
+ image_registry = os.getenv("KCR_REGISTRY", "")
586
620
  if not image_registry:
587
- image_registry = config.get('image', {}).get('registry', '')
621
+ image_registry = config.get("image", {}).get("registry", "")
588
622
  if not image_registry:
589
623
  # 默认使用企业版 KCR,智能选择内网/公网
590
- image_registry = self._get_smart_kcr_endpoint(os.getenv('KSYUN_REGION', 'cn-beijing-6'))
624
+ image_registry = self._get_smart_kcr_endpoint(os.getenv("KSYUN_REGION", "cn-beijing-6"))
591
625
  else:
592
626
  # 即使设置了 registry,如果是金山云公网地址,也尝试优化为内网
593
627
  image_registry = self._optimize_kcr_endpoint(image_registry)
594
-
628
+
595
629
  full_image = f"{image_registry}/{image_name}:{image_tag}"
596
-
630
+
597
631
  click.echo(f"🏷️ 镜像名称: {full_image}")
598
-
632
+
599
633
  # 打包 (内置打包逻辑,不再依赖 DockerProvider)
600
634
  click.echo("\n📦 打包中...")
601
635
  try:
602
636
  package_info = self._package(result)
603
637
  click.echo("✅ 打包完成")
604
638
  except Exception as e:
605
- return BuildResult(
606
- success=False,
607
- error_message=f"打包失败: {e}"
608
- )
609
-
639
+ return BuildResult(success=False, error_message=f"打包失败: {e}")
640
+
610
641
  # Docker 构建
611
642
  if not ensure_docker_running():
612
- return BuildResult(
613
- success=False,
614
- error_message="Docker 未运行"
615
- )
616
-
643
+ return BuildResult(success=False, error_message="Docker 未运行")
644
+
617
645
  click.echo("\n🔨 构建 Docker 镜像 (目标平台: linux/amd64)...")
618
646
  try:
619
- cmd = ['docker', 'build', '--platform', 'linux/amd64', '-t', full_image]
647
+ cmd = ["docker", "build", "--platform", "linux/amd64", "-t", full_image]
620
648
  if self.no_cache:
621
- cmd.append('--no-cache')
649
+ cmd.append("--no-cache")
622
650
  cmd.append(package_info.build_dir)
623
651
 
624
652
  quiet_mode = os.getenv("AGENTENGINE_OUTPUT_MODE", "").strip().lower() == "json"
@@ -628,16 +656,16 @@ if __name__ == "__main__":
628
656
  capture_output=quiet_mode,
629
657
  text=quiet_mode,
630
658
  )
631
- click.secho(f"\n✅ 镜像构建成功: {full_image}", fg='green')
632
-
659
+ click.secho(f"\n✅ 镜像构建成功: {full_image}", fg="green")
660
+
633
661
  return BuildResult(
634
662
  success=True,
635
663
  artifact_path=None, # Docker 镜像没有本地文件路径
636
664
  metadata={
637
665
  "image": full_image,
638
666
  "framework": result.type.value,
639
- "build_dir": package_info.build_dir
640
- }
667
+ "build_dir": package_info.build_dir,
668
+ },
641
669
  )
642
670
  except subprocess.CalledProcessError as e:
643
671
  error_message = f"镜像构建失败: {e}"
@@ -647,138 +675,130 @@ if __name__ == "__main__":
647
675
  detail = stderr or stdout
648
676
  if detail:
649
677
  error_message = f"{error_message}: {detail}"
650
- return BuildResult(
651
- success=False,
652
- error_message=error_message
653
- )
654
-
678
+ return BuildResult(success=False, error_message=error_message)
679
+
655
680
  def push(self, image_name: str) -> bool:
656
681
  """推送镜像到仓库"""
657
682
  # 检查镜像仓库认证
658
683
  registry = self._extract_registry(image_name)
659
-
684
+
660
685
  # 尝试使用 .env 中的认证信息自动登录
661
686
  if registry:
662
687
  if not self._auto_login_from_env(registry):
663
688
  # 自动登录失败,检查是否已有认证
664
689
  if not self._check_registry_auth(registry):
665
690
  return False
666
-
667
- click.echo(f"\n📤 推送镜像...")
691
+
692
+ click.echo("\n📤 推送镜像...")
668
693
  try:
669
- result = subprocess.run(
670
- ['docker', 'push', image_name],
671
- capture_output=True,
672
- text=True
673
- )
694
+ result = subprocess.run(["docker", "push", image_name], capture_output=True, text=True)
674
695
  if result.returncode != 0:
675
696
  # 检查是否是认证问题
676
- if 'denied' in result.stderr.lower() or 'unauthorized' in result.stderr.lower():
677
- self._print_auth_help(registry or 'docker.io')
697
+ if "denied" in result.stderr.lower() or "unauthorized" in result.stderr.lower():
698
+ self._print_auth_help(registry or "docker.io")
678
699
  return False
679
- click.secho(f"❌ 镜像推送失败: {result.stderr}", fg='red')
700
+ click.secho(f"❌ 镜像推送失败: {result.stderr}", fg="red")
680
701
  return False
681
-
682
- click.secho(f"✅ 镜像推送成功", fg='green')
702
+
703
+ click.secho("✅ 镜像推送成功", fg="green")
683
704
  return True
684
705
  except subprocess.CalledProcessError as e:
685
- click.secho(f"❌ 镜像推送失败: {e}", fg='red')
706
+ click.secho(f"❌ 镜像推送失败: {e}", fg="red")
686
707
  return False
687
-
708
+
688
709
  def _auto_login_from_env(self, registry: str) -> bool:
689
710
  """尝试使用 .env 中的凭证自动登录"""
690
711
  import os
712
+
691
713
  from dotenv import load_dotenv
692
-
714
+
693
715
  # 加载 .env
694
716
  load_dotenv()
695
-
696
- # KCR_REGISTRY is a generic registry/namespace target used for KCR and third-party registries.
697
- kcr_registry = os.getenv('KCR_REGISTRY', '')
717
+
718
+ # KCR_REGISTRY is the registry/namespace target for KCR and third parties.
719
+ kcr_registry = os.getenv("KCR_REGISTRY", "")
698
720
  if not kcr_registry:
699
721
  kcr_registry = "hub.kce.ksyun.com/agentengine"
700
-
722
+
701
723
  kcr_username, kcr_password, registry_kind = resolve_registry_credentials(registry)
702
-
724
+
703
725
  # 检查是否匹配当前 registry (支持部分匹配)
704
726
  if registry not in kcr_registry and kcr_registry not in registry:
705
727
  return False
706
-
728
+
707
729
  if not kcr_username or not kcr_password:
708
730
  print_registry_credentials_help(registry, kind=registry_kind)
709
731
  return False
710
-
732
+
711
733
  click.echo(f"🔐 使用 .env 中的凭证登录 {registry}...")
712
734
  try:
713
735
  result = subprocess.run(
714
- ['docker', 'login', registry, '-u', kcr_username, '--password-stdin'],
736
+ ["docker", "login", registry, "-u", kcr_username, "--password-stdin"],
715
737
  input=kcr_password,
716
738
  capture_output=True,
717
739
  text=True,
718
- timeout=30
740
+ timeout=30,
719
741
  )
720
742
  if result.returncode == 0:
721
- click.secho(f"✅ 登录成功", fg='green')
743
+ click.secho("✅ 登录成功", fg="green")
722
744
  return True
723
745
  else:
724
- click.secho(f"⚠️ 自动登录失败: {result.stderr.strip()}", fg='yellow')
746
+ click.secho(f"⚠️ 自动登录失败: {result.stderr.strip()}", fg="yellow")
725
747
  return False
726
748
  except Exception as e:
727
- click.secho(f"⚠️ 自动登录异常: {e}", fg='yellow')
749
+ click.secho(f"⚠️ 自动登录异常: {e}", fg="yellow")
728
750
  return False
729
-
751
+
730
752
  def get_registry_credentials(self, registry: str | None = None) -> dict:
731
753
  """获取镜像仓库凭证 (用于传给 Serverless)
732
-
754
+
733
755
  返回扁平化结构: {"username": "...", "password": "..."}
734
756
  """
735
757
  import os
758
+
736
759
  from dotenv import load_dotenv
737
-
760
+
738
761
  load_dotenv()
739
-
762
+
740
763
  registry = registry or os.getenv("KCR_REGISTRY", "")
741
764
  username, password, _ = resolve_registry_credentials(registry)
742
-
765
+
743
766
  if username and password:
744
- return {
745
- 'username': username,
746
- 'password': password
747
- }
767
+ return {"username": username, "password": password}
748
768
  return {}
749
-
769
+
750
770
  def _extract_registry(self, image_name: str) -> Optional[str]:
751
771
  """从镜像名称提取仓库地址"""
752
772
  # 格式: registry/namespace/image:tag 或 namespace/image:tag (默认 docker.io)
753
- parts = image_name.split('/')
754
- if len(parts) >= 2 and ('.' in parts[0] or ':' in parts[0]):
773
+ parts = image_name.split("/")
774
+ if len(parts) >= 2 and ("." in parts[0] or ":" in parts[0]):
755
775
  return parts[0]
756
776
  return None # 使用默认 docker.io
757
-
777
+
758
778
  def _check_registry_auth(self, registry: str) -> bool:
759
779
  """检查是否已登录镜像仓库"""
760
780
  try:
761
781
  # 尝试获取 docker 配置
762
782
  import json
763
783
  from pathlib import Path
764
-
765
- docker_config = Path.home() / '.docker' / 'config.json'
784
+
785
+ docker_config = Path.home() / ".docker" / "config.json"
766
786
  if docker_config.exists():
767
787
  with open(docker_config) as f:
768
788
  config = json.load(f)
769
- auths = config.get('auths', {})
789
+ auths = config.get("auths", {})
770
790
  # 检查是否有该仓库的认证信息
771
- if registry in auths or f'https://{registry}' in auths:
791
+ if registry in auths or f"https://{registry}" in auths:
772
792
  return True
773
-
793
+
774
794
  # 没有找到认证信息,提示用户
775
- click.secho(f"\n⚠️ 未检测到 {registry} 的登录凭证", fg='yellow')
795
+ click.secho(f"\n⚠️ 未检测到 {registry} 的登录凭证", fg="yellow")
776
796
  self._print_auth_help(registry)
777
797
  return False
778
798
  except Exception:
779
799
  # 无法检查,继续尝试推送
780
800
  return True
781
-
801
+
782
802
  def _print_auth_help(self, registry: str):
783
803
  """打印认证帮助信息"""
784
804
  print_registry_credentials_help(registry)